Skip to content

Commit 877c7cb

Browse files
committed
Auto merge of rust-lang#79903 - Mark-Simulacrum:beta-next, r=Mark-Simulacrum
[beta] backports * Revert rust-lang#77534 fixing rust-lang#77713 on beta, principled fix landed on master * fix soundness issue in `make_contiguous` rust-lang#79814 * Fix exhaustiveness in case a byte string literal is used at slice type rust-lang#79072
2 parents 19ccb6c + 527934d commit 877c7cb

File tree

14 files changed

+151
-163
lines changed

14 files changed

+151
-163
lines changed

compiler/rustc_lint/src/levels.rs

+4-43
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use rustc_hir as hir;
1010
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
1111
use rustc_hir::{intravisit, HirId};
1212
use rustc_middle::hir::map::Map;
13-
use rustc_middle::lint::LevelSource;
1413
use rustc_middle::lint::LintDiagnosticBuilder;
1514
use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
1615
use rustc_middle::ty::query::Providers;
@@ -97,44 +96,6 @@ impl<'s> LintLevelsBuilder<'s> {
9796
self.sets.list.push(LintSet::CommandLine { specs });
9897
}
9998

100-
/// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
101-
/// (e.g. if a forbid was already inserted on the same scope), then emits a
102-
/// diagnostic with no change to `specs`.
103-
fn insert_spec(
104-
&mut self,
105-
specs: &mut FxHashMap<LintId, LevelSource>,
106-
id: LintId,
107-
(level, src): LevelSource,
108-
) {
109-
if let Some((old_level, old_src)) = specs.get(&id) {
110-
if old_level == &Level::Forbid && level != Level::Forbid {
111-
let mut diag_builder = struct_span_err!(
112-
self.sess,
113-
src.span(),
114-
E0453,
115-
"{}({}) incompatible with previous forbid in same scope",
116-
level.as_str(),
117-
src.name(),
118-
);
119-
match *old_src {
120-
LintSource::Default => {}
121-
LintSource::Node(_, forbid_source_span, reason) => {
122-
diag_builder.span_label(forbid_source_span, "`forbid` level set here");
123-
if let Some(rationale) = reason {
124-
diag_builder.note(&rationale.as_str());
125-
}
126-
}
127-
LintSource::CommandLine(_, _) => {
128-
diag_builder.note("`forbid` lint level was set on command line");
129-
}
130-
}
131-
diag_builder.emit();
132-
return;
133-
}
134-
}
135-
specs.insert(id, (level, src));
136-
}
137-
13899
/// Pushes a list of AST lint attributes onto this context.
139100
///
140101
/// This function will return a `BuilderPush` object which should be passed
@@ -149,7 +110,7 @@ impl<'s> LintLevelsBuilder<'s> {
149110
/// `#[allow]`
150111
///
151112
/// Don't forget to call `pop`!
152-
pub(crate) fn push(
113+
pub fn push(
153114
&mut self,
154115
attrs: &[ast::Attribute],
155116
store: &LintStore,
@@ -261,7 +222,7 @@ impl<'s> LintLevelsBuilder<'s> {
261222
let src = LintSource::Node(name, li.span(), reason);
262223
for &id in ids {
263224
self.check_gated_lint(id, attr.span);
264-
self.insert_spec(&mut specs, id, (level, src));
225+
specs.insert(id, (level, src));
265226
}
266227
}
267228

@@ -275,7 +236,7 @@ impl<'s> LintLevelsBuilder<'s> {
275236
reason,
276237
);
277238
for id in ids {
278-
self.insert_spec(&mut specs, *id, (level, src));
239+
specs.insert(*id, (level, src));
279240
}
280241
}
281242
Err((Some(ids), new_lint_name)) => {
@@ -312,7 +273,7 @@ impl<'s> LintLevelsBuilder<'s> {
312273
reason,
313274
);
314275
for id in ids {
315-
self.insert_spec(&mut specs, *id, (level, src));
276+
specs.insert(*id, (level, src));
316277
}
317278
}
318279
Err((None, _)) => {

compiler/rustc_middle/src/lint.rs

+1-19
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_session::lint::{builtin, Level, Lint, LintId};
99
use rustc_session::{DiagnosticMessageId, Session};
1010
use rustc_span::hygiene::MacroKind;
1111
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
12-
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
12+
use rustc_span::{Span, Symbol};
1313

1414
/// How a lint level was set.
1515
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
@@ -27,24 +27,6 @@ pub enum LintSource {
2727
CommandLine(Symbol, Level),
2828
}
2929

30-
impl LintSource {
31-
pub fn name(&self) -> Symbol {
32-
match *self {
33-
LintSource::Default => symbol::kw::Default,
34-
LintSource::Node(name, _, _) => name,
35-
LintSource::CommandLine(name, _) => name,
36-
}
37-
}
38-
39-
pub fn span(&self) -> Span {
40-
match *self {
41-
LintSource::Default => DUMMY_SP,
42-
LintSource::Node(_, span, _) => span,
43-
LintSource::CommandLine(_, _) => DUMMY_SP,
44-
}
45-
}
46-
}
47-
4830
pub type LevelSource = (Level, LintSource);
4931

5032
pub struct LintLevelSets {

compiler/rustc_middle/src/ty/context.rs

+9
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,12 @@ pub struct TypeckResults<'tcx> {
418418
/// Stores the type, expression, span and optional scope span of all types
419419
/// that are live across the yield of this generator (if a generator).
420420
pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>,
421+
422+
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
423+
/// as `&[u8]`, depending on the pattern in which they are used.
424+
/// This hashset records all instances where we behave
425+
/// like this to allow `const_to_pat` to reliably handle this situation.
426+
pub treat_byte_string_as_slice: ItemLocalSet,
421427
}
422428

423429
impl<'tcx> TypeckResults<'tcx> {
@@ -443,6 +449,7 @@ impl<'tcx> TypeckResults<'tcx> {
443449
concrete_opaque_types: Default::default(),
444450
closure_captures: Default::default(),
445451
generator_interior_types: Default::default(),
452+
treat_byte_string_as_slice: Default::default(),
446453
}
447454
}
448455

@@ -677,6 +684,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
677684
ref concrete_opaque_types,
678685
ref closure_captures,
679686
ref generator_interior_types,
687+
ref treat_byte_string_as_slice,
680688
} = *self;
681689

682690
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
@@ -710,6 +718,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
710718
concrete_opaque_types.hash_stable(hcx, hasher);
711719
closure_captures.hash_stable(hcx, hasher);
712720
generator_interior_types.hash_stable(hcx, hasher);
721+
treat_byte_string_as_slice.hash_stable(hcx, hasher);
713722
})
714723
}
715724
}

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

+36-8
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
1818
/// Converts an evaluated constant to a pattern (if possible).
1919
/// This means aggregate values (like structs and enums) are converted
2020
/// to a pattern that matches the value (as if you'd compared via structural equality).
21+
#[instrument(skip(self))]
2122
pub(super) fn const_to_pat(
2223
&self,
2324
cv: &'tcx ty::Const<'tcx>,
2425
id: hir::HirId,
2526
span: Span,
2627
mir_structural_match_violation: bool,
2728
) -> Pat<'tcx> {
28-
debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
29-
debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
30-
3129
let pat = self.tcx.infer_ctxt().enter(|infcx| {
3230
let mut convert = ConstToPat::new(self, id, span, infcx);
3331
convert.to_pat(cv, mir_structural_match_violation)
3432
});
3533

36-
debug!("const_to_pat: pat={:?}", pat);
34+
debug!(?pat);
3735
pat
3836
}
3937
}
@@ -61,6 +59,8 @@ struct ConstToPat<'a, 'tcx> {
6159
infcx: InferCtxt<'a, 'tcx>,
6260

6361
include_lint_checks: bool,
62+
63+
treat_byte_string_as_slice: bool,
6464
}
6565

6666
mod fallback_to_const_ref {
@@ -88,6 +88,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
8888
span: Span,
8989
infcx: InferCtxt<'a, 'tcx>,
9090
) -> Self {
91+
trace!(?pat_ctxt.typeck_results.hir_owner);
9192
ConstToPat {
9293
id,
9394
span,
@@ -97,6 +98,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
9798
saw_const_match_error: Cell::new(false),
9899
saw_const_match_lint: Cell::new(false),
99100
behind_reference: Cell::new(false),
101+
treat_byte_string_as_slice: pat_ctxt
102+
.typeck_results
103+
.treat_byte_string_as_slice
104+
.contains(&id.local_id),
100105
}
101106
}
102107

@@ -153,6 +158,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
153158
cv: &'tcx ty::Const<'tcx>,
154159
mir_structural_match_violation: bool,
155160
) -> Pat<'tcx> {
161+
trace!(self.treat_byte_string_as_slice);
156162
// This method is just a wrapper handling a validity check; the heavy lifting is
157163
// performed by the recursive `recur` method, which is not meant to be
158164
// invoked except by this method.
@@ -384,7 +390,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
384390
}
385391
PatKind::Wild
386392
}
387-
// `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
393+
// `&str` is represented as `ConstValue::Slice`, let's keep using this
388394
// optimization for now.
389395
ty::Str => PatKind::Constant { value: cv },
390396
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
@@ -393,11 +399,33 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
393399
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
394400
// has no negative effects on pattern matching, even if we're actually matching on
395401
// arrays.
396-
ty::Array(..) |
402+
ty::Array(..) if !self.treat_byte_string_as_slice => {
403+
let old = self.behind_reference.replace(true);
404+
let array = tcx.deref_const(self.param_env.and(cv));
405+
let val = PatKind::Deref {
406+
subpattern: Pat {
407+
kind: Box::new(PatKind::Array {
408+
prefix: tcx
409+
.destructure_const(param_env.and(array))
410+
.fields
411+
.iter()
412+
.map(|val| self.recur(val, false))
413+
.collect::<Result<_, _>>()?,
414+
slice: None,
415+
suffix: vec![],
416+
}),
417+
span,
418+
ty: pointee_ty,
419+
},
420+
};
421+
self.behind_reference.set(old);
422+
val
423+
}
424+
ty::Array(elem_ty, _) |
397425
// Cannot merge this with the catch all branch below, because the `const_deref`
398426
// changes the type from slice to array, we need to keep the original type in the
399427
// pattern.
400-
ty::Slice(..) => {
428+
ty::Slice(elem_ty) => {
401429
let old = self.behind_reference.replace(true);
402430
let array = tcx.deref_const(self.param_env.and(cv));
403431
let val = PatKind::Deref {
@@ -413,7 +441,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
413441
suffix: vec![],
414442
}),
415443
span,
416-
ty: pointee_ty,
444+
ty: tcx.mk_slice(elem_ty),
417445
},
418446
};
419447
self.behind_reference.set(old);

compiler/rustc_typeck/src/check/pat.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
149149
///
150150
/// Outside of this module, `check_pat_top` should always be used.
151151
/// Conversely, inside this module, `check_pat_top` should never be used.
152+
#[instrument(skip(self, ti))]
152153
fn check_pat(
153154
&self,
154155
pat: &'tcx Pat<'tcx>,
155156
expected: Ty<'tcx>,
156157
def_bm: BindingMode,
157158
ti: TopInfo<'tcx>,
158159
) {
159-
debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm);
160-
161160
let path_res = match &pat.kind {
162161
PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)),
163162
_ => None,
@@ -398,6 +397,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
398397
if let ty::Ref(_, inner_ty, _) = expected.kind() {
399398
if matches!(inner_ty.kind(), ty::Slice(_)) {
400399
let tcx = self.tcx;
400+
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
401+
self.typeck_results
402+
.borrow_mut()
403+
.treat_byte_string_as_slice
404+
.insert(lt.hir_id.local_id);
401405
pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
402406
}
403407
}

compiler/rustc_typeck/src/check/writeback.rs

+3
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7070
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
7171
wbcx.typeck_results.used_trait_imports = used_trait_imports;
7272

73+
wbcx.typeck_results.treat_byte_string_as_slice =
74+
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
75+
7376
wbcx.typeck_results.closure_captures =
7477
mem::take(&mut self.typeck_results.borrow_mut().closure_captures);
7578

library/alloc/src/collections/vec_deque.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,8 @@ impl<T> VecDeque<T> {
15071507

15081508
#[inline]
15091509
fn is_contiguous(&self) -> bool {
1510+
// FIXME: Should we consider `head == 0` to mean
1511+
// that `self` is contiguous?
15101512
self.tail <= self.head
15111513
}
15121514

@@ -2236,7 +2238,7 @@ impl<T> VecDeque<T> {
22362238
if self.is_contiguous() {
22372239
let tail = self.tail;
22382240
let head = self.head;
2239-
return unsafe { &mut self.buffer_as_mut_slice()[tail..head] };
2241+
return unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 };
22402242
}
22412243

22422244
let buf = self.buf.ptr();
@@ -2262,7 +2264,13 @@ impl<T> VecDeque<T> {
22622264
self.tail = 0;
22632265
self.head = len;
22642266
}
2265-
} else if free >= self.head {
2267+
} else if free > self.head {
2268+
// FIXME: We currently do not consider ....ABCDEFGH
2269+
// to be contiguous because `head` would be `0` in this
2270+
// case. While we probably want to change this it
2271+
// isn't trivial as a few places expect `is_contiguous`
2272+
// to mean that we can just slice using `buf[tail..head]`.
2273+
22662274
// there is enough free space to copy the head in one go,
22672275
// this means that we first shift the tail forwards, and then
22682276
// copy the head to the correct position.
@@ -2276,7 +2284,7 @@ impl<T> VecDeque<T> {
22762284
// ...ABCDEFGH.
22772285

22782286
self.tail = self.head;
2279-
self.head = self.tail + len;
2287+
self.head = self.wrap_add(self.tail, len);
22802288
}
22812289
} else {
22822290
// free is smaller than both head and tail,
@@ -2316,7 +2324,7 @@ impl<T> VecDeque<T> {
23162324

23172325
let tail = self.tail;
23182326
let head = self.head;
2319-
unsafe { &mut self.buffer_as_mut_slice()[tail..head] }
2327+
unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 }
23202328
}
23212329

23222330
/// Rotates the double-ended queue `mid` places to the left.
@@ -3282,7 +3290,7 @@ impl<T> From<VecDeque<T>> for Vec<T> {
32823290
let len = other.len();
32833291
let cap = other.cap();
32843292

3285-
if other.head != 0 {
3293+
if other.tail != 0 {
32863294
ptr::copy(buf.add(other.tail), buf, len);
32873295
}
32883296
Vec::from_raw_parts(buf, len, cap)

library/alloc/src/collections/vec_deque/tests.rs

+14
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,20 @@ fn make_contiguous_small_free() {
210210
);
211211
}
212212

213+
#[test]
214+
fn make_contiguous_head_to_end() {
215+
let mut dq = VecDeque::with_capacity(3);
216+
dq.push_front('B');
217+
dq.push_front('A');
218+
dq.push_back('C');
219+
dq.make_contiguous();
220+
let expected_tail = 0;
221+
let expected_head = 3;
222+
assert_eq!(expected_tail, dq.tail);
223+
assert_eq!(expected_head, dq.head);
224+
assert_eq!((&['A', 'B', 'C'] as &[_], &[] as &[_]), dq.as_slices());
225+
}
226+
213227
#[test]
214228
fn test_remove() {
215229
// This test checks that every single combination of tail position, length, and

0 commit comments

Comments
 (0)