Skip to content

Commit ac0aff2

Browse files
committed
Auto merge of #149572 - cuviper:beta-next, r=cuviper
[beta] backports - rustdoc: Use configured target modifiers when collecting doctests #148068 - fix(rustdoc): Color doctest errors #148834 - Fix the issue of unused assignment from MIR liveness checking #149072 - Skip unused variables warning for unreachable code #149096 - In `BTreeMap::eq`, do not compare the elements if the sizes are different. #149125 - Handle cycles when checking impl candidates for `doc(hidden)` #149185 - Generalize branch references #148395 - only the commit updating CI scripts - Change default branch references #148564 r? cuviper
2 parents f3f1244 + 519b57b commit ac0aff2

File tree

32 files changed

+506
-75
lines changed

32 files changed

+506
-75
lines changed

.github/workflows/post-merge.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ name: Post merge analysis
66
on:
77
push:
88
branches:
9-
- master
9+
- main
1010

1111
jobs:
1212
analysis:

compiler/rustc_errors/src/emitter.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3465,14 +3465,9 @@ impl Drop for Buffy {
34653465

34663466
pub fn stderr_destination(color: ColorConfig) -> Destination {
34673467
let buffer_writer = std::io::stderr();
3468-
let choice = color.to_color_choice();
34693468
// We need to resolve `ColorChoice::Auto` before `Box`ing since
34703469
// `ColorChoice::Auto` on `dyn Write` will always resolve to `Never`
3471-
let choice = if matches!(choice, ColorChoice::Auto) {
3472-
AutoStream::choice(&buffer_writer)
3473-
} else {
3474-
choice
3475-
};
3470+
let choice = get_stderr_color_choice(color, &buffer_writer);
34763471
// On Windows we'll be performing global synchronization on the entire
34773472
// system for emitting rustc errors, so there's no need to buffer
34783473
// anything.
@@ -3487,6 +3482,11 @@ pub fn stderr_destination(color: ColorConfig) -> Destination {
34873482
}
34883483
}
34893484

3485+
pub fn get_stderr_color_choice(color: ColorConfig, stderr: &std::io::Stderr) -> ColorChoice {
3486+
let choice = color.to_color_choice();
3487+
if matches!(choice, ColorChoice::Auto) { AutoStream::choice(stderr) } else { choice }
3488+
}
3489+
34903490
/// On Windows, BRIGHT_BLUE is hard to read on black. Use cyan instead.
34913491
///
34923492
/// See #36178.

compiler/rustc_mir_transform/src/liveness.rs

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ struct Access {
4545
/// When we encounter multiple statements at the same location, we only increase the liveness,
4646
/// in order to avoid false positives.
4747
live: bool,
48+
/// Is this a direct access to the place itself, no projections, or to a field?
49+
/// This helps distinguish `x = ...` from `x.field = ...`
50+
is_direct: bool,
4851
}
4952

5053
#[tracing::instrument(level = "debug", skip(tcx), ret)]
@@ -689,15 +692,17 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
689692
|place: Place<'tcx>, kind, source_info: SourceInfo, live: &DenseBitSet<PlaceIndex>| {
690693
if let Some((index, extra_projections)) = checked_places.get(place.as_ref()) {
691694
if !is_indirect(extra_projections) {
695+
let is_direct = extra_projections.is_empty();
692696
match assignments[index].entry(source_info) {
693697
IndexEntry::Vacant(v) => {
694-
let access = Access { kind, live: live.contains(index) };
698+
let access = Access { kind, live: live.contains(index), is_direct };
695699
v.insert(access);
696700
}
697701
IndexEntry::Occupied(mut o) => {
698702
// There were already a sighting. Mark this statement as live if it
699703
// was, to avoid false positives.
700704
o.get_mut().live |= live.contains(index);
705+
o.get_mut().is_direct &= is_direct;
701706
}
702707
}
703708
}
@@ -781,7 +786,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
781786
continue;
782787
};
783788
let source_info = body.local_decls[place.local].source_info;
784-
let access = Access { kind, live: live.contains(index) };
789+
let access = Access { kind, live: live.contains(index), is_direct: true };
785790
assignments[index].insert(source_info, access);
786791
}
787792
}
@@ -875,6 +880,33 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
875880
dead_captures
876881
}
877882

883+
/// Check if a local is referenced in any reachable basic block.
884+
/// Variables in unreachable code (e.g., after `todo!()`) should not trigger unused warnings.
885+
fn is_local_in_reachable_code(&self, local: Local) -> bool {
886+
struct LocalVisitor {
887+
target_local: Local,
888+
found: bool,
889+
}
890+
891+
impl<'tcx> Visitor<'tcx> for LocalVisitor {
892+
fn visit_local(&mut self, local: Local, _context: PlaceContext, _location: Location) {
893+
if local == self.target_local {
894+
self.found = true;
895+
}
896+
}
897+
}
898+
899+
let mut visitor = LocalVisitor { target_local: local, found: false };
900+
for (bb, bb_data) in traversal::postorder(self.body) {
901+
visitor.visit_basic_block_data(bb, bb_data);
902+
if visitor.found {
903+
return true;
904+
}
905+
}
906+
907+
false
908+
}
909+
878910
/// Report fully unused locals, and forget the corresponding assignments.
879911
fn report_fully_unused(&mut self) {
880912
let tcx = self.tcx;
@@ -928,6 +960,10 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
928960

929961
let statements = &mut self.assignments[index];
930962
if statements.is_empty() {
963+
if !self.is_local_in_reachable_code(local) {
964+
continue;
965+
}
966+
931967
let sugg = if from_macro {
932968
errors::UnusedVariableSugg::NoSugg { span: def_span, name }
933969
} else {
@@ -977,8 +1013,10 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
9771013
self.checked_places,
9781014
self.body,
9791015
) {
980-
statements.clear();
981-
continue;
1016+
statements.retain(|_, access| access.is_direct);
1017+
if statements.is_empty() {
1018+
continue;
1019+
}
9821020
}
9831021

9841022
let typo = maybe_suggest_typo();
@@ -1049,26 +1087,28 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10491087

10501088
let Some((name, decl_span)) = self.checked_places.names[index] else { continue };
10511089

1052-
// We have outstanding assignments and with non-trivial drop.
1053-
// This is probably a drop-guard, so we do not issue a warning there.
1054-
if maybe_drop_guard(
1090+
let is_maybe_drop_guard = maybe_drop_guard(
10551091
tcx,
10561092
self.typing_env,
10571093
index,
10581094
&self.ever_dropped,
10591095
self.checked_places,
10601096
self.body,
1061-
) {
1062-
continue;
1063-
}
1097+
);
10641098

10651099
// We probed MIR in reverse order for dataflow.
10661100
// We revert the vector to give a consistent order to the user.
1067-
for (source_info, Access { live, kind }) in statements.into_iter().rev() {
1101+
for (source_info, Access { live, kind, is_direct }) in statements.into_iter().rev() {
10681102
if live {
10691103
continue;
10701104
}
10711105

1106+
// If this place was dropped and has non-trivial drop,
1107+
// skip reporting field assignments.
1108+
if !is_direct && is_maybe_drop_guard {
1109+
continue;
1110+
}
1111+
10721112
// Report the dead assignment.
10731113
let Some(hir_id) = source_info.scope.lint_root(&self.body.source_scopes) else {
10741114
continue;

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use core::ops::ControlFlow;
22
use std::borrow::Cow;
3+
use std::collections::hash_set;
34
use std::path::PathBuf;
45

56
use rustc_abi::ExternAbi;
67
use rustc_ast::ast::LitKind;
78
use rustc_ast::{LitIntType, TraitObjectSyntax};
8-
use rustc_data_structures::fx::FxHashMap;
9+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
910
use rustc_data_structures::unord::UnordSet;
1011
use rustc_errors::codes::*;
1112
use rustc_errors::{
@@ -1927,11 +1928,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19271928
if self.tcx.visibility(did).is_accessible_from(body_def_id, self.tcx) {
19281929
// don't suggest foreign `#[doc(hidden)]` types
19291930
if !did.is_local() {
1930-
while let Some(parent) = parent_map.get(&did) {
1931+
let mut previously_seen_dids: FxHashSet<DefId> = Default::default();
1932+
previously_seen_dids.insert(did);
1933+
while let Some(&parent) = parent_map.get(&did)
1934+
&& let hash_set::Entry::Vacant(v) =
1935+
previously_seen_dids.entry(parent)
1936+
{
19311937
if self.tcx.is_doc_hidden(did) {
19321938
return false;
19331939
}
1934-
did = *parent;
1940+
v.insert();
1941+
did = parent;
19351942
}
19361943
}
19371944
true

compiler/rustc_trait_selection/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#![feature(associated_type_defaults)]
2121
#![feature(box_patterns)]
2222
#![feature(default_field_values)]
23+
#![feature(hash_set_entry)]
2324
#![feature(if_let_guard)]
2425
#![feature(iter_intersperse)]
2526
#![feature(iterator_try_reduce)]

library/alloc/src/collections/btree/map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2414,7 +2414,7 @@ impl<K, V> Default for BTreeMap<K, V> {
24142414
#[stable(feature = "rust1", since = "1.0.0")]
24152415
impl<K: PartialEq, V: PartialEq, A: Allocator + Clone> PartialEq for BTreeMap<K, V, A> {
24162416
fn eq(&self, other: &BTreeMap<K, V, A>) -> bool {
2417-
self.iter().eq(other)
2417+
self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b)
24182418
}
24192419
}
24202420

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//! Regression tests which fail if some collections' `PartialEq::eq` impls compare
2+
//! elements when the collections have different sizes.
3+
//! This behavior is not guaranteed either way, so regressing these tests is fine
4+
//! if it is done on purpose.
5+
use std::cmp::Ordering;
6+
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList};
7+
8+
/// This intentionally has a panicking `PartialEq` impl, to test that various
9+
/// collections' `PartialEq` impls don't actually compare elements if their sizes
10+
/// are unequal.
11+
///
12+
/// This is not advisable in normal code.
13+
#[derive(Debug, Clone, Copy, Hash)]
14+
struct Evil;
15+
16+
impl PartialEq for Evil {
17+
fn eq(&self, _: &Self) -> bool {
18+
panic!("Evil::eq is evil");
19+
}
20+
}
21+
impl Eq for Evil {}
22+
23+
impl PartialOrd for Evil {
24+
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
25+
Some(Ordering::Equal)
26+
}
27+
}
28+
29+
impl Ord for Evil {
30+
fn cmp(&self, _: &Self) -> Ordering {
31+
// Constructing a `BTreeSet`/`BTreeMap` uses `cmp` on the elements,
32+
// but comparing it with with `==` uses `eq` on the elements,
33+
// so Evil::cmp doesn't need to be evil.
34+
Ordering::Equal
35+
}
36+
}
37+
38+
// check Evil works
39+
#[test]
40+
#[should_panic = "Evil::eq is evil"]
41+
fn evil_eq_works() {
42+
let v1 = vec![Evil];
43+
let v2 = vec![Evil];
44+
45+
_ = v1 == v2;
46+
}
47+
48+
// check various containers don't compare if their sizes are different
49+
50+
#[test]
51+
fn vec_evil_eq() {
52+
let v1 = vec![Evil];
53+
let v2 = vec![Evil; 2];
54+
55+
assert_eq!(false, v1 == v2);
56+
}
57+
58+
#[test]
59+
fn hashset_evil_eq() {
60+
let s1 = HashSet::from([(0, Evil)]);
61+
let s2 = HashSet::from([(0, Evil), (1, Evil)]);
62+
63+
assert_eq!(false, s1 == s2);
64+
}
65+
66+
#[test]
67+
fn hashmap_evil_eq() {
68+
let m1 = HashMap::from([(0, Evil)]);
69+
let m2 = HashMap::from([(0, Evil), (1, Evil)]);
70+
71+
assert_eq!(false, m1 == m2);
72+
}
73+
74+
#[test]
75+
fn btreeset_evil_eq() {
76+
let s1 = BTreeSet::from([(0, Evil)]);
77+
let s2 = BTreeSet::from([(0, Evil), (1, Evil)]);
78+
79+
assert_eq!(false, s1 == s2);
80+
}
81+
82+
#[test]
83+
fn btreemap_evil_eq() {
84+
let m1 = BTreeMap::from([(0, Evil)]);
85+
let m2 = BTreeMap::from([(0, Evil), (1, Evil)]);
86+
87+
assert_eq!(false, m1 == m2);
88+
}
89+
90+
#[test]
91+
fn linkedlist_evil_eq() {
92+
let m1 = LinkedList::from([Evil]);
93+
let m2 = LinkedList::from([Evil; 2]);
94+
95+
assert_eq!(false, m1 == m2);
96+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
mod binary_heap;
2+
mod eq_diff_len;

src/ci/citool/src/jobs.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub fn load_job_db(db: &str) -> anyhow::Result<JobDatabase> {
123123
/// modulo certain carve-outs" in [`validate_job_database`].
124124
///
125125
/// This invariant is important to make sure that it's not easily possible (without modifying
126-
/// `citool`) to have PRs with red PR-only CI jobs merged into `master`, causing all subsequent PR
126+
/// `citool`) to have PRs with red PR-only CI jobs merged into `main`, causing all subsequent PR
127127
/// CI runs to be red until the cause is fixed.
128128
fn register_pr_jobs_as_auto_jobs(db: &mut JobDatabase) -> anyhow::Result<()> {
129129
for pr_job in &db.pr_jobs {
@@ -273,7 +273,7 @@ pub enum RunType {
273273
/// Merge attempt workflow
274274
AutoJob,
275275
/// Fake job only used for sharing Github Actions cache.
276-
MasterJob,
276+
MainJob,
277277
}
278278

279279
/// Maximum number of custom try jobs that can be requested in a single
@@ -323,7 +323,7 @@ fn calculate_jobs(
323323
(jobs, "try", &db.envs.try_env)
324324
}
325325
RunType::AutoJob => (db.auto_jobs.clone(), "auto", &db.envs.auto_env),
326-
RunType::MasterJob => return Ok(vec![]),
326+
RunType::MainJob => return Ok(vec![]),
327327
};
328328
let jobs = substitute_github_vars(jobs.clone())
329329
.context("Failed to substitute GitHub context variables in jobs")?;
@@ -376,15 +376,15 @@ pub fn calculate_job_matrix(
376376
eprintln!("Run type: {run_type:?}");
377377

378378
let jobs = calculate_jobs(&run_type, &db, channel)?;
379-
if jobs.is_empty() && !matches!(run_type, RunType::MasterJob) {
379+
if jobs.is_empty() && !matches!(run_type, RunType::MainJob) {
380380
return Err(anyhow::anyhow!("Computed job list is empty"));
381381
}
382382

383383
let run_type = match run_type {
384384
RunType::PullRequest => "pr",
385385
RunType::TryJob { .. } => "try",
386386
RunType::AutoJob => "auto",
387-
RunType::MasterJob => "master",
387+
RunType::MainJob => "main",
388388
};
389389

390390
eprintln!("Output");

src/ci/citool/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl GitHubContext {
4747
Some(RunType::TryJob { job_patterns: patterns })
4848
}
4949
("push", "refs/heads/auto") => Some(RunType::AutoJob),
50-
("push", "refs/heads/master") => Some(RunType::MasterJob),
50+
("push", "refs/heads/main") => Some(RunType::MainJob),
5151
_ => None,
5252
}
5353
}

0 commit comments

Comments
 (0)