Skip to content

Commit d05dd84

Browse files
committed
Auto merge of rust-lang#119719 - Mark-Simulacrum:beta-next, r=Mark-Simulacrum
[beta] backport rollup This PR backports: - rust-lang#119544: Fix: Properly set vendor in i686-win7-windows-msvc target - rust-lang#118796: Exhaustiveness: Improve complexity on some wide matches - rust-lang#119546: Temporarily disable M1 runners on GitHub Actions - rust-lang#119584: [beta] Clippy (early) beta backport - rust-lang#119559: [beta-1.76] Update cargo And also: - Bumps stage0 to released stable. r? `@Mark-Simulacrum`
2 parents 0e09125 + 94fdd66 commit d05dd84

File tree

8 files changed

+617
-487
lines changed

8 files changed

+617
-487
lines changed

Diff for: .github/workflows/ci.yml

+4-16
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,8 @@ jobs:
361361
os: macos-13
362362
- name: dist-aarch64-apple
363363
env:
364-
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
365-
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
364+
SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
365+
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
366366
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
367367
SELECT_XCODE: /Applications/Xcode_13.4.1.app
368368
USE_XCODE_CLANG: 1
@@ -372,20 +372,8 @@ jobs:
372372
NO_DEBUG_ASSERTIONS: 1
373373
NO_OVERFLOW_CHECKS: 1
374374
DIST_REQUIRE_ALL_TOOLS: 1
375-
os: macos-13-xlarge
376-
- name: aarch64-apple
377-
env:
378-
SCRIPT: "./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
379-
RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
380-
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
381-
SELECT_XCODE: /Applications/Xcode_13.4.1.app
382-
USE_XCODE_CLANG: 1
383-
MACOSX_DEPLOYMENT_TARGET: 11.0
384-
MACOSX_STD_DEPLOYMENT_TARGET: 11.0
385-
NO_LLVM_ASSERTIONS: 1
386-
NO_DEBUG_ASSERTIONS: 1
387-
NO_OVERFLOW_CHECKS: 1
388-
os: macos-13-xlarge
375+
JEMALLOC_SYS_WITH_LG_PAGE: 14
376+
os: macos-13
389377
- name: x86_64-msvc
390378
env:
391379
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"

Diff for: compiler/rustc_pattern_analysis/src/usefulness.rs

+205-29
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,166 @@
300300
//!
301301
//!
302302
//!
303+
//! # `Missing` and relevancy
304+
//!
305+
//! ## Relevant values
306+
//!
307+
//! Take the following example:
308+
//!
309+
//! ```compile_fail,E0004
310+
//! # let foo = (true, true);
311+
//! match foo {
312+
//! (true, _) => 1,
313+
//! (_, true) => 2,
314+
//! };
315+
//! ```
316+
//!
317+
//! Consider the value `(true, true)`:
318+
//! - Row 2 does not distinguish `(true, true)` and `(false, true)`;
319+
//! - `false` does not show up in the first column of the match, so without knowing anything else we
320+
//! can deduce that `(false, true)` matches the same or fewer rows than `(true, true)`.
321+
//!
322+
//! Using those two facts together, we deduce that `(true, true)` will not give us more usefulness
323+
//! information about row 2 than `(false, true)` would. We say that "`(true, true)` is made
324+
//! irrelevant for row 2 by `(false, true)`". We will use this idea to prune the search tree.
325+
//!
326+
//!
327+
//! ## Computing relevancy
328+
//!
329+
//! We now generalize from the above example to approximate relevancy in a simple way. Note that we
330+
//! will only compute an approximation: we can sometimes determine when a case is irrelevant, but
331+
//! computing this precisely is at least as hard as computing usefulness.
332+
//!
333+
//! Our computation of relevancy relies on the `Missing` constructor. As explained in
334+
//! [`crate::constructor`], `Missing` represents the constructors not present in a given column. For
335+
//! example in the following:
336+
//!
337+
//! ```compile_fail,E0004
338+
//! enum Direction { North, South, East, West }
339+
//! # let wind = (Direction::North, 0u8);
340+
//! match wind {
341+
//! (Direction::North, _) => 1,
342+
//! (_, 50..) => 2,
343+
//! };
344+
//! ```
345+
//!
346+
//! Here `South`, `East` and `West` are missing in the first column, and `0..50` is missing in the
347+
//! second. Both of these sets are represented by `Constructor::Missing` in their corresponding
348+
//! column.
349+
//!
350+
//! We then compute relevancy as follows: during the course of the algorithm, for a row `r`:
351+
//! - if `r` has a wildcard in the first column;
352+
//! - and some constructors are missing in that column;
353+
//! - then any `c != Missing` is considered irrelevant for row `r`.
354+
//!
355+
//! By this we mean that continuing the algorithm by specializing with `c` is guaranteed not to
356+
//! contribute more information about the usefulness of row `r` than what we would get by
357+
//! specializing with `Missing`. The argument is the same as in the previous subsection.
358+
//!
359+
//! Once we've specialized by a constructor `c` that is irrelevant for row `r`, we're guaranteed to
360+
//! only explore values irrelevant for `r`. If we then ever reach a point where we're only exploring
361+
//! values that are irrelevant to all of the rows (including the virtual wildcard row used for
362+
//! exhaustiveness), we skip that case entirely.
363+
//!
364+
//!
365+
//! ## Example
366+
//!
367+
//! Let's go through a variation on the first example:
368+
//!
369+
//! ```compile_fail,E0004
370+
//! # let foo = (true, true, true);
371+
//! match foo {
372+
//! (true, _, true) => 1,
373+
//! (_, true, _) => 2,
374+
//! };
375+
//! ```
376+
//!
377+
//! ```text
378+
//! ┐ Patterns:
379+
//! │ 1. `[(true, _, true)]`
380+
//! │ 2. `[(_, true, _)]`
381+
//! │ 3. `[_]` // virtual extra wildcard row
382+
//! │
383+
//! │ Specialize with `(,,)`:
384+
//! ├─┐ Patterns:
385+
//! │ │ 1. `[true, _, true]`
386+
//! │ │ 2. `[_, true, _]`
387+
//! │ │ 3. `[_, _, _]`
388+
//! │ │
389+
//! │ │ There are missing constructors in the first column (namely `false`), hence
390+
//! │ │ `true` is irrelevant for rows 2 and 3.
391+
//! │ │
392+
//! │ │ Specialize with `true`:
393+
//! │ ├─┐ Patterns:
394+
//! │ │ │ 1. `[_, true]`
395+
//! │ │ │ 2. `[true, _]` // now exploring irrelevant cases
396+
//! │ │ │ 3. `[_, _]` // now exploring irrelevant cases
397+
//! │ │ │
398+
//! │ │ │ There are missing constructors in the first column (namely `false`), hence
399+
//! │ │ │ `true` is irrelevant for rows 1 and 3.
400+
//! │ │ │
401+
//! │ │ │ Specialize with `true`:
402+
//! │ │ ├─┐ Patterns:
403+
//! │ │ │ │ 1. `[true]` // now exploring irrelevant cases
404+
//! │ │ │ │ 2. `[_]` // now exploring irrelevant cases
405+
//! │ │ │ │ 3. `[_]` // now exploring irrelevant cases
406+
//! │ │ │ │
407+
//! │ │ │ │ The current case is irrelevant for all rows: we backtrack immediately.
408+
//! │ │ ├─┘
409+
//! │ │ │
410+
//! │ │ │ Specialize with `false`:
411+
//! │ │ ├─┐ Patterns:
412+
//! │ │ │ │ 1. `[true]`
413+
//! │ │ │ │ 3. `[_]` // now exploring irrelevant cases
414+
//! │ │ │ │
415+
//! │ │ │ │ Specialize with `true`:
416+
//! │ │ │ ├─┐ Patterns:
417+
//! │ │ │ │ │ 1. `[]`
418+
//! │ │ │ │ │ 3. `[]` // now exploring irrelevant cases
419+
//! │ │ │ │ │
420+
//! │ │ │ │ │ Row 1 is therefore useful.
421+
//! │ │ │ ├─┘
422+
//! <etc...>
423+
//! ```
424+
//!
425+
//! Relevancy allowed us to skip the case `(true, true, _)` entirely. In some cases this pruning can
426+
//! give drastic speedups. The case this was built for is the following (#118437):
427+
//!
428+
//! ```ignore(illustrative)
429+
//! match foo {
430+
//! (true, _, _, _, ..) => 1,
431+
//! (_, true, _, _, ..) => 2,
432+
//! (_, _, true, _, ..) => 3,
433+
//! (_, _, _, true, ..) => 4,
434+
//! ...
435+
//! }
436+
//! ```
437+
//!
438+
//! Without considering relevancy, we would explore all 2^n combinations of the `true` and `Missing`
439+
//! constructors. Relevancy tells us that e.g. `(true, true, false, false, false, ...)` is
440+
//! irrelevant for all the rows. This allows us to skip all cases with more than one `true`
441+
//! constructor, changing the runtime from exponential to linear.
442+
//!
443+
//!
444+
//! ## Relevancy and exhaustiveness
445+
//!
446+
//! For exhaustiveness, we do something slightly different w.r.t relevancy: we do not report
447+
//! witnesses of non-exhaustiveness that are irrelevant for the virtual wildcard row. For example,
448+
//! in:
449+
//!
450+
//! ```ignore(illustrative)
451+
//! match foo {
452+
//! (true, true) => {}
453+
//! }
454+
//! ```
455+
//!
456+
//! we only report `(false, _)` as missing. This was a deliberate choice made early in the
457+
//! development of rust, for diagnostic and performance purposes. As showed in the previous section,
458+
//! ignoring irrelevant cases preserves usefulness, so this choice still correctly computes whether
459+
//! a match is exhaustive.
460+
//!
461+
//!
462+
//!
303463
//! # Or-patterns
304464
//!
305465
//! What we have described so far works well if there are no or-patterns. To handle them, if the
@@ -674,11 +834,15 @@ impl fmt::Display for ValidityConstraint {
674834
struct PatStack<'a, 'p, Cx: TypeCx> {
675835
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
676836
pats: SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]>,
837+
/// Sometimes we know that as far as this row is concerned, the current case is already handled
838+
/// by a different, more general, case. When the case is irrelevant for all rows this allows us
839+
/// to skip a case entirely. This is purely an optimization. See at the top for details.
840+
relevant: bool,
677841
}
678842

679843
impl<'a, 'p, Cx: TypeCx> PatStack<'a, 'p, Cx> {
680844
fn from_pattern(pat: &'a DeconstructedPat<'p, Cx>) -> Self {
681-
PatStack { pats: smallvec![pat] }
845+
PatStack { pats: smallvec![pat], relevant: true }
682846
}
683847

684848
fn is_empty(&self) -> bool {
@@ -713,12 +877,17 @@ impl<'a, 'p, Cx: TypeCx> PatStack<'a, 'p, Cx> {
713877
&self,
714878
pcx: &PlaceCtxt<'a, 'p, Cx>,
715879
ctor: &Constructor<Cx>,
880+
ctor_is_relevant: bool,
716881
) -> PatStack<'a, 'p, Cx> {
717882
// We pop the head pattern and push the new fields extracted from the arguments of
718883
// `self.head()`.
719884
let mut new_pats = self.head().specialize(pcx, ctor);
720885
new_pats.extend_from_slice(&self.pats[1..]);
721-
PatStack { pats: new_pats }
886+
// `ctor` is relevant for this row if it is the actual constructor of this row, or if the
887+
// row has a wildcard and `ctor` is relevant for wildcards.
888+
let ctor_is_relevant =
889+
!matches!(self.head().ctor(), Constructor::Wildcard) || ctor_is_relevant;
890+
PatStack { pats: new_pats, relevant: self.relevant && ctor_is_relevant }
722891
}
723892
}
724893

@@ -784,10 +953,11 @@ impl<'a, 'p, Cx: TypeCx> MatrixRow<'a, 'p, Cx> {
784953
&self,
785954
pcx: &PlaceCtxt<'a, 'p, Cx>,
786955
ctor: &Constructor<Cx>,
956+
ctor_is_relevant: bool,
787957
parent_row: usize,
788958
) -> MatrixRow<'a, 'p, Cx> {
789959
MatrixRow {
790-
pats: self.pats.pop_head_constructor(pcx, ctor),
960+
pats: self.pats.pop_head_constructor(pcx, ctor, ctor_is_relevant),
791961
parent_row,
792962
is_under_guard: self.is_under_guard,
793963
useful: false,
@@ -913,8 +1083,9 @@ impl<'a, 'p, Cx: TypeCx> Matrix<'a, 'p, Cx> {
9131083
&self,
9141084
pcx: &PlaceCtxt<'a, 'p, Cx>,
9151085
ctor: &Constructor<Cx>,
1086+
ctor_is_relevant: bool,
9161087
) -> Matrix<'a, 'p, Cx> {
917-
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor);
1088+
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, ctor_is_relevant);
9181089
let new_validity = self.place_validity[0].specialize(ctor);
9191090
let new_place_validity = std::iter::repeat(new_validity)
9201091
.take(ctor.arity(pcx))
@@ -924,7 +1095,7 @@ impl<'a, 'p, Cx: TypeCx> Matrix<'a, 'p, Cx> {
9241095
Matrix { rows: Vec::new(), wildcard_row, place_validity: new_place_validity };
9251096
for (i, row) in self.rows().enumerate() {
9261097
if ctor.is_covered_by(pcx, row.head().ctor()) {
927-
let new_row = row.pop_head_constructor(pcx, ctor, i);
1098+
let new_row = row.pop_head_constructor(pcx, ctor, ctor_is_relevant, i);
9281099
matrix.expand_and_push(new_row);
9291100
}
9301101
}
@@ -1122,7 +1293,10 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
11221293
if matches!(ctor, Constructor::Missing) {
11231294
// We got the special `Missing` constructor that stands for the constructors not present
11241295
// in the match.
1125-
if !report_individual_missing_ctors {
1296+
if missing_ctors.is_empty() {
1297+
// Nothing to report.
1298+
*self = Self::empty();
1299+
} else if !report_individual_missing_ctors {
11261300
// Report `_` as missing.
11271301
let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard);
11281302
self.push_pattern(pat);
@@ -1181,6 +1355,13 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
11811355
) -> WitnessMatrix<Cx> {
11821356
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
11831357

1358+
if !matrix.wildcard_row.relevant && matrix.rows().all(|r| !r.pats.relevant) {
1359+
// Here we know that nothing will contribute further to exhaustiveness or usefulness. This
1360+
// is purely an optimization: skipping this check doesn't affect correctness. See the top of
1361+
// the file for details.
1362+
return WitnessMatrix::empty();
1363+
}
1364+
11841365
let Some(ty) = matrix.head_ty() else {
11851366
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
11861367
// A row is useful iff it has no (unguarded) rows above it.
@@ -1193,8 +1374,14 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
11931374
return WitnessMatrix::empty();
11941375
}
11951376
}
1196-
// No (unguarded) rows, so the match is not exhaustive. We return a new witness.
1197-
return WitnessMatrix::unit_witness();
1377+
// No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
1378+
// irrelevant.
1379+
return if matrix.wildcard_row.relevant {
1380+
WitnessMatrix::unit_witness()
1381+
} else {
1382+
// We choose to not report anything here; see at the top for details.
1383+
WitnessMatrix::empty()
1384+
};
11981385
};
11991386

12001387
debug!("ty: {ty:?}");
@@ -1237,32 +1424,21 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
12371424

12381425
let mut ret = WitnessMatrix::empty();
12391426
for ctor in split_ctors {
1240-
debug!("specialize({:?})", ctor);
12411427
// Dig into rows that match `ctor`.
1242-
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor);
1428+
debug!("specialize({:?})", ctor);
1429+
// `ctor` is *irrelevant* if there's another constructor in `split_ctors` that matches
1430+
// strictly fewer rows. In that case we can sometimes skip it. See the top of the file for
1431+
// details.
1432+
let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty();
1433+
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
12431434
let mut witnesses = ensure_sufficient_stack(|| {
12441435
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
12451436
});
12461437

1247-
let counts_for_exhaustiveness = match ctor {
1248-
Constructor::Missing => !missing_ctors.is_empty(),
1249-
// If there are missing constructors we'll report those instead. Since `Missing` matches
1250-
// only the wildcard rows, it matches fewer rows than this constructor, and is therefore
1251-
// guaranteed to result in the same or more witnesses. So skipping this does not
1252-
// jeopardize correctness.
1253-
_ => missing_ctors.is_empty(),
1254-
};
1255-
if counts_for_exhaustiveness {
1256-
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1257-
witnesses.apply_constructor(
1258-
pcx,
1259-
&missing_ctors,
1260-
&ctor,
1261-
report_individual_missing_ctors,
1262-
);
1263-
// Accumulate the found witnesses.
1264-
ret.extend(witnesses);
1265-
}
1438+
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1439+
witnesses.apply_constructor(pcx, &missing_ctors, &ctor, report_individual_missing_ctors);
1440+
// Accumulate the found witnesses.
1441+
ret.extend(witnesses);
12661442

12671443
// A parent row is useful if any of its children is.
12681444
for child_row in spec_matrix.rows() {

Diff for: compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub fn target() -> Target {
44
let mut base = base::windows_msvc::opts();
55
base.cpu = "pentium4".into();
66
base.max_atomic_width = Some(64);
7+
base.vendor = "win7".into();
78

89
base.add_pre_link_args(
910
LinkerFlavor::Msvc(Lld::No),

0 commit comments

Comments
 (0)