Skip to content

Commit 748c7c1

Browse files
committed
Auto merge of rust-lang#139837 - Zalathar:rollup-hqr9nyf, r=Zalathar
Rollup of 12 pull requests Successful merges: - rust-lang#138374 (Enable contracts for const functions) - rust-lang#138380 (ci: add runners for vanilla LLVM 20) - rust-lang#138393 (Allow const patterns of matches to contain pattern types) - rust-lang#139393 (rustdoc-json: Output target feature information) - rust-lang#139517 (std: sys: process: uefi: Use NULL stdin by default) - rust-lang#139554 (std: add Output::exit_ok) - rust-lang#139745 (Avoid unused clones in `Cloned<I>` and `Copied<I>`) - rust-lang#139757 (opt-dist: use executable-extension for host llvm-profdata) - rust-lang#139778 (Add test for issue 34834) - rust-lang#139783 (Use `compiletest-ignore-dir` for bootstrap self-tests) - rust-lang#139789 (do not unnecessarily leak auto traits in item bounds) - rust-lang#139791 (drop global where-bounds before merging candidates) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 2da29db + 7f3fec3 commit 748c7c1

File tree

72 files changed

+1496
-93
lines changed

Some content is hidden

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

72 files changed

+1496
-93
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -399,12 +399,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
399399
&mut self,
400400
expr: &'hir hir::Expr<'hir>,
401401
span: Span,
402-
check_ident: Ident,
403-
check_hir_id: HirId,
402+
cond_ident: Ident,
403+
cond_hir_id: HirId,
404404
) -> &'hir hir::Expr<'hir> {
405-
let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
406-
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
407-
self.expr_call(span, checker_fn, std::slice::from_ref(expr))
405+
let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
406+
let call_expr = self.expr_call_lang_item_fn_mut(
407+
span,
408+
hir::LangItem::ContractCheckEnsures,
409+
arena_vec![self; *cond_fn, *expr],
410+
);
411+
self.arena.alloc(call_expr)
408412
}
409413

410414
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {

compiler/rustc_ast_lowering/src/item.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1206,8 +1206,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
12061206
let precond = if let Some(req) = &contract.requires {
12071207
// Lower the precondition check intrinsic.
12081208
let lowered_req = this.lower_expr_mut(&req);
1209+
let req_span = this.mark_span_with_reason(
1210+
DesugaringKind::Contract,
1211+
lowered_req.span,
1212+
None,
1213+
);
12091214
let precond = this.expr_call_lang_item_fn_mut(
1210-
req.span,
1215+
req_span,
12111216
hir::LangItem::ContractCheckRequires,
12121217
&*arena_vec![this; lowered_req],
12131218
);
@@ -1217,6 +1222,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
12171222
};
12181223
let (postcond, body) = if let Some(ens) = &contract.ensures {
12191224
let ens_span = this.lower_span(ens.span);
1225+
let ens_span =
1226+
this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
12201227
// Set up the postcondition `let` statement.
12211228
let check_ident: Ident =
12221229
Ident::from_str_and_span("__ensures_checker", ens_span);

compiler/rustc_borrowck/src/type_check/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1557,11 +1557,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
15571557
}
15581558
}
15591559
CastKind::Transmute => {
1560-
span_mirbug!(
1561-
self,
1562-
rvalue,
1563-
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
1564-
);
1560+
let ty_from = op.ty(self.body, tcx);
1561+
match ty_from.kind() {
1562+
ty::Pat(base, _) if base == ty => {}
1563+
_ => span_mirbug!(
1564+
self,
1565+
rvalue,
1566+
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
1567+
),
1568+
}
15651569
}
15661570
}
15671571
}

compiler/rustc_hir/src/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,8 @@ language_item_table! {
442442
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
443443
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
444444
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
445+
446+
ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None;
445447
}
446448

447449
/// The requirement imposed on the generics of a lang item

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,11 @@ pub(crate) fn check_intrinsic_type(
217217
};
218218
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
219219
} else if intrinsic_name == sym::contract_check_ensures {
220-
// contract_check_ensures::<'a, Ret, C>(&'a Ret, C)
221-
// where C: impl Fn(&'a Ret) -> bool,
220+
// contract_check_ensures::<Ret, C>(Ret, C) -> Ret
221+
// where C: for<'a> Fn(&'a Ret) -> bool,
222222
//
223-
// so: two type params, one lifetime param, 0 const params, two inputs, no return
224-
225-
let p = generics.param_at(0, tcx);
226-
let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
227-
let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
228-
(2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe)
223+
// so: two type params, 0 lifetime param, 0 const params, two inputs, no return
224+
(2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe)
229225
} else {
230226
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
231227
let (n_tps, n_cts, inputs, output) = match intrinsic_name {

compiler/rustc_mir_build/src/builder/matches/test.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
140140
let success_block = target_block(TestBranch::Success);
141141
let fail_block = target_block(TestBranch::Failure);
142142

143-
let expect_ty = value.ty();
144-
let expect = self.literal_operand(test.span, value);
143+
let mut expect_ty = value.ty();
144+
let mut expect = self.literal_operand(test.span, value);
145145

146146
let mut place = place;
147147
let mut block = block;
@@ -174,6 +174,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
174174
place = ref_str;
175175
ty = ref_str_ty;
176176
}
177+
&ty::Pat(base, _) => {
178+
assert_eq!(ty, value.ty());
179+
assert!(base.is_trivially_pure_clone_copy());
180+
181+
let transmuted_place = self.temp(base, test.span);
182+
self.cfg.push_assign(
183+
block,
184+
self.source_info(scrutinee_span),
185+
transmuted_place,
186+
Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
187+
);
188+
189+
let transmuted_expect = self.temp(base, test.span);
190+
self.cfg.push_assign(
191+
block,
192+
self.source_info(test.span),
193+
transmuted_expect,
194+
Rvalue::Cast(CastKind::Transmute, expect, base),
195+
);
196+
197+
place = transmuted_place;
198+
expect = Operand::Copy(transmuted_expect);
199+
ty = base;
200+
expect_ty = base;
201+
}
177202
_ => {}
178203
}
179204

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

+31-9
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ where
164164
ecx: &mut EvalCtxt<'_, D>,
165165
goal: Goal<I, Self>,
166166
) -> Result<Candidate<I>, NoSolution> {
167+
let cx = ecx.cx();
167168
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
168169
return Err(NoSolution);
169170
}
@@ -174,20 +175,37 @@ where
174175

175176
// Only consider auto impls of unsafe traits when there are no unsafe
176177
// fields.
177-
if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
178+
if cx.trait_is_unsafe(goal.predicate.def_id())
178179
&& goal.predicate.self_ty().has_unsafe_fields()
179180
{
180181
return Err(NoSolution);
181182
}
182183

183-
// We only look into opaque types during analysis for opaque types
184-
// outside of their defining scope. Doing so for opaques in the
185-
// defining scope may require calling `typeck` on the same item we're
186-
// currently type checking, which will result in a fatal cycle that
187-
// ideally we want to avoid, since we can make progress on this goal
188-
// via an alias bound or a locally-inferred hidden type instead.
184+
// We leak the implemented auto traits of opaques outside of their defining scope.
185+
// This depends on `typeck` of the defining scope of that opaque, which may result in
186+
// fatal query cycles.
187+
//
188+
// We only get to this point if we're outside of the defining scope as we'd otherwise
189+
// be able to normalize the opaque type. We may also cycle in case `typeck` of a defining
190+
// scope relies on the current context, e.g. either because it also leaks auto trait
191+
// bounds of opaques defined in the current context or by evaluating the current item.
192+
//
193+
// To avoid this we don't try to leak auto trait bounds if they can also be proven via
194+
// item bounds of the opaque. These bounds are always applicable as auto traits must not
195+
// have any generic parameters. They would also get preferred over the impl candidate
196+
// when merging candidates anyways.
197+
//
198+
// See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs.
189199
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
190200
debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
201+
for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
202+
if item_bound
203+
.as_trait_clause()
204+
.is_some_and(|b| b.def_id() == goal.predicate.def_id())
205+
{
206+
return Err(NoSolution);
207+
}
208+
}
191209
}
192210

193211
ecx.probe_and_evaluate_goal_for_constituent_tys(
@@ -1238,10 +1256,11 @@ where
12381256
D: SolverDelegate<Interner = I>,
12391257
I: Interner,
12401258
{
1259+
#[instrument(level = "debug", skip(self, goal), ret)]
12411260
pub(super) fn merge_trait_candidates(
12421261
&mut self,
12431262
goal: Goal<I, TraitPredicate<I>>,
1244-
candidates: Vec<Candidate<I>>,
1263+
mut candidates: Vec<Candidate<I>>,
12451264
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
12461265
if let TypingMode::Coherence = self.typing_mode() {
12471266
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
@@ -1323,13 +1342,16 @@ where
13231342

13241343
// If there are *only* global where bounds, then make sure to return that this
13251344
// is still reported as being proven-via the param-env so that rigid projections
1326-
// operate correctly.
1345+
// operate correctly. Otherwise, drop all global where-bounds before merging the
1346+
// remaining candidates.
13271347
let proven_via =
13281348
if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
13291349
TraitGoalProvenVia::ParamEnv
13301350
} else {
1351+
candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_)));
13311352
TraitGoalProvenVia::Misc
13321353
};
1354+
13331355
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
13341356
if let Some(response) = self.try_merge_responses(&all_candidates) {
13351357
Ok((response, Some(proven_via)))

library/core/src/contracts.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22
33
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
44

5-
/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
6-
/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
7-
/// (including the implicit return of the tail expression, if any).
5+
/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute.
6+
///
7+
/// This is an existing hack to allow users to omit the type of the return value in their ensures
8+
/// attribute.
9+
///
10+
/// Ideally, rustc should be able to generate the type annotation.
11+
/// The existing lowering logic makes it rather hard to add the explicit type annotation,
12+
/// while the function call is fairly straight forward.
813
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
14+
// Similar to `contract_check_requires`, we need to use the user-facing
15+
// `contracts` feature rather than the perma-unstable `contracts_internals`.
16+
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
17+
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
918
#[lang = "contract_build_check_ensures"]
10-
#[track_caller]
11-
pub fn build_check_ensures<Ret, C>(cond: C) -> impl (Fn(Ret) -> Ret) + Copy
19+
pub const fn build_check_ensures<Ret, C>(cond: C) -> C
1220
where
13-
C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static,
21+
C: Fn(&Ret) -> bool + Copy + 'static,
1422
{
15-
#[track_caller]
16-
move |ret| {
17-
crate::intrinsics::contract_check_ensures(&ret, cond);
18-
ret
19-
}
23+
cond
2024
}

library/core/src/intrinsics/mod.rs

+48-6
Original file line numberDiff line numberDiff line change
@@ -3402,20 +3402,62 @@ pub const fn contract_checks() -> bool {
34023402
///
34033403
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
34043404
/// returns false.
3405-
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
3405+
///
3406+
/// Note that this function is a no-op during constant evaluation.
3407+
#[unstable(feature = "contracts_internals", issue = "128044")]
3408+
// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of
3409+
// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking
3410+
// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing
3411+
// `contracts` feature rather than the perma-unstable `contracts_internals`
3412+
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
34063413
#[lang = "contract_check_requires"]
34073414
#[rustc_intrinsic]
3408-
pub fn contract_check_requires<C: Fn() -> bool>(cond: C) {
3409-
if contract_checks() && !cond() {
3410-
// Emit no unwind panic in case this was a safety requirement.
3411-
crate::panicking::panic_nounwind("failed requires check");
3412-
}
3415+
pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
3416+
const_eval_select!(
3417+
@capture[C: Fn() -> bool + Copy] { cond: C } :
3418+
if const {
3419+
// Do nothing
3420+
} else {
3421+
if contract_checks() && !cond() {
3422+
// Emit no unwind panic in case this was a safety requirement.
3423+
crate::panicking::panic_nounwind("failed requires check");
3424+
}
3425+
}
3426+
)
34133427
}
34143428

34153429
/// Check if the post-condition `cond` has been met.
34163430
///
34173431
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
34183432
/// returns false.
3433+
///
3434+
/// Note that this function is a no-op during constant evaluation.
3435+
#[cfg(not(bootstrap))]
3436+
#[unstable(feature = "contracts_internals", issue = "128044")]
3437+
// Similar to `contract_check_requires`, we need to use the user-facing
3438+
// `contracts` feature rather than the perma-unstable `contracts_internals`.
3439+
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
3440+
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
3441+
#[lang = "contract_check_ensures"]
3442+
#[rustc_intrinsic]
3443+
pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, ret: Ret) -> Ret {
3444+
const_eval_select!(
3445+
@capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret :
3446+
if const {
3447+
// Do nothing
3448+
ret
3449+
} else {
3450+
if contract_checks() && !cond(&ret) {
3451+
// Emit no unwind panic in case this was a safety requirement.
3452+
crate::panicking::panic_nounwind("failed ensures check");
3453+
}
3454+
ret
3455+
}
3456+
)
3457+
}
3458+
3459+
/// This is the old version of contract_check_ensures kept here for bootstrap only.
3460+
#[cfg(bootstrap)]
34193461
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
34203462
#[rustc_intrinsic]
34213463
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {

0 commit comments

Comments
 (0)