Skip to content

Commit d86652a

Browse files
committed
Contraint the var_values to not contain type and const inference variable during PostTypeckUntilBorrowck for auto trait opaque ty
1 parent b3d3ab1 commit d86652a

3 files changed

Lines changed: 49 additions & 22 deletions

File tree

‎compiler/rustc_next_trait_solver/src/solve/trait_goals.rs‎

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt;
55
use rustc_type_ir::inherent::*;
66
use rustc_type_ir::lang_items::SolverTraitLangItem;
77
use rustc_type_ir::solve::{
8-
AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, MaybeInfo,
8+
AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, ExternalConstraintsData, MaybeInfo,
99
NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunNonErased,
1010
RerunReason, RerunResultExt, SizedTraitKind,
1111
};
@@ -1286,9 +1286,6 @@ where
12861286
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
12871287
let cx = self.cx();
12881288
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
1289-
if self.opaque_accesses.might_rerun() {
1290-
match self.opaque_accesses.rerun_always(RerunReason::AutoTraitLeakage)? {}
1291-
}
12921289

12931290
for item_bound in cx.item_self_bounds(def_id.into()).skip_binder() {
12941291
if item_bound.as_trait_clause().is_some_and(|b| b.def_id() == goal.predicate.def_id()) {
@@ -1303,25 +1300,49 @@ where
13031300
goal.with(cx, goal.predicate.with_replaced_self_ty(cx, hidden_ty)),
13041301
)?;
13051302
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1306-
});
1303+
})?;
13071304

1308-
let opaque_types_may_leak = match self.typing_mode() {
1309-
TypingMode::PostTypeckUntilBorrowck { .. } => false,
1310-
TypingMode::Coherence
1311-
| TypingMode::Typeck { .. }
1312-
| TypingMode::PostBorrowck { .. }
1313-
| TypingMode::Reflection
1314-
| TypingMode::PostAnalysis
1315-
| TypingMode::Codegen
1316-
| TypingMode::ErasedNotCoherence(MayBeErased) => true,
1317-
};
1305+
// Proving an auto trait for the hidden type must not constrain inference
1306+
// variables, as that would leak the hidden type itself.
1307+
if !candidate.result.value.var_values.is_identity_modulo_regions() {
1308+
return self.forced_ambiguity(MaybeInfo::AMBIGUOUS);
1309+
}
13181310

1319-
match candidate {
1320-
Ok(candidate) if has_only_region_constraints(candidate.result) => Ok(candidate),
1321-
Ok(candidate) if !opaque_types_may_leak => Ok(candidate),
1322-
Ok(_) => self.forced_ambiguity(MaybeInfo::AMBIGUOUS),
1323-
Err(err) => Err(err),
1311+
let ExternalConstraintsData {
1312+
region_constraints: _,
1313+
ref opaque_types,
1314+
ref normalization_nested_goals,
1315+
} = *candidate.result.value.external_constraints;
1316+
debug_assert!(normalization_nested_goals.is_empty());
1317+
1318+
// New defining uses may leak an opaque's hidden type into the caller's
1319+
// inference state. This is safe after typeck, where hidden types are already
1320+
// fixed and only regions are inferred, but not during typeck while hidden
1321+
// types may still contain inference variables.
1322+
if !opaque_types.is_empty() {
1323+
match self.typing_mode() {
1324+
// We're inferring regions of opaque types, but
1325+
// the type itself is already fully known, no way
1326+
// to leak the hidden type.
1327+
TypingMode::PostTypeckUntilBorrowck { .. } => {}
1328+
// We're inferring the hidden type of opaques, could
1329+
// leak types through it.
1330+
TypingMode::Typeck { .. } => {
1331+
return self.forced_ambiguity(MaybeInfo::AMBIGUOUS);
1332+
}
1333+
// we never add new uses to the opaque type storage
1334+
TypingMode::Coherence
1335+
| TypingMode::PostBorrowck { .. }
1336+
| TypingMode::Reflection
1337+
| TypingMode::PostAnalysis
1338+
| TypingMode::Codegen
1339+
| TypingMode::ErasedNotCoherence(MayBeErased) => {
1340+
return self.forced_ambiguity(MaybeInfo::AMBIGUOUS);
1341+
}
1342+
}
13241343
}
1344+
1345+
Ok(candidate)
13251346
}
13261347

13271348
// Return `Some` if there is an impl (built-in or user provided) that may

‎tests/ui/impl-trait/auto-trait-leakage/auxiliary/opaque-auto-trait-leakage.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
// External crate for `opaque-hidden-ty-inference.rs`.
2+
//
3+
// `define` returns `WaddupGamers<T, closure>`. Its `Unpin` impl only holds if
4+
// `<T as Leak>::Assoc` is that closure. The test's caller says `Assoc` is its
5+
// own opaque type instead, so checking `Unpin` would try to set that opaque
6+
// type to this closure.
17
pub struct WaddupGamers<T, U>(Option<T>, U);
28

39
impl<T: Leak<Assoc = U>, U> Unpin for WaddupGamers<T, U> {}

‎tests/ui/impl-trait/auto-trait-leakage/opaque-hidden-ty-inference.stderr‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | let opaque = require_auto(define::<T>());
66
| |
77
| required by a bound introduced by this call
88
|
9-
::: $DIR/auxiliary/opaque-auto-trait-leakage.rs:14:29
9+
::: $DIR/auxiliary/opaque-auto-trait-leakage.rs:20:29
1010
|
1111
LL | WaddupGamers(None::<T>, || ())
1212
| -- the expected closure
@@ -15,7 +15,7 @@ LL | WaddupGamers(None::<T>, || ())
1515
found type `!`
1616
= note: required for `WaddupGamers<T, {closure@dep::define<T>::{closure#0}}>` to implement `Unpin`
1717
note: required because it appears within the type `impl Sized`
18-
--> $DIR/auxiliary/opaque-auto-trait-leakage.rs:13:23
18+
--> $DIR/auxiliary/opaque-auto-trait-leakage.rs:19:23
1919
|
2020
LL | pub fn define<T>() -> impl Sized {
2121
| ^^^^^^^^^^

0 commit comments

Comments
 (0)