From 5cb65792ed2db58df74e13c8331c28dc4dddc571 Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Mon, 4 May 2026 10:04:21 +0100 Subject: [PATCH 1/6] move box related tests into its folder --- .../box-array-match-temporary-drop.rs} | 0 .../box-array-match-temporary-drop.stderr} | 0 .../box-deref-in-match-arm-no-invalid-ir.rs} | 0 .../issue-23491.rs => box/box-dst-node-with-empty-slice.rs} | 0 .../box-fixed-array-coerce-unsized-match.rs} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-20055-box-trait.rs => box/box-array-match-temporary-drop.rs} (100%) rename tests/ui/{issues/issue-20055-box-trait.stderr => box/box-array-match-temporary-drop.stderr} (100%) rename tests/ui/{issues/issue-18845.rs => box/box-deref-in-match-arm-no-invalid-ir.rs} (100%) rename tests/ui/{issues/issue-23491.rs => box/box-dst-node-with-empty-slice.rs} (100%) rename tests/ui/{issues/issue-20055-box-unsized-array.rs => box/box-fixed-array-coerce-unsized-match.rs} (100%) diff --git a/tests/ui/issues/issue-20055-box-trait.rs b/tests/ui/box/box-array-match-temporary-drop.rs similarity index 100% rename from tests/ui/issues/issue-20055-box-trait.rs rename to tests/ui/box/box-array-match-temporary-drop.rs diff --git a/tests/ui/issues/issue-20055-box-trait.stderr b/tests/ui/box/box-array-match-temporary-drop.stderr similarity index 100% rename from tests/ui/issues/issue-20055-box-trait.stderr rename to tests/ui/box/box-array-match-temporary-drop.stderr diff --git a/tests/ui/issues/issue-18845.rs b/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs similarity index 100% rename from tests/ui/issues/issue-18845.rs rename to tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs diff --git a/tests/ui/issues/issue-23491.rs b/tests/ui/box/box-dst-node-with-empty-slice.rs similarity index 100% rename from tests/ui/issues/issue-23491.rs rename to tests/ui/box/box-dst-node-with-empty-slice.rs diff --git a/tests/ui/issues/issue-20055-box-unsized-array.rs b/tests/ui/box/box-fixed-array-coerce-unsized-match.rs similarity index 100% rename from tests/ui/issues/issue-20055-box-unsized-array.rs rename to tests/ui/box/box-fixed-array-coerce-unsized-match.rs From 2c2dad1cfeae19186091150f48df10e53d2e0bc8 Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Mon, 4 May 2026 10:23:53 +0100 Subject: [PATCH 2/6] add issue links and bless --- tests/ui/box/box-array-match-temporary-drop.rs | 2 +- tests/ui/box/box-array-match-temporary-drop.stderr | 2 +- tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs | 2 ++ tests/ui/box/box-dst-node-with-empty-slice.rs | 2 ++ tests/ui/box/box-fixed-array-coerce-unsized-match.rs | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/ui/box/box-array-match-temporary-drop.rs b/tests/ui/box/box-array-match-temporary-drop.rs index 43f1f43ba2785..d87c4307760f8 100644 --- a/tests/ui/box/box-array-match-temporary-drop.rs +++ b/tests/ui/box/box-array-match-temporary-drop.rs @@ -1,5 +1,5 @@ //@ run-pass -// See Issues #20055 and #21695. +// See Issues https://github.com/rust-lang/rust/issues/20055 and https://github.com/rust-lang/rust/issues/21695. // We are checking here that the temporaries `Box<[i8, k]>`, for `k` // in 1, 2, 3, 4, that are induced by the match expression are diff --git a/tests/ui/box/box-array-match-temporary-drop.stderr b/tests/ui/box/box-array-match-temporary-drop.stderr index b1cbb2a571733..09caa6741afa7 100644 --- a/tests/ui/box/box-array-match-temporary-drop.stderr +++ b/tests/ui/box/box-array-match-temporary-drop.stderr @@ -1,5 +1,5 @@ warning: method `dummy` is never used - --> $DIR/issue-20055-box-trait.rs:11:8 + --> $DIR/box-array-match-temporary-drop.rs:11:8 | LL | trait Boo { | --- method in this trait diff --git a/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs b/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs index c9dc175b10a8a..8c005a392dca9 100644 --- a/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs +++ b/tests/ui/box/box-deref-in-match-arm-no-invalid-ir.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/18845 + //@ run-pass // This used to generate invalid IR in that even if we took the // `false` branch we'd still try to free the Box from the other diff --git a/tests/ui/box/box-dst-node-with-empty-slice.rs b/tests/ui/box/box-dst-node-with-empty-slice.rs index 0a2dfa4257a03..15ee8d4434b5d 100644 --- a/tests/ui/box/box-dst-node-with-empty-slice.rs +++ b/tests/ui/box/box-dst-node-with-empty-slice.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/23491 + //@ run-pass #![allow(unused_variables)] diff --git a/tests/ui/box/box-fixed-array-coerce-unsized-match.rs b/tests/ui/box/box-fixed-array-coerce-unsized-match.rs index 2663bcfb4f727..4251495347183 100644 --- a/tests/ui/box/box-fixed-array-coerce-unsized-match.rs +++ b/tests/ui/box/box-fixed-array-coerce-unsized-match.rs @@ -1,5 +1,5 @@ //@ run-pass -// Issue #2005: Check that boxed fixed-size arrays are properly +// Issue https://github.com/rust-lang/rust/issues/20055: Check that boxed fixed-size arrays are properly // accounted for (namely, only deallocated if they were actually // created) when they appear as temporaries in unused arms of a match // expression. From 10f9f14377a2fdf65a1f07497c48ce264816a04a Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Mon, 1 Jun 2026 13:47:30 -0300 Subject: [PATCH 3/6] Build a fully-applied trait ref in method-not-found suggestion When a method call fails to resolve, the suggestion machinery probes all traits for a method with the same name and builds a trait reference for the providing trait to detect duplicate trait items coming from multiple crate versions. It passed only the receiver type as the single argument, which is correct only for traits whose sole generic parameter is `Self`. For a trait with further parameters (for example `Borrow`), or when the receiver type is unknown, the argument list no longer matched the trait's generics and tripped the `debug_assert_args_compatible` assertion, producing an ICE. Build the argument list with `GenericArgs::for_item` instead, using the receiver type for `Self` when known and fresh inference variables for the remaining parameters. --- .../rustc_hir_typeck/src/method/suggest.rs | 19 +++++- ...estion-trait-with-extra-generics-no-ice.rs | 24 +++++++ ...on-trait-with-extra-generics-no-ice.stderr | 65 +++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs create mode 100644 tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index c9ec32159f476..48e1f553900b0 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4796,7 +4796,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else { return false; }; - let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter()); + // The trait may have generic parameters beyond `Self` (e.g. `Borrow`), and + // `rcvr_ty` may even be unknown. We only ever know the receiver type (the `Self` arg), + // so fill `Self` from `rcvr_ty` when available and the remaining parameters with fresh + // inference variables; building a `TraitRef` with a partial arg list would otherwise trip + // `debug_assert_args_compatible` and ICE. See #157189. + let trait_ref = ty::TraitRef::new_from_args( + self.tcx, + trait_def_id, + ty::GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { + if param.index == 0 + && let Some(rcvr_ty) = rcvr_ty + { + rcvr_ty.into() + } else { + self.var_for_def(rcvr.span, param) + } + }), + ); let trait_pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive, diff --git a/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs new file mode 100644 index 0000000000000..0a98cdef5c923 --- /dev/null +++ b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.rs @@ -0,0 +1,24 @@ +//! Regression test for #157189. +//! +//! When a method call fails to resolve, the "trait which provides `` is +//! implemented but not in scope" diagnostic probes all traits for a method of the +//! same name. Here `.borrow()` matches `std::borrow::Borrow::borrow`, and `Borrow` +//! has a generic parameter (`Borrowed`) besides `Self`. Building the trait +//! reference for the diagnostic used to pass only the receiver type as the single +//! argument, which mismatched the trait's generics and ICEd in +//! `debug_assert_args_compatible`. It should just report the error. + +trait Foo { + extern "C" fn borrow(&self); +} + +struct Bar; + +fn main() { + let foo: Box usize> = Box::new(Bar); + //~^ ERROR expected a `Fn(bool)` closure, found `Bar` + foo.borrow(); + //~^ ERROR no method named `borrow` found + foo.take() + //~^ ERROR `Box usize>` is not an iterator +} diff --git a/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr new file mode 100644 index 0000000000000..aa46a41fa3378 --- /dev/null +++ b/tests/ui/methods/method-suggestion-trait-with-extra-generics-no-ice.stderr @@ -0,0 +1,65 @@ +error[E0599]: no method named `borrow` found for struct `Box usize>` in the current scope + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:20:9 + | +LL | foo.borrow(); + | ^^^^^^ + | + --> $SRC_DIR/core/src/borrow.rs:LL:COL + | + = note: the method is available for `Box usize>` here + | + = help: items from traits can only be used if the trait is in scope +help: use parentheses to call this trait object + | +LL | foo(/* bool */).borrow(); + | ++++++++++++ +help: trait `Borrow` which provides `borrow` is implemented but not in scope; perhaps you want to import it + | +LL + use std::borrow::Borrow; + | +help: there is a method `borrow_mut` with a similar name + | +LL | foo.borrow_mut(); + | ++++ + +error[E0277]: expected a `Fn(bool)` closure, found `Bar` + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:18:43 + | +LL | let foo: Box usize> = Box::new(Bar); + | ^^^^^^^^^^^^^ expected an `Fn(bool)` closure, found `Bar` + | +help: the trait `Fn(bool)` is not implemented for `Bar` + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:15:1 + | +LL | struct Bar; + | ^^^^^^^^^^ + = note: required for the cast from `Box` to `Box usize>` + +error[E0599]: `Box usize>` is not an iterator + --> $DIR/method-suggestion-trait-with-extra-generics-no-ice.rs:22:9 + | +LL | foo.take() + | ^^^^ + | | + | this is an associated function, not a method + | `Box usize>` is not an iterator + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter + = note: the candidate is defined in an impl for the type `Box` + = note: the following trait bounds were not satisfied: + `dyn Fn(bool) -> usize: Iterator` + which is required by `Box usize>: Iterator` + `Box usize>: Iterator` + which is required by `&mut Box usize>: Iterator` + `dyn Fn(bool) -> usize: Iterator` + which is required by `&mut dyn Fn(bool) -> usize: Iterator` +help: use associated function syntax instead + | +LL - foo.take() +LL + Box:: usize>::take(foo) + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. From f25f4b459c38678d56b1d0624b4856e9a35c891d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 5 Jun 2026 22:41:18 +0800 Subject: [PATCH 4/6] compiletest: inject `#![windows_subsystem = "windows"]` to debuginfo tests on Windows So that we don't get a bunch of console windows spawned by the debugger processes. --- src/tools/compiletest/src/runtest.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 72817ad64521a..79e04b12fbed3 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1645,6 +1645,11 @@ impl<'test> TestCx<'test> { if self.config.mode == TestMode::CodegenUnits { compiler.args(&["-Z", "human_readable_cgu_names"]); } + + if self.config.mode == TestMode::DebugInfo && cfg!(target_os = "windows") { + // Prevent debugger processes from creating new console windows. + compiler.args(&["-Z", r#"crate-attr=windows_subsystem="windows""#]); + } } if self.config.optimize_tests && compiler_kind == CompilerKind::Rustc { From 36742d886762365ad22152d8ddcf311ed58968cf Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Fri, 5 Jun 2026 17:04:12 +0000 Subject: [PATCH 5/6] Convert `QueryRegionConstraint` into a struct --- .../src/type_check/constraint_conversion.rs | 8 ++-- .../src/infer/canonical/query_response.rs | 43 ++++++++++++------- compiler/rustc_middle/src/infer/canonical.rs | 9 ++-- .../src/solve/delegate.rs | 5 ++- .../src/traits/outlives_bounds.rs | 3 +- .../rustc_traits/src/coroutine_witnesses.rs | 3 +- 6 files changed, 45 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index bca2de041b657..4d93fa08fe0bd 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::SubregionOrigin; -use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::canonical::{QueryRegionConstraint, QueryRegionConstraints}; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; @@ -74,9 +74,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let assumptions = elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied()); - for &(constraint, constraint_category, _) in constraints { + for &QueryRegionConstraint { constraint, category, .. } in constraints { constraint.iter_outlives().for_each(|predicate| { - self.convert(predicate, constraint_category, &assumptions); + self.convert(predicate, category, &assumptions); }); } } @@ -296,7 +296,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // FIXME(higher_ranked_auto): What should we do with the assumptions here? if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints { next_outlives_predicates.extend(constraints.iter().flat_map( - |(constraint, category, _)| { + |QueryRegionConstraint { constraint, category, .. }| { constraint.iter_outlives().map(|outlives| (outlives, *category)) }, )); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 98763ff742f25..5641523c304c9 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -13,7 +13,7 @@ use std::iter; use rustc_index::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::bug; -use rustc_middle::infer::canonical::CanonicalVarKind; +use rustc_middle::infer::canonical::{CanonicalVarKind, QueryRegionConstraint}; use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use tracing::{debug, instrument}; @@ -188,7 +188,9 @@ impl<'tcx> InferCtxt<'tcx> { let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; - for (constraint, _category, vis) in &query_response.value.region_constraints.constraints { + for QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in + &query_response.value.region_constraints.constraints + { let constraint = instantiate_value(self.tcx, &result_args, *constraint); match constraint { ty::RegionConstraint::Outlives(predicate) => { @@ -285,11 +287,12 @@ impl<'tcx> InferCtxt<'tcx> { (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => { if v_o != v_r { - output_query_region_constraints.constraints.push(( - ty::RegionEqPredicate(v_o, v_r).into(), - constraint_category, - ty::VisibleForLeakCheck::Yes, - )); + let constraint = QueryRegionConstraint { + constraint: ty::RegionEqPredicate(v_o, v_r).into(), + category: constraint_category, + visible_for_leak_check: ty::VisibleForLeakCheck::Yes, + }; + output_query_region_constraints.constraints.push(constraint); } } @@ -321,7 +324,7 @@ impl<'tcx> InferCtxt<'tcx> { let r_c = instantiate_value(self.tcx, &result_args, r_c); // Screen out `'a: 'a` or `'a == 'a` cases. - if r_c.0.is_trivial() { None } else { Some(r_c) } + if r_c.constraint.is_trivial() { None } else { Some(r_c) } }), ); @@ -616,7 +619,7 @@ pub fn make_query_region_constraints<'tcx>( debug!(?constraints); - let constraints: Vec<_> = constraints + let constraints: Vec> = constraints .iter() .map(|(c, origin)| match c.kind { ConstraintKind::VarSubVar @@ -625,22 +628,30 @@ pub fn make_query_region_constraints<'tcx>( | ConstraintKind::RegSubReg => { // Swap regions because we are going from sub (<=) to outlives (>=). let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub).into(); - (constraint, origin.to_constraint_category(), c.visible_for_leak_check) + QueryRegionConstraint { + constraint, + category: origin.to_constraint_category(), + visible_for_leak_check: c.visible_for_leak_check, + } } ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => { let constraint = ty::RegionEqPredicate(c.sup, c.sub).into(); - (constraint, origin.to_constraint_category(), c.visible_for_leak_check) + QueryRegionConstraint { + constraint, + category: origin.to_constraint_category(), + visible_for_leak_check: c.visible_for_leak_check, + } } }) .chain(outlives_obligations.into_iter().map( |TypeOutlivesConstraint { sub_region, sup_type, origin }| { - ( - ty::OutlivesPredicate(sup_type.into(), sub_region).into(), - origin.to_constraint_category(), + QueryRegionConstraint { + constraint: ty::OutlivesPredicate(sup_type.into(), sub_region).into(), + category: origin.to_constraint_category(), // We don't do leak checks for type outlives - ty::VisibleForLeakCheck::Unreachable, - ) + visible_for_leak_check: ty::VisibleForLeakCheck::Unreachable, + } }, )) .collect(); diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index ee8ab8a2ff931..8f182d096e759 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -135,9 +135,12 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -// FIXME: Convert this into a struct -pub type QueryRegionConstraint<'tcx> = - (ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>, ty::VisibleForLeakCheck); +#[derive(Debug, StableHash, Hash, Eq, PartialEq, TypeVisitable, Clone, TypeFoldable, Copy)] +pub struct QueryRegionConstraint<'tcx> { + pub constraint: ty::RegionConstraint<'tcx>, + pub category: ConstraintCategory<'tcx>, + pub visible_for_leak_check: ty::VisibleForLeakCheck, +} #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index bd22ba6b6bf6d..7c2f5c7f170aa 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -7,6 +7,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues, + QueryRegionConstraint, }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::{FetchEligibleAssocItemResponse, Goal}; @@ -262,7 +263,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let mut seen = FxHashMap::default(); let mut constraints = vec![]; - for (outlives, _, vis) in region_constraints.constraints { + for QueryRegionConstraint { constraint: outlives, visible_for_leak_check: vis, .. } in + region_constraints.constraints + { match seen.entry(outlives) { Entry::Occupied(occupied) => { let idx = occupied.get(); diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 8be26fed0ca42..a171a0de9dd79 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,4 +1,5 @@ use rustc_infer::infer::InferOk; +use rustc_infer::infer::canonical::QueryRegionConstraint; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_macros::extension; @@ -83,7 +84,7 @@ fn implied_outlives_bounds<'a, 'tcx>( // outlives bound required proving some higher-ranked coroutine obl. let QueryRegionConstraints { constraints, assumptions: _ } = constraints; let cause = ObligationCause::misc(span, body_id); - for &(constraint, _, vis) in &constraints { + for &QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in &constraints { match constraint { ty::RegionConstraint::Outlives(predicate) => { infcx.register_outlives_constraint(predicate, vis, &cause) diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 83a77f17b28ce..7fe8303b7459b 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -1,4 +1,5 @@ use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::canonical::QueryRegionConstraint; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::{Obligation, ObligationCause}; @@ -80,7 +81,7 @@ fn compute_assumptions<'tcx>( tcx.mk_outlives_from_iter( constraints .into_iter() - .flat_map(|(constraint, _, _)| constraint.iter_outlives()) + .flat_map(|QueryRegionConstraint { constraint, .. }| constraint.iter_outlives()) // FIXME(higher_ranked_auto): We probably should deeply resolve these before // filtering out infers which only correspond to unconstrained infer regions // which we can sometimes get. From 4e59f4c54b480d98dbe3eb37f12feb4d46be3d55 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 27 May 2026 12:22:03 +0200 Subject: [PATCH 6/6] add `extern "tail"` calling convention --- compiler/rustc_abi/src/canon_abi.rs | 7 +- compiler/rustc_abi/src/extern_abi.rs | 9 ++- compiler/rustc_ast_lowering/src/stability.rs | 3 + .../rustc_ast_passes/src/ast_validation.rs | 1 + .../rustc_codegen_cranelift/src/abi/mod.rs | 7 +- compiler/rustc_codegen_gcc/src/abi.rs | 29 ++++--- compiler/rustc_codegen_gcc/src/context.rs | 8 +- compiler/rustc_codegen_llvm/src/abi.rs | 4 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir_typeck/src/callee.rs | 1 + compiler/rustc_middle/src/ty/layout.rs | 4 +- compiler/rustc_public/src/abi.rs | 1 + compiler/rustc_public/src/ty.rs | 1 + .../src/unstable/convert/internal.rs | 1 + .../src/unstable/convert/stable/abi.rs | 1 + .../src/unstable/convert/stable/ty.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/spec/abi_map.rs | 1 + tests/codegen-llvm/preserve-none.rs | 2 +- tests/codegen-llvm/tailcc.rs | 28 +++++++ tests/ui/abi/rust-preserve-none-cc.rs | 29 ++++--- tests/ui/abi/rust-tail-cc.rs | 80 +++++++++++++++++++ .../feature-gate-rust-tail-cc.rs | 21 +++++ .../feature-gate-rust-tail-cc.stderr | 73 +++++++++++++++++ .../print-calling-conventions.stdout | 1 + 25 files changed, 286 insertions(+), 30 deletions(-) create mode 100644 tests/codegen-llvm/tailcc.rs create mode 100644 tests/ui/abi/rust-tail-cc.rs create mode 100644 tests/ui/feature-gates/feature-gate-rust-tail-cc.rs create mode 100644 tests/ui/feature-gates/feature-gate-rust-tail-cc.stderr diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 316cb05ec1806..6b4963ae92461 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -28,6 +28,7 @@ pub enum CanonAbi { Rust, RustCold, RustPreserveNone, + RustTail, /// An ABI that rustc does not know how to call or define. Custom, @@ -59,7 +60,10 @@ pub enum CanonAbi { impl CanonAbi { pub fn is_rustic_abi(self) -> bool { match self { - CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true, + CanonAbi::Rust + | CanonAbi::RustCold + | CanonAbi::RustPreserveNone + | CanonAbi::RustTail => true, CanonAbi::C | CanonAbi::Custom | CanonAbi::Swift @@ -81,6 +85,7 @@ impl fmt::Display for CanonAbi { CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone, + CanonAbi::RustTail => ExternAbi::RustTail, CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Swift => ExternAbi::Swift, CanonAbi::Arm(arm_call) => match arm_call { diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 3def8a8ccf0ba..f30b923eeed17 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -49,6 +49,11 @@ pub enum ExternAbi { /// forcing callers to save all registers. RustPreserveNone, + /// Ensures that calls in tail position can always be optimized into a jump. + /// + /// This ABI is not stable, and relies on LLVM implementation details. + RustTail, + /// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM. /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, @@ -205,6 +210,7 @@ abi_impls! { System { unwind: true } =><= "system-unwind", SysV64 { unwind: false } =><= "sysv64", SysV64 { unwind: true } =><= "sysv64-unwind", + RustTail =><= "tail", Thiscall { unwind: false } =><= "thiscall", Thiscall { unwind: true } =><= "thiscall-unwind", Unadjusted =><= "unadjusted", @@ -280,7 +286,7 @@ impl ExternAbi { /// - are subject to change between compiler versions pub fn is_rustic_abi(self) -> bool { use ExternAbi::*; - matches!(self, Rust | RustCall | RustCold | RustPreserveNone) + matches!(self, Rust | RustCall | RustCold | RustPreserveNone | RustTail) } /// Returns whether the ABI supports C variadics. This only controls whether we allow *imports* @@ -354,6 +360,7 @@ impl ExternAbi { | Self::SysV64 { .. } | Self::Win64 { .. } | Self::RustPreserveNone + | Self::RustTail | Self::Swift => true, } } diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index 00b6a353d93f6..b58087e4aa3a6 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -100,6 +100,9 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { feature: sym::rust_preserve_none_cc, explain: GateReason::Experimental, }), + ExternAbi::RustTail => { + Err(UnstableAbi { abi, feature: sym::rust_tail_cc, explain: GateReason::Experimental }) + } ExternAbi::RustInvalid => { Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail }) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index afaee6e542082..05f0990bf8512 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -424,6 +424,7 @@ impl<'a> AstValidator<'a> { | CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone + | CanonAbi::RustTail | CanonAbi::Swift | CanonAbi::Arm(_) | CanonAbi::X86(_) => { /* nothing to check */ } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index a8b179f169bf6..9644932ae1055 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -55,8 +55,9 @@ pub(crate) fn conv_to_call_conv( match c { CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::C => default_call_conv, - // Cranelift doesn't currently have anything for this. - CanonAbi::RustPreserveNone => default_call_conv, + CanonAbi::RustPreserveNone | CanonAbi::RustTail => { + sess.dcx().fatal(format!("call conv {c:?} is LLVM-specific")) + } // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling @@ -71,7 +72,7 @@ pub(crate) fn conv_to_call_conv( }, CanonAbi::Interrupt(_) | CanonAbi::Arm(_) | CanonAbi::Swift => { - sess.dcx().fatal("call conv {c:?} is not yet implemented") + sess.dcx().fatal(format!("call conv {c:?} is not yet implemented")) } CanonAbi::GpuKernel => { unreachable!("tried to use {c:?} call conv which only exists on an unsupported target") diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index fb243ff842c83..1b7bb8c907735 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -10,7 +10,7 @@ use rustc_middle::bug; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] -use rustc_session::config; +use rustc_session::{Session, config}; use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode}; #[cfg(feature = "master")] use rustc_target::spec::Arch; @@ -230,32 +230,43 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { #[cfg(feature = "master")] fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option> { - conv_to_fn_attribute(self.conv, &cx.tcx.sess.target.arch) + conv_to_fn_attribute(cx.sess(), self.conv) } } #[cfg(feature = "master")] -pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option> { +pub fn conv_to_fn_attribute<'gcc>(sess: &Session, conv: CanonAbi) -> Option> { let attribute = match conv { CanonAbi::C | CanonAbi::Rust => return None, - // gcc/gccjit does not have anything for this. - CanonAbi::RustPreserveNone => return None, + CanonAbi::RustPreserveNone => { + // This calling convention is LLVM-specific and unspecified. + sess.dcx() + .fatal("gcc/gccjit backend does not support RustPreserveNone calling convention") + } + CanonAbi::RustTail => { + // This calling convention is LLVM-specific and unspecified. + sess.dcx().fatal("gcc/gccjit backend does not support RustTail calling convention") + } CanonAbi::RustCold => FnAttribute::Cold, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. CanonAbi::Custom => return None, - // gcc/gccjit does not have anything for Swift's calling convention. - CanonAbi::Swift => panic!("gcc/gccjit backend does not support Swift calling convention"), + CanonAbi::Swift => { + // gcc/gccjit does not have anything for Swift's calling convention. + sess.dcx().fatal("gcc/gccjit backend does not support Swift calling convention") + } CanonAbi::Arm(arm_call) => match arm_call { ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall, ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry, ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"), }, - CanonAbi::GpuKernel => match arch { + CanonAbi::GpuKernel => match &sess.target.arch { &Arch::AmdGpu => FnAttribute::GcnAmdGpuHsaKernel, &Arch::Nvptx64 => FnAttribute::NvptxKernel, - arch => panic!("Arch {arch} does not support GpuKernel calling convention"), + arch => sess + .dcx() + .fatal(format!("Arch {arch} does not support GpuKernel calling convention")), }, // FIXME(antoyo): check if those AVR attributes are mapped correctly. CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index ed313859aeafa..ea71546ea1c0e 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -486,10 +486,10 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn declare_c_main(&self, fn_type: Self::Type) -> Option { let entry_name = self.sess().target.entry_name.as_ref(); if !self.functions.borrow().contains_key(entry_name) { - #[cfg(feature = "master")] - let conv = conv_to_fn_attribute(self.sess().target.entry_abi, &self.sess().target.arch); - #[cfg(not(feature = "master"))] - let conv = None; + let conv = cfg_select! { + feature = "master" => conv_to_fn_attribute(self.sess(), self.sess().target.entry_abi), + _ => None, + }; Some(self.declare_entry_fn(entry_name, fn_type, conv)) } else { // If the symbol already exists, it is an error: for example, the user wrote diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 3f6010e55928d..4d18818bbe7bd 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -723,6 +723,10 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm: Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone, _ => llvm::CCallConv, }, + CanonAbi::RustTail => match &sess.target.arch { + Arch::X86 | Arch::X86_64 | Arch::AArch64 => llvm::Tail, + _ => sess.dcx().fatal("extern \"tail\" is only supported on x86_64 and aarch64"), + }, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index be98544d89ecd..693326e198721 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -709,6 +709,8 @@ declare_features! ( (unstable, rust_cold_cc, "1.63.0", Some(97544)), /// Allows `extern "rust-preserve-none"`. (unstable, rust_preserve_none_cc, "1.95.0", Some(151401)), + /// Allows `extern "tail"`. + (unstable, rust_tail_cc, "CURRENT_RUSTC_VERSION", Some(157427)), /// Target features on s390x. (unstable, s390x_target_feature, "1.82.0", Some(150259)), /// Allows the use of the `sanitize` attribute. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 7d687099f9715..e70936972e7c7 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -205,6 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone + | CanonAbi::RustTail | CanonAbi::Swift | CanonAbi::Arm(_) | CanonAbi::X86(_) => {} diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 682bec55b4a38..a0dd7b5c5cb5e 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1305,7 +1305,9 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | RustInvalid | Swift | Unadjusted => false, - Rust | RustCall | RustCold | RustPreserveNone => tcx.sess.panic_strategy().unwinds(), + Rust | RustCall | RustCold | RustPreserveNone | RustTail => { + tcx.sess.panic_strategy().unwinds() + } } } diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 1227fe23713cb..cde885def8a41 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -455,6 +455,7 @@ pub enum CallConvention { PreserveMost, PreserveAll, PreserveNone, + Tail, Custom, diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index f71ca7213e9ed..9b9a480ab5f82 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1167,6 +1167,7 @@ pub enum Abi { RiscvInterruptM, RiscvInterruptS, RustPreserveNone, + RustTail, RustInvalid, Custom, Swift, diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index 37f00da9f7103..f18fe84053b32 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -618,6 +618,7 @@ impl RustcInternal for Abi { Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, Abi::RustPreserveNone => rustc_abi::ExternAbi::RustPreserveNone, + Abi::RustTail => rustc_abi::ExternAbi::RustTail, Abi::Custom => rustc_abi::ExternAbi::Custom, Abi::Swift => rustc_abi::ExternAbi::Swift, } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index f42399241cd28..7e0b04f8a7f61 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -125,6 +125,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi { CanonAbi::Rust => CallConvention::Rust, CanonAbi::RustCold => CallConvention::Cold, CanonAbi::RustPreserveNone => CallConvention::PreserveNone, + CanonAbi::RustTail => CallConvention::Tail, CanonAbi::Custom => CallConvention::Custom, CanonAbi::Swift => CallConvention::Swift, CanonAbi::Arm(arm_call) => match arm_call { diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 925d4a5b40b20..8469c500b24c8 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -1046,6 +1046,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::Unadjusted => Abi::Unadjusted, ExternAbi::RustCold => Abi::RustCold, ExternAbi::RustPreserveNone => Abi::RustPreserveNone, + ExternAbi::RustTail => Abi::RustTail, ExternAbi::RustInvalid => Abi::RustInvalid, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fb433aef68cf8..9313e869278db 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1703,6 +1703,7 @@ symbols! { rust_logo, rust_out, rust_preserve_none_cc, + rust_tail_cc, rustc, rustc_abi, // FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index 8c56dcb899718..f7a7ae1eb7555 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -100,6 +100,7 @@ impl AbiMap { (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, (ExternAbi::RustCold, _) => CanonAbi::RustCold, (ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone, + (ExternAbi::RustTail, _) => CanonAbi::RustTail, (ExternAbi::Custom, _) => CanonAbi::Custom, diff --git a/tests/codegen-llvm/preserve-none.rs b/tests/codegen-llvm/preserve-none.rs index b45e49a466bf3..b8c8db25f272c 100644 --- a/tests/codegen-llvm/preserve-none.rs +++ b/tests/codegen-llvm/preserve-none.rs @@ -19,7 +19,7 @@ extern crate minicore; // UNSUPPORTED: define{{( dso_local)?}} void @peach(i16 #[no_mangle] #[inline(never)] -pub extern "rust-preserve-none" fn peach(x: u16) { +pub extern "rust-preserve-none" fn peach(_: u16) { loop {} } diff --git a/tests/codegen-llvm/tailcc.rs b/tests/codegen-llvm/tailcc.rs new file mode 100644 index 0000000000000..15ae69cf0498c --- /dev/null +++ b/tests/codegen-llvm/tailcc.rs @@ -0,0 +1,28 @@ +//@ add-minicore +//@ revisions: I586 X86_64 AARCH64 +//@ [I586] compile-flags: -C no-prepopulate-passes --target=i586-unknown-linux-gnu +//@ [I586] needs-llvm-components: x86 +//@ [X86_64] compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu +//@ [X86_64] needs-llvm-components: x86 +//@ [AARCH64] compile-flags: -C no-prepopulate-passes --target=aarch64-unknown-linux-gnu +//@ [AARCH64] needs-llvm-components: aarch64 + +#![crate_type = "lib"] +#![feature(no_core, rust_tail_cc, explicit_tail_calls)] +#![no_core] + +extern crate minicore; + +// CHECK: define{{( dso_local)?}} tailcc void @peach(i16 +#[no_mangle] +#[inline(never)] +pub extern "tail" fn peach(_: u16) { + loop {} +} + +// CHECK: call tailcc void @peach(i16 +pub fn quince(x: u16) { + if let 12345u16 = x { + peach(54321); + } +} diff --git a/tests/ui/abi/rust-preserve-none-cc.rs b/tests/ui/abi/rust-preserve-none-cc.rs index deacb926971c8..20895e1583f4e 100644 --- a/tests/ui/abi/rust-preserve-none-cc.rs +++ b/tests/ui/abi/rust-preserve-none-cc.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc #![feature(rust_preserve_none_cc)] @@ -17,9 +18,7 @@ extern "rust-preserve-none" fn oven_explosion() { #[inline(never)] fn bite_into(yummy: u64) -> u64 { - let did_it_actually = std::panic::catch_unwind(move || { - oven_explosion() - }); + let did_it_actually = std::panic::catch_unwind(move || oven_explosion()); assert!(did_it_actually.is_err()); yummy - 25 } @@ -52,16 +51,26 @@ extern "rust-preserve-none" fn lotsa_apples( and_a.rome.iter().sum(), fuji + ambrosia, cosmic_crisp - honeycrisp, - bite_into(and_a.golden_delicious) + bite_into(and_a.golden_delicious), ) } fn main() { - let pie = lotsa_apples(220, 140, 210.54201234, &[180, 210], (), CrateOf { - mcintosh: 150.0, - golden_delicious: 185, - jonagold: None, - rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202] - }, 270, 193.1, &[]); + let pie = lotsa_apples( + 220, + 140, + 210.54201234, + &[180, 210], + (), + CrateOf { + mcintosh: 150.0, + golden_delicious: 185, + jonagold: None, + rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202], + }, + 270, + 193.1, + &[], + ); assert_eq!(pie, (2292, 403.64201234, 50, 160)); } diff --git a/tests/ui/abi/rust-tail-cc.rs b/tests/ui/abi/rust-tail-cc.rs new file mode 100644 index 0000000000000..aba5d0d695647 --- /dev/null +++ b/tests/ui/abi/rust-tail-cc.rs @@ -0,0 +1,80 @@ +//@ revisions: aarch64 x32 x64 +//@ run-pass +//@[aarch64] only-aarch64 +//@[x32] only-x86 +//@[x64] only-x86_64 +//@ needs-unwind +//@ ignore-backends: gcc + +#![feature(rust_tail_cc)] + +struct CrateOf<'a> { + mcintosh: f64, + golden_delicious: u64, + jonagold: Option<&'a u64>, + rome: [u64; 12], +} + +#[inline(never)] +extern "tail" fn oven_explosion() { + panic!("bad time"); +} + +#[inline(never)] +fn bite_into(yummy: u64) -> u64 { + let did_it_actually = std::panic::catch_unwind(move || oven_explosion()); + assert!(did_it_actually.is_err()); + yummy - 25 +} + +#[inline(never)] +extern "tail" fn lotsa_apples( + honeycrisp: u64, + gala: u32, + fuji: f64, + granny_smith: &[u64], + pink_lady: (), + and_a: CrateOf<'static>, + cosmic_crisp: u64, + ambrosia: f64, + winesap: &[u64], +) -> (u64, f64, u64, u64) { + assert_eq!(honeycrisp, 220); + assert_eq!(gala, 140); + assert_eq!(fuji, 210.54201234); + assert_eq!(granny_smith, &[180, 210]); + assert_eq!(pink_lady, ()); + assert_eq!(and_a.mcintosh, 150.0); + assert_eq!(and_a.golden_delicious, 185); + assert_eq!(and_a.jonagold, None); // my scales can't weight these gargantuans. + assert_eq!(and_a.rome, [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202]); + assert_eq!(cosmic_crisp, 270); + assert_eq!(ambrosia, 193.1); + assert_eq!(winesap, &[]); + ( + and_a.rome.iter().sum(), + fuji + ambrosia, + cosmic_crisp - honeycrisp, + bite_into(and_a.golden_delicious), + ) +} + +fn main() { + let pie = lotsa_apples( + 220, + 140, + 210.54201234, + &[180, 210], + (), + CrateOf { + mcintosh: 150.0, + golden_delicious: 185, + jonagold: None, + rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202], + }, + 270, + 193.1, + &[], + ); + assert_eq!(pie, (2292, 403.64201234, 50, 160)); +} diff --git a/tests/ui/feature-gates/feature-gate-rust-tail-cc.rs b/tests/ui/feature-gates/feature-gate-rust-tail-cc.rs new file mode 100644 index 0000000000000..b2bbf606cc7a8 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rust-tail-cc.rs @@ -0,0 +1,21 @@ +#![crate_type = "lib"] + +extern "tail" fn apple() {} //~ ERROR "tail" ABI is experimental + +trait T { + extern "tail" fn banana(); //~ ERROR "tail" ABI is experimental + extern "tail" fn citrus() {} //~ ERROR "tail" ABI is experimental +} + +struct S; +impl T for S { + extern "tail" fn banana() {} //~ ERROR "tail" ABI is experimental +} + +impl S { + extern "tail" fn durian() {} //~ ERROR "tail" ABI is experimental +} + +type Fig = extern "tail" fn(); //~ ERROR "tail" ABI is experimental + +extern "tail" {} //~ ERROR "tail" ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-rust-tail-cc.stderr b/tests/ui/feature-gates/feature-gate-rust-tail-cc.stderr new file mode 100644 index 0000000000000..e588569e6bd79 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rust-tail-cc.stderr @@ -0,0 +1,73 @@ +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:3:8 + | +LL | extern "tail" fn apple() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:6:12 + | +LL | extern "tail" fn banana(); + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:7:12 + | +LL | extern "tail" fn citrus() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:12:12 + | +LL | extern "tail" fn banana() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:16:12 + | +LL | extern "tail" fn durian() {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:19:19 + | +LL | type Fig = extern "tail" fn(); + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "tail" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-tail-cc.rs:21:8 + | +LL | extern "tail" {} + | ^^^^^^ + | + = note: see issue #157427 for more information + = help: add `#![feature(rust_tail_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/print-request/print-calling-conventions.stdout b/tests/ui/print-request/print-calling-conventions.stdout index 506bbea23e171..af4f491fc069e 100644 --- a/tests/ui/print-request/print-calling-conventions.stdout +++ b/tests/ui/print-request/print-calling-conventions.stdout @@ -29,6 +29,7 @@ system system-unwind sysv64 sysv64-unwind +tail thiscall thiscall-unwind unadjusted