Skip to content

Commit 26a1e5f

Browse files
committed
Auto merge of #147659 - Zalathar:rollup-1rdmknm, r=Zalathar
Rollup of 11 pull requests Successful merges: - #146277 (Enable `u64` limbs in `core::num::bignum`) - #146976 (constify basic Clone impls) - #147249 (Do two passes of `handle_opaque_type_uses_next`) - #147266 (fix 2 search graph bugs) - #147468 (Implement fs api set_times and set_times_nofollow) - #147497 (`proc_macro` cleanups (3/N)) - #147594 (std: implement `pal::os::exit` for VEXos) - #147596 (Adjust the Arm targets in CI to reflect latest changes) - #147607 (GVN: Invalidate derefs at loop headers) - #147620 (Avoid redundant UB check in RangeFrom slice indexing) - #147647 (Hide vendoring and copyright in GHA group) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 4b94758 + 304b76d commit 26a1e5f

File tree

42 files changed

+1087
-199
lines changed

Some content is hidden

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

42 files changed

+1087
-199
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/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
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-
}

compiler/rustc_next_trait_solver/src/solve/search_graph.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,23 @@ where
9999
response_no_constraints(cx, input, Certainty::overflow(false))
100100
}
101101

102-
fn is_ambiguous_result(result: QueryResult<I>) -> bool {
103-
result.is_ok_and(|response| {
104-
has_no_inference_or_external_constraints(response)
102+
fn is_ambiguous_result(result: QueryResult<I>) -> Option<Certainty> {
103+
result.ok().and_then(|response| {
104+
if has_no_inference_or_external_constraints(response)
105105
&& matches!(response.value.certainty, Certainty::Maybe { .. })
106+
{
107+
Some(response.value.certainty)
108+
} else {
109+
None
110+
}
106111
})
107112
}
108113

109114
fn propagate_ambiguity(
110115
cx: I,
111116
for_input: CanonicalInput<I>,
112-
from_result: QueryResult<I>,
117+
certainty: Certainty,
113118
) -> QueryResult<I> {
114-
let certainty = from_result.unwrap().value.certainty;
115119
response_no_constraints(cx, for_input, certainty)
116120
}
117121

compiler/rustc_type_ir/src/interner.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::inherent::*;
1111
use crate::ir_print::IrPrint;
1212
use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
1313
use crate::relate::Relate;
14-
use crate::solve::{CanonicalInput, ExternalConstraintsData, QueryResult, inspect};
14+
use crate::solve::{CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect};
1515
use crate::visit::{Flags, TypeVisitable};
1616
use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph};
1717

@@ -550,6 +550,7 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
550550
impl<I: Interner> search_graph::Cx for I {
551551
type Input = CanonicalInput<I>;
552552
type Result = QueryResult<I>;
553+
type AmbiguityInfo = Certainty;
553554

554555
type DepNodeIndex = I::DepNodeIndex;
555556
type Tracked<T: Debug + Clone> = I::Tracked<T>;

0 commit comments

Comments
 (0)