Skip to content

Commit 7eef946

Browse files
committed
Auto merge of rust-lang#99943 - compiler-errors:tuple-trait, r=jackh726
Implement `std::marker::Tuple`, use it in `extern "rust-call"` and `Fn`-family traits Implements rust-lang/compiler-team#537 I made a few opinionated decisions in this implementation, specifically: 1. Enforcing `extern "rust-call"` on fn items during wfcheck, 2. Enforcing this for all functions (not just ones that have bodies), 3. Gating this `Tuple` marker trait behind its own feature, instead of grouping it into (e.g.) `unboxed_closures`. Still needing to be done: 1. Enforce that `extern "rust-call"` `fn`-ptrs are well-formed only if they have 1/2 args and the second one implements `Tuple`. (Doing this would fix ICE in rust-lang#66696.) 2. Deny all explicit/user `impl`s of the `Tuple` trait, kinda like `Sized`. 3. Fixing `Tuple` trait built-in impl for chalk, so that chalkification tests are un-broken. Open questions: 1. Does this need t-lang or t-libs signoff? Fixes rust-lang#99820
2 parents 1e1e5b8 + ff8f84c commit 7eef946

File tree

53 files changed

+841
-242
lines changed

Some content is hidden

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

53 files changed

+841
-242
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+28
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_middle::ty::{GenericArgKind, InternalSubsts};
2121
use rustc_session::parse::feature_err;
2222
use rustc_span::symbol::{sym, Ident, Symbol};
2323
use rustc_span::{Span, DUMMY_SP};
24+
use rustc_target::spec::abi::Abi;
2425
use rustc_trait_selection::autoderef::Autoderef;
2526
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
2627
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
@@ -1542,6 +1543,33 @@ fn check_fn_or_method<'tcx>(
15421543
sig.output(),
15431544
hir_decl.output.span(),
15441545
);
1546+
1547+
if sig.abi == Abi::RustCall {
1548+
let span = tcx.def_span(def_id);
1549+
let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
1550+
let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 });
1551+
// Check that the argument is a tuple
1552+
if let Some(ty) = inputs.next() {
1553+
wfcx.register_bound(
1554+
ObligationCause::new(span, wfcx.body_id, ObligationCauseCode::RustCall),
1555+
wfcx.param_env,
1556+
*ty,
1557+
tcx.require_lang_item(hir::LangItem::Tuple, Some(span)),
1558+
);
1559+
} else {
1560+
tcx.sess.span_err(
1561+
hir_decl.inputs.last().map_or(span, |input| input.span),
1562+
"functions with the \"rust-call\" ABI must take a single non-self tuple argument",
1563+
);
1564+
}
1565+
// No more inputs other than the `self` type and the tuple type
1566+
if inputs.next().is_some() {
1567+
tcx.sess.span_err(
1568+
hir_decl.inputs.last().map_or(span, |input| input.span),
1569+
"functions with the \"rust-call\" ABI must take a single non-self tuple argument",
1570+
);
1571+
}
1572+
}
15451573
}
15461574

15471575
/// Basically `check_associated_type_bounds`, but separated for now and should be

compiler/rustc_hir_typeck/src/callee.rs

+16
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
468468
def_id,
469469
);
470470

471+
if fn_sig.abi == abi::Abi::RustCall {
472+
let sp = arg_exprs.last().map_or(call_expr.span, |expr| expr.span);
473+
if let Some(ty) = fn_sig.inputs().last().copied() {
474+
self.register_bound(
475+
ty,
476+
self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
477+
traits::ObligationCause::new(sp, self.body_id, traits::RustCall),
478+
);
479+
} else {
480+
self.tcx.sess.span_err(
481+
sp,
482+
"functions with the \"rust-call\" ABI must take a single non-self tuple argument",
483+
);
484+
}
485+
}
486+
471487
fn_sig.output()
472488
}
473489

compiler/rustc_hir_typeck/src/check.rs

-37
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ use rustc_hir as hir;
66
use rustc_hir::def::DefKind;
77
use rustc_hir::intravisit::Visitor;
88
use rustc_hir::lang_items::LangItem;
9-
use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
109
use rustc_hir_analysis::check::fn_maybe_err;
1110
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1211
use rustc_infer::infer::RegionVariableOrigin;
1312
use rustc_middle::ty::{self, Ty, TyCtxt};
1413
use rustc_span::def_id::LocalDefId;
15-
use rustc_target::spec::abi::Abi;
1614
use rustc_trait_selection::traits;
1715
use std::cell::RefCell;
1816

@@ -56,41 +54,6 @@ pub(super) fn check_fn<'a, 'tcx>(
5654

5755
fn_maybe_err(tcx, span, fn_sig.abi);
5856

59-
if fn_sig.abi == Abi::RustCall {
60-
let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
61-
62-
let err = || {
63-
let item = match tcx.hir().get(fn_id) {
64-
Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
65-
Node::ImplItem(hir::ImplItem {
66-
kind: hir::ImplItemKind::Fn(header, ..), ..
67-
}) => Some(header),
68-
Node::TraitItem(hir::TraitItem {
69-
kind: hir::TraitItemKind::Fn(header, ..),
70-
..
71-
}) => Some(header),
72-
// Closures are RustCall, but they tuple their arguments, so shouldn't be checked
73-
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
74-
node => bug!("Item being checked wasn't a function/closure: {:?}", node),
75-
};
76-
77-
if let Some(header) = item {
78-
tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
79-
}
80-
};
81-
82-
if fn_sig.inputs().len() != expected_args {
83-
err()
84-
} else {
85-
// FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
86-
// This will probably require wide-scale changes to support a TupleKind obligation
87-
// We can't resolve this without knowing the type of the param
88-
if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
89-
err()
90-
}
91-
}
92-
}
93-
9457
if body.generator_kind.is_some() && can_be_generator.is_some() {
9558
let yield_ty = fcx
9659
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
136136
tuple_arguments,
137137
Some(method.def_id),
138138
);
139+
139140
method.sig.output()
140141
}
141142

@@ -214,7 +215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
214215
"cannot use call notation; the first type parameter \
215216
for the function trait is neither a tuple nor unit"
216217
)
217-
.emit();
218+
.delay_as_bug();
218219
(self.err_args(provided_args.len()), None)
219220
}
220221
}

compiler/rustc_hir_typeck/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'
458458
/// # fn f(x: (isize, isize)) {}
459459
/// f((1, 2));
460460
/// ```
461-
#[derive(Clone, Eq, PartialEq)]
461+
#[derive(Copy, Clone, Eq, PartialEq)]
462462
enum TupleArgumentsFlag {
463463
DontTupleArguments,
464464
TupleArguments,

compiler/rustc_middle/src/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ pub enum ObligationCauseCode<'tcx> {
438438
},
439439

440440
AscribeUserTypeProvePredicate(Span),
441+
442+
RustCall,
441443
}
442444

443445
/// The 'location' at which we try to perform HIR-based wf checking.

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+21-6
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
700700
}
701701
}
702702

703+
if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
704+
match obligation.cause.code().peel_derives() {
705+
ObligationCauseCode::RustCall => {
706+
err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
707+
}
708+
ObligationCauseCode::BindingObligation(def_id, _)
709+
| ObligationCauseCode::ItemObligation(def_id)
710+
if ty::ClosureKind::from_def_id(tcx, *def_id).is_some() =>
711+
{
712+
err.code(rustc_errors::error_code!(E0059));
713+
err.set_primary_message(format!(
714+
"type parameter to bare `{}` trait must be a tuple",
715+
tcx.def_path_str(*def_id)
716+
));
717+
}
718+
_ => {}
719+
}
720+
}
721+
703722
if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
704723
&& predicate_is_const
705724
{
@@ -848,12 +867,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
848867
);
849868
}
850869

851-
let is_fn_trait = [
852-
self.tcx.lang_items().fn_trait(),
853-
self.tcx.lang_items().fn_mut_trait(),
854-
self.tcx.lang_items().fn_once_trait(),
855-
]
856-
.contains(&Some(trait_ref.def_id()));
870+
let is_fn_trait =
871+
ty::ClosureKind::from_def_id(tcx, trait_ref.def_id()).is_some();
857872
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
858873
*trait_ref.skip_binder().self_ty().kind()
859874
{

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2407,7 +2407,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
24072407
| ObligationCauseCode::CheckAssociatedTypeBounds { .. }
24082408
| ObligationCauseCode::LetElse
24092409
| ObligationCauseCode::BinOp { .. }
2410-
| ObligationCauseCode::AscribeUserTypeProvePredicate(..) => {}
2410+
| ObligationCauseCode::AscribeUserTypeProvePredicate(..)
2411+
| ObligationCauseCode::RustCall => {}
24112412
ObligationCauseCode::SliceOrArrayElem => {
24122413
err.note("slice and array elements must have `Sized` type");
24132414
}

library/alloc/src/boxed.rs

+31
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ use core::hash::{Hash, Hasher};
158158
#[cfg(not(no_global_oom_handling))]
159159
use core::iter::FromIterator;
160160
use core::iter::{FusedIterator, Iterator};
161+
#[cfg(not(bootstrap))]
162+
use core::marker::Tuple;
161163
use core::marker::{Destruct, Unpin, Unsize};
162164
use core::mem;
163165
use core::ops::{
@@ -1979,6 +1981,7 @@ impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A
19791981
#[stable(feature = "fused", since = "1.26.0")]
19801982
impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
19811983

1984+
#[cfg(bootstrap)]
19821985
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
19831986
impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
19841987
type Output = <F as FnOnce<Args>>::Output;
@@ -1988,20 +1991,48 @@ impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
19881991
}
19891992
}
19901993

1994+
#[cfg(not(bootstrap))]
1995+
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
1996+
impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
1997+
type Output = <F as FnOnce<Args>>::Output;
1998+
1999+
extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
2000+
<F as FnOnce<Args>>::call_once(*self, args)
2001+
}
2002+
}
2003+
2004+
#[cfg(bootstrap)]
19912005
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
19922006
impl<Args, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
19932007
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
19942008
<F as FnMut<Args>>::call_mut(self, args)
19952009
}
19962010
}
19972011

2012+
#[cfg(not(bootstrap))]
2013+
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
2014+
impl<Args: Tuple, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
2015+
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
2016+
<F as FnMut<Args>>::call_mut(self, args)
2017+
}
2018+
}
2019+
2020+
#[cfg(bootstrap)]
19982021
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
19992022
impl<Args, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
20002023
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
20012024
<F as Fn<Args>>::call(self, args)
20022025
}
20032026
}
20042027

2028+
#[cfg(not(bootstrap))]
2029+
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
2030+
impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
2031+
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
2032+
<F as Fn<Args>>::call(self, args)
2033+
}
2034+
}
2035+
20052036
#[unstable(feature = "coerce_unsized", issue = "27732")]
20062037
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
20072038

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@
150150
#![feature(trusted_len)]
151151
#![feature(trusted_random_access)]
152152
#![feature(try_trait_v2)]
153+
#![cfg_attr(not(bootstrap), feature(tuple_trait))]
153154
#![feature(unchecked_math)]
154155
#![feature(unicode_internals)]
155156
#![feature(unsize)]

library/core/src/const_closure.rs

+30
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::marker::Destruct;
2+
#[cfg(not(bootstrap))]
3+
use crate::marker::Tuple;
24

35
/// Struct representing a closure with mutably borrowed data.
46
///
@@ -44,6 +46,7 @@ impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData,
4446

4547
macro_rules! impl_fn_mut_tuple {
4648
($($var:ident)*) => {
49+
#[cfg(bootstrap)]
4750
#[allow(unused_parens)]
4851
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
4952
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
@@ -56,6 +59,7 @@ macro_rules! impl_fn_mut_tuple {
5659
self.call_mut(args)
5760
}
5861
}
62+
#[cfg(bootstrap)]
5963
#[allow(unused_parens)]
6064
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
6165
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
@@ -68,6 +72,32 @@ macro_rules! impl_fn_mut_tuple {
6872
(self.func)(($($var),*), args)
6973
}
7074
}
75+
#[cfg(not(bootstrap))]
76+
#[allow(unused_parens)]
77+
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
78+
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
79+
where
80+
Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue+ ~const Destruct,
81+
{
82+
type Output = ClosureReturnValue;
83+
84+
extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
85+
self.call_mut(args)
86+
}
87+
}
88+
#[cfg(not(bootstrap))]
89+
#[allow(unused_parens)]
90+
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
91+
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
92+
where
93+
Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
94+
{
95+
extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
96+
#[allow(non_snake_case)]
97+
let ($($var),*) = &mut self.data;
98+
(self.func)(($($var),*), args)
99+
}
100+
}
71101
};
72102
}
73103
impl_fn_mut_tuple!(A);

0 commit comments

Comments
 (0)