Skip to content

Commit e100792

Browse files
committed
Auto merge of rust-lang#147662 - Zalathar:rollup-j8ci0f2, r=Zalathar
Rollup of 12 pull requests Successful merges: - rust-lang#146277 (Enable `u64` limbs in `core::num::bignum`) - rust-lang#146976 (constify basic Clone impls) - rust-lang#147249 (Do two passes of `handle_opaque_type_uses_next`) - rust-lang#147266 (fix 2 search graph bugs) - rust-lang#147497 (`proc_macro` cleanups (3/N)) - rust-lang#147546 (Suppress unused_parens for labeled break) - rust-lang#147548 (Fix ICE for never pattern as closure parameters) - rust-lang#147594 (std: implement `pal::os::exit` for VEXos) - rust-lang#147596 (Adjust the Arm targets in CI to reflect latest changes) - rust-lang#147607 (GVN: Invalidate derefs at loop headers) - rust-lang#147620 (Avoid redundant UB check in RangeFrom slice indexing) - rust-lang#147647 (Hide vendoring and copyright in GHA group) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 2f7620a + 0f6fe91 commit e100792

File tree

37 files changed

+611
-151
lines changed

37 files changed

+611
-151
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,6 @@ fn add_hidden_type<'tcx>(
155155
}
156156
}
157157

158-
fn get_hidden_type<'tcx>(
159-
hidden_types: &DefinitionSiteHiddenTypes<'tcx>,
160-
def_id: LocalDefId,
161-
) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> {
162-
hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
163-
}
164-
165158
#[derive(Debug)]
166159
struct DefiningUse<'tcx> {
167160
/// The opaque type using non NLL vars. This uses the actual
@@ -508,7 +501,8 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
508501
let tcx = infcx.tcx;
509502
let mut errors = Vec::new();
510503
for &(key, hidden_type) in opaque_types {
511-
let Some(expected) = get_hidden_type(hidden_types, key.def_id) else {
504+
let Some(expected) = hidden_types.0.get(&key.def_id).map(|ty| EarlyBinder::bind(*ty))
505+
else {
512506
if !tcx.use_typing_mode_borrowck() {
513507
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
514508
&& alias_ty.def_id == key.def_id.to_def_id()

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1817,12 +1817,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18171817
expr: &'tcx hir::Expr<'tcx>,
18181818
) -> Ty<'tcx> {
18191819
let element_ty = if !args.is_empty() {
1820+
// This shouldn't happen unless there's another error
1821+
// (e.g., never patterns in inappropriate contexts).
1822+
if self.diverges.get() != Diverges::Maybe {
1823+
self.dcx()
1824+
.struct_span_err(expr.span, "unexpected divergence state in checking array")
1825+
.delay_as_bug();
1826+
}
1827+
18201828
let coerce_to = expected
18211829
.to_option(self)
18221830
.and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index())
18231831
.unwrap_or_else(|| self.next_ty_var(expr.span));
18241832
let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
1825-
assert_eq!(self.diverges.get(), Diverges::Maybe);
1833+
18261834
for e in args {
18271835
let e_ty = self.check_expr_with_hint(e, coerce_to);
18281836
let cause = self.misc(e.span);

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ pub(crate) struct FnCtxt<'a, 'tcx> {
104104
/// the diverges flag is set to something other than `Maybe`.
105105
pub(super) diverges: Cell<Diverges>,
106106

107-
/// If one of the function arguments is a never pattern, this counts as diverging code. This
108-
/// affect typechecking of the function body.
107+
/// If one of the function arguments is a never pattern, this counts as diverging code.
108+
/// This affect typechecking of the function body.
109109
pub(super) function_diverges_because_of_empty_arguments: Cell<Diverges>,
110110

111111
/// Whether the currently checked node is the whole body of the function.

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ fn typeck_with_inspect<'tcx>(
219219
// the future.
220220
fcx.check_repeat_exprs();
221221

222+
// We need to handle opaque types before emitting ambiguity errors as applying
223+
// defining uses may guide type inference.
224+
if fcx.next_trait_solver() {
225+
fcx.try_handle_opaque_type_uses_next();
226+
}
227+
222228
fcx.type_inference_fallback();
223229

224230
// Even though coercion casts provide type hints, we check casts after fallback for

compiler/rustc_hir_typeck/src/opaque_types.rs

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,50 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
2222
/// inference variables.
2323
///
2424
/// It then uses these defining uses to guide inference for all other uses.
25+
///
26+
/// Unlike `handle_opaque_type_uses_next`, this does not report errors.
27+
#[instrument(level = "debug", skip(self))]
28+
pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
29+
// We clone the opaques instead of stealing them here as we still need
30+
// to use them after fallback.
31+
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
32+
33+
self.compute_definition_site_hidden_types(opaque_types, false);
34+
}
35+
36+
/// This takes all the opaque type uses during HIR typeck. It first computes
37+
/// the concrete hidden type by iterating over all defining uses.
38+
///
39+
/// A use during HIR typeck is defining if all non-lifetime arguments are
40+
/// unique generic parameters and the hidden type does not reference any
41+
/// inference variables.
42+
///
43+
/// It then uses these defining uses to guide inference for all other uses.
2544
#[instrument(level = "debug", skip(self))]
2645
pub(super) fn handle_opaque_type_uses_next(&mut self) {
2746
// We clone the opaques instead of stealing them here as they are still used for
2847
// normalization in the next generation trait solver.
29-
let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types();
48+
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
3049
let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
3150
let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
3251
debug_assert_eq!(prev, None);
33-
for entry in &mut opaque_types {
34-
*entry = self.resolve_vars_if_possible(*entry);
35-
}
36-
debug!(?opaque_types);
3752

38-
self.compute_definition_site_hidden_types(&opaque_types);
39-
self.apply_definition_site_hidden_types(&opaque_types);
53+
self.compute_definition_site_hidden_types(opaque_types, true);
4054
}
4155
}
4256

57+
#[derive(Copy, Clone, Debug)]
4358
enum UsageKind<'tcx> {
4459
None,
4560
NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>),
4661
UnconstrainedHiddenType(OpaqueHiddenType<'tcx>),
47-
HasDefiningUse,
62+
HasDefiningUse(OpaqueHiddenType<'tcx>),
4863
}
4964

5065
impl<'tcx> UsageKind<'tcx> {
5166
fn merge(&mut self, other: UsageKind<'tcx>) {
5267
match (&*self, &other) {
53-
(UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(),
68+
(UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
5469
(UsageKind::None, _) => *self = other,
5570
// When mergining non-defining uses, prefer earlier ones. This means
5671
// the error happens as early as possible.
@@ -64,7 +79,7 @@ impl<'tcx> UsageKind<'tcx> {
6479
// intended to be defining.
6580
(
6681
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
67-
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse,
82+
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
6883
) => *self = other,
6984
}
7085
}
@@ -73,8 +88,14 @@ impl<'tcx> UsageKind<'tcx> {
7388
impl<'tcx> FnCtxt<'_, 'tcx> {
7489
fn compute_definition_site_hidden_types(
7590
&mut self,
76-
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
91+
mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
92+
error_on_missing_defining_use: bool,
7793
) {
94+
for entry in opaque_types.iter_mut() {
95+
*entry = self.resolve_vars_if_possible(*entry);
96+
}
97+
debug!(?opaque_types);
98+
7899
let tcx = self.tcx;
79100
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
80101
else {
@@ -88,19 +109,47 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
88109
_ => unreachable!("not opaque or generator: {def_id:?}"),
89110
}
90111

112+
// We do actually need to check this the second pass (we can't just
113+
// store this), because we can go from `UnconstrainedHiddenType` to
114+
// `HasDefiningUse` (because of fallback)
91115
let mut usage_kind = UsageKind::None;
92-
for &(opaque_type_key, hidden_type) in opaque_types {
116+
for &(opaque_type_key, hidden_type) in &opaque_types {
93117
if opaque_type_key.def_id != def_id {
94118
continue;
95119
}
96120

97121
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
98-
if let UsageKind::HasDefiningUse = usage_kind {
122+
123+
if let UsageKind::HasDefiningUse(..) = usage_kind {
99124
break;
100125
}
101126
}
102127

128+
if let UsageKind::HasDefiningUse(ty) = usage_kind {
129+
for &(opaque_type_key, hidden_type) in &opaque_types {
130+
if opaque_type_key.def_id != def_id {
131+
continue;
132+
}
133+
134+
let expected = EarlyBinder::bind(ty.ty).instantiate(tcx, opaque_type_key.args);
135+
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
136+
}
137+
138+
// Being explicit here: it may be possible that we in a
139+
// previous call to this function we did an insert, but this
140+
// should be just fine, since they all get equated anyways and
141+
// we shouldn't ever go from `HasDefiningUse` to anyway else.
142+
let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
143+
}
144+
145+
// If we're in `fn try_handle_opaque_type_uses_next` then do not
146+
// report any errors.
147+
if !error_on_missing_defining_use {
148+
continue;
149+
}
150+
103151
let guar = match usage_kind {
152+
UsageKind::HasDefiningUse(_) => continue,
104153
UsageKind::None => {
105154
if let Some(guar) = self.tainted_by_errors() {
106155
guar
@@ -137,7 +186,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
137186
.emit()
138187
}
139188
}
140-
UsageKind::HasDefiningUse => continue,
141189
};
142190

143191
self.typeck_results
@@ -148,8 +196,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
148196
}
149197
}
150198

199+
#[tracing::instrument(skip(self), ret)]
151200
fn consider_opaque_type_use(
152-
&mut self,
201+
&self,
153202
opaque_type_key: OpaqueTypeKey<'tcx>,
154203
hidden_type: OpaqueHiddenType<'tcx>,
155204
) -> UsageKind<'tcx> {
@@ -161,11 +210,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
161210
) {
162211
match err {
163212
NonDefiningUseReason::Tainted(guar) => {
164-
self.typeck_results.borrow_mut().hidden_types.insert(
165-
opaque_type_key.def_id,
166-
OpaqueHiddenType::new_error(self.tcx, guar),
167-
);
168-
return UsageKind::HasDefiningUse;
213+
return UsageKind::HasDefiningUse(OpaqueHiddenType::new_error(self.tcx, guar));
169214
}
170215
_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
171216
};
@@ -193,27 +238,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
193238
self.tcx,
194239
DefiningScopeKind::HirTypeck,
195240
);
196-
197-
let prev = self
198-
.typeck_results
199-
.borrow_mut()
200-
.hidden_types
201-
.insert(opaque_type_key.def_id, hidden_type);
202-
assert!(prev.is_none());
203-
UsageKind::HasDefiningUse
204-
}
205-
206-
fn apply_definition_site_hidden_types(
207-
&mut self,
208-
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
209-
) {
210-
let tcx = self.tcx;
211-
for &(key, hidden_type) in opaque_types {
212-
let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap();
213-
214-
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
215-
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
216-
}
241+
UsageKind::HasDefiningUse(hidden_type)
217242
}
218243

219244
/// We may in theory add further uses of an opaque after cloning the opaque

compiler/rustc_lint/src/unused.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,16 @@ trait UnusedDelimLint {
914914
(value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
915915
}
916916

917-
Break(_, Some(ref value)) => {
917+
Break(label, Some(ref value)) => {
918+
// Don't lint on `break 'label ({...})` - the parens are necessary
919+
// to disambiguate from `break 'label {...}` which would be a syntax error.
920+
// This avoids conflicts with the `break_with_label_and_loop` lint.
921+
if label.is_some()
922+
&& matches!(value.kind, ast::ExprKind::Paren(ref inner)
923+
if matches!(inner.kind, ast::ExprKind::Block(..)))
924+
{
925+
return;
926+
}
918927
(value, UnusedDelimsCtx::BreakValue, false, None, None, true)
919928
}
920929

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use rustc_index::bit_set::DenseBitSet;
2+
3+
use super::*;
4+
5+
/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
6+
/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
7+
/// However, computing dominators is expensive, so we approximate according to the post-order
8+
/// traversal order. A loop header for us is a block which is visited after its predecessor in
9+
/// post-order. This is ok as we mostly need a heuristic.
10+
pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
11+
let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
12+
let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
13+
for (bb, bbdata) in traversal::postorder(body) {
14+
// Post-order means we visit successors before the block for acyclic CFGs.
15+
// If the successor is not visited yet, consider it a loop header.
16+
for succ in bbdata.terminator().successors() {
17+
if !visited.contains(succ) {
18+
maybe_loop_headers.insert(succ);
19+
}
20+
}
21+
22+
// Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
23+
// bb1: goto -> bb1;
24+
let _new = visited.insert(bb);
25+
debug_assert!(_new);
26+
}
27+
28+
maybe_loop_headers
29+
}

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ mod statement;
5151
mod syntax;
5252
mod terminator;
5353

54+
pub mod loops;
5455
pub mod traversal;
5556
pub mod visit;
5657

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
129129
let ssa = SsaLocals::new(tcx, body, typing_env);
130130
// Clone dominators because we need them while mutating the body.
131131
let dominators = body.basic_blocks.dominators().clone();
132+
let maybe_loop_headers = loops::maybe_loop_headers(body);
132133

133134
let arena = DroplessArena::default();
134135
let mut state =
@@ -141,6 +142,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
141142

142143
let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
143144
for bb in reverse_postorder {
145+
// N.B. With loops, reverse postorder cannot produce a valid topological order.
146+
// A statement or terminator from inside the loop, that is not processed yet, may have performed an indirect write.
147+
if maybe_loop_headers.contains(bb) {
148+
state.invalidate_derefs();
149+
}
144150
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
145151
state.visit_basic_block_data(bb, data);
146152
}

compiler/rustc_mir_transform/src/jump_threading.rs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
8484
body,
8585
arena,
8686
map: Map::new(tcx, body, Some(MAX_PLACES)),
87-
maybe_loop_headers: maybe_loop_headers(body),
87+
maybe_loop_headers: loops::maybe_loop_headers(body),
8888
opportunities: Vec::new(),
8989
};
9090

@@ -830,29 +830,3 @@ enum Update {
830830
Incr,
831831
Decr,
832832
}
833-
834-
/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
835-
/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
836-
/// However, computing dominators is expensive, so we approximate according to the post-order
837-
/// traversal order. A loop header for us is a block which is visited after its predecessor in
838-
/// post-order. This is ok as we mostly need a heuristic.
839-
fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
840-
let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
841-
let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
842-
for (bb, bbdata) in traversal::postorder(body) {
843-
// Post-order means we visit successors before the block for acyclic CFGs.
844-
// If the successor is not visited yet, consider it a loop header.
845-
for succ in bbdata.terminator().successors() {
846-
if !visited.contains(succ) {
847-
maybe_loop_headers.insert(succ);
848-
}
849-
}
850-
851-
// Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
852-
// bb1: goto -> bb1;
853-
let _new = visited.insert(bb);
854-
debug_assert!(_new);
855-
}
856-
857-
maybe_loop_headers
858-
}

0 commit comments

Comments
 (0)