authorbors <bors@rust-lang.org> 2026-06-27 01:14:21 UTC
committerbors <bors@rust-lang.org> 2026-06-27 01:14:21 UTC
log16761606d606b6ec4d0c88fc9251670742ad9fd2
tree3c0a01736c840678fcbddb7d07bd4da8a023afdc
parentce9954c0cfc4bf26b82aef16e6fd8b020c237992
parent2ea8268f763c4c540786d16a1db8301a091d34e9

Auto merge of #158455 - JonathanBrouwer:rollup-3fPbHms, r=JonathanBrouwer

Rollup of 15 pull requests Successful merges: - rust-lang/rust#153697 (Add arg splat experiment initial tuple impl) - rust-lang/rust#158360 (Various borrowck cleanups and param_env/opaque_types_defined_by query simplifications for typeck children) - rust-lang/rust#158438 (Use rigidness marker in fast_reject) - rust-lang/rust#157127 (cg_LLVM: Stop needing an alloca for volatile loads) - rust-lang/rust#158376 (Suggest `>=` for `=>` typo in closure and call argument positions) - rust-lang/rust#158185 (perf: Make stable_crate_ids reads lock-free after crate loading) - rust-lang/rust#158244 (Attribute docs `deprecated` , `warn`, `allow`, `cfg`, `deny`, and `forbid` ) - rust-lang/rust#158355 (Fixup the refactoring errors in rust-lang/rust#156246) - rust-lang/rust#158361 (Move `check_ffi_pure` into the attribute parser) - rust-lang/rust#158382 (Add safety section for SliceIndex::get_unchecked(mut)) - rust-lang/rust#158399 (std: truncate thread names on NetBSD) - rust-lang/rust#158418 (Eliminate double length check in `Vec::into_array`) - rust-lang/rust#158430 (Guard clone suggestion against empty obligation errors) - rust-lang/rust#158446 (Update Enzyme submodule) - rust-lang/rust#158448 (Cleanup `NumBuffer` comment and replace `ilog(10)` with `ilog10()`)

144 files changed, 3543 insertions(+), 457 deletions(-)

compiler/rustc_ast/src/ast.rs+6-4
......@@ -3059,13 +3059,15 @@ impl FnDecl {
30593059 }
30603060
30613061 /// The marker index for "no splatted arguments".
3062 /// Higher values are also not supported, for performance reasons.
3063 ///
30623064 /// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `FnDeclFlags::NO_SPLATTED_ARG_INDEX`.
3063 pub const NO_SPLATTED_ARG_INDEX: u16 = u16::MAX;
3065 pub const NO_SPLATTED_ARG_INDEX: u8 = u8::MAX;
30643066
30653067 /// Returns a splatted argument index, if any are present.
3066 pub fn splatted(&self) -> Option<u16> {
3068 pub fn splatted(&self) -> Option<u8> {
30673069 self.inputs.iter().enumerate().find_map(|(index, arg)| {
3068 if index == Self::NO_SPLATTED_ARG_INDEX as usize {
3070 if index >= usize::from(Self::NO_SPLATTED_ARG_INDEX) {
30693071 // AST validation has already checked the splatted argument index is valid, so just
30703072 // ignore invalid indexes here.
30713073 None
......@@ -3073,7 +3075,7 @@ impl FnDecl {
30733075 arg.attrs
30743076 .iter()
30753077 .any(|attr| attr.has_name(sym::splat))
3076 .then_some(u16::try_from(index).unwrap())
3078 .then_some(u8::try_from(index).unwrap())
30773079 }
30783080 })
30793081 }
compiler/rustc_ast_lowering/src/delegation.rs+2-3
......@@ -93,7 +93,7 @@ struct ParamInfo {
9393 pub c_variadic: bool,
9494
9595 /// The index of the splatted parameter, if any.
96 pub splatted: Option<u16>,
96 pub splatted: Option<u8>,
9797}
9898
9999const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
......@@ -364,11 +364,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
364364 fn param_info(&self, def_id: DefId) -> ParamInfo {
365365 let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
366366
367 // FIXME(splat): use `sig.splatted()` once FnSig has it
368367 ParamInfo {
369368 param_count: sig.inputs().len() + usize::from(sig.c_variadic()),
370369 c_variadic: sig.c_variadic(),
371 splatted: None,
370 splatted: sig.splatted(),
372371 }
373372 }
374373
compiler/rustc_ast_passes/src/ast_validation.rs+3-3
......@@ -412,11 +412,11 @@ impl<'a> AstValidator<'a> {
412412 })
413413 .unzip();
414414
415 // A splatted argument at the "no splatted" marker index is not supported (this is an
416 // unlikely edge case).
415 // A splatted argument greater than or equal to the "no splatted" marker index is not
416 // supported.
417417 if let (Some(&splatted_arg_index), Some(&splatted_span)) =
418418 (splatted_arg_indexes.last(), splatted_spans.last())
419 && splatted_arg_index == FnDecl::NO_SPLATTED_ARG_INDEX
419 && splatted_arg_index >= u16::from(FnDecl::NO_SPLATTED_ARG_INDEX)
420420 {
421421 self.dcx().emit_err(diagnostics::InvalidSplattedArg {
422422 splatted_arg_index,
compiler/rustc_attr_parsing/src/attributes/link_attrs.rs+12-5
......@@ -14,11 +14,11 @@ use super::util::parse_single_integer;
1414use crate::attributes::AttributeSafety;
1515use crate::attributes::cfg::parse_cfg_entry;
1616use crate::session_diagnostics::{
17 AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
18 ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
19 InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
20 LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection, RawDylibOnlyWindows,
21 WholeArchiveNeedsStatic,
17 AsNeededCompatibility, BothFfiConstAndPure, BundleNeedsStatic, EmptyLinkName,
18 ExportSymbolsNeedsStatic, ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink,
19 InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple,
20 LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection,
21 RawDylibOnlyWindows, WholeArchiveNeedsStatic,
2222};
2323
2424pub(crate) struct LinkNameParser;
......@@ -575,6 +575,13 @@ impl NoArgsAttributeParser for FfiPureParser {
575575 AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
576576 const STABILITY: AttributeStability = unstable!(ffi_pure);
577577 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
578
579 fn finalize_check(attr_span: Span, cx: &FinalizeContext<'_, '_>) {
580 // `#[ffi_const]` functions cannot be `#[ffi_pure]`.
581 if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) {
582 cx.emit_err(BothFfiConstAndPure { attr_span });
583 }
584 }
578585}
579586
580587pub(crate) struct RustcStdInternalSymbolParser;
compiler/rustc_attr_parsing/src/attributes/mod.rs+24-2
......@@ -147,6 +147,14 @@ pub(crate) trait SingleAttributeParser: 'static {
147147
148148 /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
149149 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind>;
150
151 /// Optional cross-attribute validation, run once during finalization after all
152 /// attributes on the item have been parsed. Unlike [`convert`](Self::convert), this
153 /// has access to the sibling attributes via [`FinalizeContext::all_attrs`], so it can
154 /// reject incompatible combinations. `attr_span` is the span of this attribute.
155 ///
156 /// Defaults to a no-op.
157 fn finalize_check(_attr_span: Span, _cx: &FinalizeContext<'_, '_>) {}
150158}
151159
152160/// Use in combination with [`SingleAttributeParser`].
......@@ -177,8 +185,10 @@ impl<T: SingleAttributeParser> AttributeParser for Single<T> {
177185 const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS;
178186 const SAFETY: AttributeSafety = T::SAFETY;
179187
180 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
181 Some(self.1?.0)
188 fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
189 let (kind, span) = self.1?;
190 T::finalize_check(span, cx);
191 Some(kind)
182192 }
183193}
184194
......@@ -258,6 +268,14 @@ pub(crate) trait NoArgsAttributeParser: 'static {
258268
259269 /// Create the [`AttributeKind`] given attribute's [`Span`].
260270 const CREATE: fn(Span) -> AttributeKind;
271
272 /// Optional cross-attribute validation, run once during finalization after all
273 /// attributes on the item have been parsed. Has access to the sibling attributes via
274 /// [`FinalizeContext::all_attrs`], so it can reject incompatible combinations.
275 /// `attr_span` is the span of this attribute.
276 ///
277 /// Defaults to a no-op.
278 fn finalize_check(_attr_span: Span, _cx: &FinalizeContext<'_, '_>) {}
261279}
262280
263281pub(crate) struct WithoutArgs<T: NoArgsAttributeParser>(PhantomData<T>);
......@@ -280,6 +298,10 @@ impl<T: NoArgsAttributeParser> SingleAttributeParser for WithoutArgs<T> {
280298 let _ = cx.expect_no_args(args);
281299 Some(T::CREATE(cx.attr_span))
282300 }
301
302 fn finalize_check(attr_span: Span, cx: &FinalizeContext<'_, '_>) {
303 T::finalize_check(attr_span, cx)
304 }
283305}
284306
285307type ConvertFn<E> = fn(ThinVec<E>, Span) -> AttributeKind;
compiler/rustc_attr_parsing/src/session_diagnostics.rs+7
......@@ -13,6 +13,13 @@ use rustc_target::spec::TargetTuple;
1313use crate::AttributeTemplate;
1414use crate::context::Suggestion;
1515
16#[derive(Diagnostic)]
17#[diag("`#[ffi_const]` function cannot be `#[ffi_pure]`", code = E0757)]
18pub(crate) struct BothFfiConstAndPure {
19 #[primary_span]
20 pub attr_span: Span,
21}
22
1623#[derive(Diagnostic)]
1724#[diag("{$attr_str} attribute cannot have empty value")]
1825pub(crate) struct DocAliasEmpty<'a> {
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs+13-9
......@@ -1461,15 +1461,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
14611461 let cause = ObligationCause::misc(expr.span, self.mir_def_id());
14621462 ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait);
14631463 let errors = ocx.evaluate_obligations_error_on_ambiguity();
1464 if errors.iter().all(|error| {
1465 match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) {
1466 Some(clause) => match clause.self_ty().skip_binder().kind() {
1467 ty::Adt(def, _) => def.did().is_local() && clause.def_id() == clone_trait,
1468 _ => false,
1469 },
1470 None => false,
1471 }
1472 }) {
1464 if !errors.is_empty()
1465 && errors.iter().all(|error| {
1466 match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) {
1467 Some(clause) => match clause.self_ty().skip_binder().kind() {
1468 ty::Adt(def, _) => {
1469 def.did().is_local() && clause.def_id() == clone_trait
1470 }
1471 _ => false,
1472 },
1473 None => false,
1474 }
1475 })
1476 {
14731477 let mut type_spans = vec![];
14741478 let mut types = FxIndexSet::default();
14751479 for clause in errors
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs+1-1
......@@ -706,7 +706,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
706706 Some(Cause::LiveVar(..) | Cause::DropVar(..)) | None => {
707707 // Here, under NLL: no cause was found. Under polonius: no cause was found, or a
708708 // boring local was found, which we ignore like NLLs do to match its diagnostics.
709 if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
709 if let Some(region) = self.regioncx.to_error_region_vid(borrow_region_vid) {
710710 let (category, from_closure, span, region_name, path) =
711711 self.free_region_constraint_info(borrow_region_vid, region);
712712 if let Some(region_name) = region_name {
compiler/rustc_borrowck/src/diagnostics/mod.rs+32-29
......@@ -116,11 +116,42 @@ impl<'infcx, 'tcx> BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
116116 pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
117117 self.buffered_diags.push(BufferedDiag::NonError(diag));
118118 }
119 pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
120 self.buffered_diags.push(BufferedDiag::Error(diag));
121 }
122
123 pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
124 let mut res = None;
125
126 // Buffer any move errors that we collected and de-duplicated.
127 for (_, (_, diag)) in std::mem::take(&mut self.buffered_move_errors) {
128 // We have already set tainted for this error, so just buffer it.
129 self.buffer_error(diag);
130 }
131 for (_, (mut diag, count)) in std::mem::take(&mut self.buffered_mut_errors) {
132 if count > 10 {
133 diag.note(format!("...and {} other attempted mutable borrows", count - 10));
134 }
135 self.buffer_error(diag);
136 }
137
138 if !self.buffered_diags.is_empty() {
139 self.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
140 for buffered_diag in self.buffered_diags.drain(..) {
141 match buffered_diag {
142 BufferedDiag::Error(diag) => res = Some(diag.emit()),
143 BufferedDiag::NonError(diag) => diag.emit(),
144 }
145 }
146 }
147
148 res
149 }
119150}
120151
121152impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
122153 pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
123 self.diags_buffer.buffered_diags.push(BufferedDiag::Error(diag));
154 self.diags_buffer.buffer_error(diag);
124155 }
125156
126157 pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
......@@ -152,34 +183,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
152183 self.diags_buffer.buffered_mut_errors.insert(span, (diag, count));
153184 }
154185
155 pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
156 let mut res = self.infcx.tainted_by_errors();
157
158 // Buffer any move errors that we collected and de-duplicated.
159 for (_, (_, diag)) in std::mem::take(&mut self.diags_buffer.buffered_move_errors) {
160 // We have already set tainted for this error, so just buffer it.
161 self.buffer_error(diag);
162 }
163 for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
164 if count > 10 {
165 diag.note(format!("...and {} other attempted mutable borrows", count - 10));
166 }
167 self.buffer_error(diag);
168 }
169
170 if !self.diags_buffer.buffered_diags.is_empty() {
171 self.diags_buffer.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
172 for buffered_diag in self.diags_buffer.buffered_diags.drain(..) {
173 match buffered_diag {
174 BufferedDiag::Error(diag) => res = Some(diag.emit()),
175 BufferedDiag::NonError(diag) => diag.emit(),
176 }
177 }
178 }
179
180 res
181 }
182
183186 pub(crate) fn has_buffered_diags(&self) -> bool {
184187 self.diags_buffer.buffered_diags.is_empty()
185188 }
compiler/rustc_borrowck/src/diagnostics/opaque_types.rs+2-6
......@@ -28,11 +28,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
2828 }
2929
3030 let infcx = self.infcx;
31 let mut guar = None;
3231 let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
3332 None;
3433 for error in errors {
35 guar = Some(match error {
34 match error {
3635 DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(infcx),
3736 DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => {
3837 infcx.dcx().emit_err(err)
......@@ -82,11 +81,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
8281 )
8382 ),
8483 ),
85 });
84 };
8685 }
87 let guar = guar.unwrap();
88 self.root_cx.set_tainted_by_errors(guar);
89 self.infcx.set_tainted_by_errors(guar);
9086 }
9187
9288 /// Try to note when an opaque is involved in a borrowck error and that
compiler/rustc_borrowck/src/diagnostics/region_errors.rs+26-14
......@@ -28,6 +28,7 @@ use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
2828use tracing::{debug, instrument, trace};
2929
3030use super::{LIMITATION_NOTE, OutlivesSuggestionBuilder, RegionName, RegionNameSource};
31use crate::consumers::RegionInferenceContext;
3132use crate::nll::ConstraintDescription;
3233use crate::region_infer::{BlameConstraint, TypeTest};
3334use crate::session_diagnostics::{
......@@ -134,7 +135,7 @@ pub(crate) struct ErrorConstraintInfo<'tcx> {
134135 pub(super) span: Span,
135136}
136137
137impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
138impl<'tcx> RegionInferenceContext<'tcx> {
138139 /// Converts a region inference variable into a `ty::Region` that
139140 /// we can use for error reporting. If `r` is universally bound,
140141 /// then we use the name that we have on record for it. If `r` is
......@@ -142,20 +143,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
142143 /// to find a good name from that. Returns `None` if we can't find
143144 /// one (e.g., this is just some random part of the CFG).
144145 pub(super) fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
145 self.to_error_region_vid(r).and_then(|r| self.regioncx.region_definition(r).external_name)
146 self.to_error_region_vid(r).and_then(|r| self.region_definition(r).external_name)
146147 }
147148
148149 /// Returns the `RegionVid` corresponding to the region returned by
149150 /// `to_error_region`.
150151 pub(super) fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
151 if self.regioncx.universal_regions().is_universal_region(r) {
152 if self.universal_regions().is_universal_region(r) {
152153 Some(r)
153154 } else {
154155 // We just want something nameable, even if it's not
155156 // actually an upper bound.
156 let upper_bound = self.regioncx.approx_universal_upper_bound(r);
157 let upper_bound = self.approx_universal_upper_bound(r);
157158
158 if self.regioncx.upper_bound_in_region_scc(r, upper_bound) {
159 if self.upper_bound_in_region_scc(r, upper_bound) {
159160 self.to_error_region_vid(upper_bound)
160161 } else {
161162 None
......@@ -179,14 +180,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
179180 if let Some(r) = self.to_error_region(fr)
180181 && let ty::ReLateParam(late_param) = r.kind()
181182 && let ty::LateParamRegionKind::ClosureEnv = late_param.kind
182 && let DefiningTy::Closure(_, args) = self.regioncx.universal_regions().defining_ty
183 && let DefiningTy::Closure(_, args) = self.universal_regions().defining_ty
183184 {
184185 return args.as_closure().kind() == ty::ClosureKind::FnMut;
185186 }
186187
187188 false
188189 }
190}
189191
192impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
190193 // For generic associated types (GATs) which implied 'static requirement
191194 // from higher-ranked trait bounds (HRTB). Try to locate span of the trait
192195 // and the span which bounded to the trait for adding 'static lifetime suggestion
......@@ -309,12 +312,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
309312 RegionErrorKind::TypeTestError { type_test } => {
310313 // Try to convert the lower-bound region into something named we can print for
311314 // the user.
312 let lower_bound_region = self.to_error_region(type_test.lower_bound);
315 let lower_bound_region = self.regioncx.to_error_region(type_test.lower_bound);
313316
314317 let type_test_span = type_test.span;
315318
316319 if let Some(lower_bound_region) = lower_bound_region {
317 let generic_ty = self.name_regions(
320 let generic_ty = self.regioncx.name_regions(
318321 self.infcx.tcx,
319322 type_test.generic_kind.to_ty(self.infcx.tcx),
320323 );
......@@ -324,7 +327,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
324327 self.body.source.def_id().expect_local(),
325328 type_test_span,
326329 Some(origin),
327 self.name_regions(self.infcx.tcx, type_test.generic_kind),
330 self.regioncx.name_regions(self.infcx.tcx, type_test.generic_kind),
328331 lower_bound_region,
329332 ));
330333 } else {
......@@ -450,7 +453,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
450453 debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
451454
452455 // Check if we can use one of the "nice region errors".
453 if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
456 if let (Some(f), Some(o)) =
457 (self.regioncx.to_error_region(fr), self.regioncx.to_error_region(outlived_fr))
458 {
454459 let infer_err = self.infcx.err_ctxt();
455460 let nice =
456461 NiceRegionError::new_from_span(&infer_err, self.mir_def_id(), cause.span, o, f);
......@@ -481,7 +486,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
481486 d.note("meoow :c");
482487 d
483488 }
484 (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
489 (ConstraintCategory::Return(kind), true, false)
490 if self.regioncx.is_closure_fn_mut(fr) =>
491 {
485492 self.report_fnmut_error(&errci, kind)
486493 }
487494 (ConstraintCategory::Assignment, true, false)
......@@ -736,7 +743,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
736743 // Only show an extra note if we can find an 'error region' for both of the region
737744 // variables. This avoids showing a noisy note that just mentions 'synthetic' regions
738745 // that don't help the user understand the error.
739 match (self.to_error_region(errci.fr), self.to_error_region(errci.outlived_fr)) {
746 match (
747 self.regioncx.to_error_region(errci.fr),
748 self.regioncx.to_error_region(errci.outlived_fr),
749 ) {
740750 (Some(f), Some(o)) => {
741751 self.maybe_suggest_constrain_dyn_trait_impl(&mut diag, f, o, category);
742752
......@@ -842,7 +852,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
842852 outlived_fr: RegionVid,
843853 ) {
844854 if let (Some(f), Some(outlived_f)) =
845 (self.to_error_region(fr), self.to_error_region(outlived_fr))
855 (self.regioncx.to_error_region(fr), self.regioncx.to_error_region(outlived_fr))
846856 {
847857 if outlived_f.kind() != ty::ReStatic {
848858 return;
......@@ -1013,7 +1023,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10131023 }
10141024
10151025 fn suggest_adding_lifetime_params(&self, diag: &mut Diag<'_>, sub: RegionVid, sup: RegionVid) {
1016 let (Some(sub), Some(sup)) = (self.to_error_region(sub), self.to_error_region(sup)) else {
1026 let (Some(sub), Some(sup)) =
1027 (self.regioncx.to_error_region(sub), self.regioncx.to_error_region(sup))
1028 else {
10171029 return;
10181030 };
10191031
compiler/rustc_borrowck/src/diagnostics/region_name.rs+3-3
......@@ -283,7 +283,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
283283 /// named variants.
284284 #[instrument(level = "trace", skip(self))]
285285 fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
286 let error_region = self.to_error_region(fr)?;
286 let error_region = self.regioncx.to_error_region(fr)?;
287287
288288 let tcx = self.infcx.tcx;
289289
......@@ -1015,7 +1015,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
10151015 &self,
10161016 fr: RegionVid,
10171017 ) -> Option<RegionName> {
1018 let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else {
1018 let ty::ReEarlyParam(region) = self.regioncx.to_error_region(fr)?.kind() else {
10191019 return None;
10201020 };
10211021 if region.is_named() {
......@@ -1050,7 +1050,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
10501050 &self,
10511051 fr: RegionVid,
10521052 ) -> Option<RegionName> {
1053 let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else {
1053 let ty::ReEarlyParam(region) = self.regioncx.to_error_region(fr)?.kind() else {
10541054 return None;
10551055 };
10561056 if region.is_named() {
compiler/rustc_borrowck/src/lib.rs+14-5
......@@ -48,6 +48,7 @@ use rustc_mir_dataflow::points::DenseLocationMap;
4848use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
4949use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
5050use rustc_span::{ErrorGuaranteed, Span, Symbol};
51use rustc_trait_selection::traits::query::type_op::{QueryTypeOp, TypeOp, TypeOpOutput};
5152use smallvec::SmallVec;
5253use tracing::{debug, instrument};
5354
......@@ -323,7 +324,6 @@ fn borrowck_collect_region_constraints<'tcx>(
323324 let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
324325 if let Some(e) = input_body.tainted_by_errors {
325326 infcx.set_tainted_by_errors(e);
326 root_cx.set_tainted_by_errors(e);
327327 }
328328
329329 // Replace all regions with fresh inference variables. This
......@@ -571,15 +571,16 @@ fn borrowck_check_region_constraints<'tcx>(
571571
572572 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
573573 mbcx.lint_unused_mut();
574 if let Some(guar) = mbcx.emit_errors() {
575 mbcx.root_cx.set_tainted_by_errors(guar);
576 }
577574
578575 let result = PropagatedBorrowCheckResults {
579576 closure_requirements: opt_closure_req,
580577 used_mut_upvars: mbcx.used_mut_upvars,
581578 };
582579
580 if let Some(guar) = mbcx.diags_buffer.emit_errors().or(infcx.tainted_by_errors()) {
581 root_cx.set_tainted_by_errors(guar);
582 }
583
583584 if let Some(consumer) = &mut root_cx.consumer {
584585 consumer.insert_body(
585586 def,
......@@ -707,6 +708,14 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
707708
708709 next_region
709710 }
711
712 fn fully_perform<Q: QueryTypeOp<'tcx> + TypeVisitable<TyCtxt<'tcx>>>(
713 &self,
714 q: Q,
715 span: Span,
716 ) -> Result<TypeOpOutput<'tcx, ty::ParamEnvAnd<'tcx, Q>>, ErrorGuaranteed> {
717 self.param_env.and(q).fully_perform(&self.infcx, self.root_def_id, span)
718 }
710719}
711720
712721impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
......@@ -718,7 +727,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
718727}
719728
720729pub(crate) struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
721 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
730 root_cx: &'a BorrowCheckRootCtxt<'tcx>,
722731 infcx: &'infcx BorrowckInferCtxt<'tcx>,
723732 body: &'a Body<'tcx>,
724733 move_data: &'a MoveData<'tcx>,
compiler/rustc_borrowck/src/nll.rs+1-1
......@@ -111,7 +111,7 @@ pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>(
111111///
112112/// This may result in errors being reported.
113113pub(crate) fn compute_regions<'tcx>(
114 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
114 root_cx: &BorrowCheckRootCtxt<'tcx>,
115115 infcx: &BorrowckInferCtxt<'tcx>,
116116 body: &Body<'tcx>,
117117 location_table: &PoloniusLocationTable,
compiler/rustc_borrowck/src/root_cx.rs+1-1
......@@ -72,7 +72,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
7272 }
7373
7474 pub(super) fn used_mut_upvars(
75 &mut self,
75 &self,
7676 nested_body_def_id: LocalDefId,
7777 ) -> &SmallVec<[FieldIdx; 8]> {
7878 &self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs+2-6
......@@ -11,7 +11,7 @@ use rustc_middle::ty::{
1111 self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions,
1212};
1313use rustc_span::Span;
14use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
14use rustc_trait_selection::traits::query::type_op::TypeOpOutput;
1515use tracing::{debug, instrument};
1616
1717use crate::constraints::OutlivesConstraint;
......@@ -287,11 +287,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
287287 ConstraintCategory<'tcx>,
288288 )>,
289289 ) -> Ty<'tcx> {
290 match self.infcx.param_env.and(DeeplyNormalize { value: ty }).fully_perform(
291 self.infcx,
292 self.infcx.root_def_id,
293 self.span,
294 ) {
290 match self.infcx.fully_perform(DeeplyNormalize { value: ty }, self.span) {
295291 Ok(TypeOpOutput { output: ty, constraints, .. }) => {
296292 // FIXME(higher_ranked_auto): What should we do with the assumptions here?
297293 if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
compiler/rustc_borrowck/src/type_check/free_region_relations.rs+13-21
......@@ -10,7 +10,7 @@ use rustc_middle::mir::ConstraintCategory;
1010use rustc_middle::traits::query::OutlivesBound;
1111use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
1212use rustc_span::{ErrorGuaranteed, Span};
13use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
13use rustc_trait_selection::traits::query::type_op;
1414use tracing::{debug, instrument};
1515use type_op::TypeOpOutput;
1616
......@@ -242,15 +242,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
242242 if let Some(c) = constraints_unnorm {
243243 constraints.push(c)
244244 }
245 let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
246 param_env
247 .and(DeeplyNormalize { value: ty })
248 .fully_perform(self.infcx, self.infcx.root_def_id, span)
249 .unwrap_or_else(|guar| TypeOpOutput {
250 output: Ty::new_error(self.infcx.tcx, guar),
251 constraints: None,
252 error_info: None,
253 });
245 let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
246 .infcx
247 .fully_perform(DeeplyNormalize { value: ty }, span)
248 .unwrap_or_else(|guar| TypeOpOutput {
249 output: Ty::new_error(self.infcx.tcx, guar),
250 constraints: None,
251 error_info: None,
252 });
254253 if let Some(c) = constraints_normalize {
255254 constraints.push(c)
256255 }
......@@ -299,9 +298,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
299298 if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst { .. })
300299 {
301300 for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
302 let result: Result<_, ErrorGuaranteed> = param_env
303 .and(DeeplyNormalize { value: ty })
304 .fully_perform(self.infcx, self.infcx.root_def_id, span);
301 let result: Result<_, ErrorGuaranteed> =
302 self.infcx.fully_perform(DeeplyNormalize { value: ty }, span);
305303 let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
306304 continue;
307305 };
......@@ -354,11 +352,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
354352 output: normalized_outlives,
355353 constraints: constraints_normalize,
356354 error_info: _,
357 }) = self.infcx.param_env.and(DeeplyNormalize { value: outlives }).fully_perform(
358 self.infcx,
359 self.infcx.root_def_id,
360 span,
361 )
355 }) = self.infcx.fully_perform(DeeplyNormalize { value: outlives }, span)
362356 else {
363357 self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
364358 return;
......@@ -381,9 +375,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
381375 ) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
382376 let TypeOpOutput { output: bounds, constraints, .. } = self
383377 .infcx
384 .param_env
385 .and(type_op::ImpliedOutlivesBounds { ty })
386 .fully_perform(self.infcx, self.infcx.root_def_id, span)
378 .fully_perform(type_op::ImpliedOutlivesBounds { ty }, span)
387379 .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
388380 .ok()?;
389381 debug!(?bounds, ?constraints);
compiler/rustc_borrowck/src/type_check/liveness/trace.rs+6-4
......@@ -15,7 +15,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
1515use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
1616use rustc_trait_selection::traits::ObligationCtxt;
1717use rustc_trait_selection::traits::query::dropck_outlives;
18use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, TypeOpOutput};
18use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOpOutput};
1919use tracing::debug;
2020
2121use crate::polonius;
......@@ -638,9 +638,9 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
638638 ) -> DropData<'tcx> {
639639 debug!("compute_drop_data(dropped_ty={:?})", dropped_ty);
640640
641 let op = typeck.infcx.param_env.and(DropckOutlives { dropped_ty });
641 let goal = DropckOutlives { dropped_ty };
642642
643 match op.fully_perform(typeck.infcx, typeck.root_cx.root_def_id(), DUMMY_SP) {
643 match typeck.infcx.fully_perform(goal, DUMMY_SP) {
644644 Ok(TypeOpOutput { output, constraints, .. }) => {
645645 DropData { dropck_result: output, region_constraint_data: constraints }
646646 }
......@@ -655,7 +655,9 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
655655 typeck.infcx.probe(|_| {
656656 let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx);
657657 let errors = match dropck_outlives::compute_dropck_outlives_with_errors(
658 &ocx, op, span,
658 &ocx,
659 typeck.infcx.param_env.and(goal),
660 span,
659661 ) {
660662 Ok(_) => ocx.evaluate_obligations_error_on_ambiguity(),
661663 Err(e) => e,
compiler/rustc_borrowck/src/type_check/mod.rs+2-3
......@@ -95,7 +95,7 @@ mod relate_tys;
9595/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
9696/// - `location_map` -- map between MIR `Location` and `PointIndex`
9797pub(crate) fn type_check<'tcx>(
98 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
98 root_cx: &BorrowCheckRootCtxt<'tcx>,
9999 infcx: &BorrowckInferCtxt<'tcx>,
100100 body: &Body<'tcx>,
101101 promoted: &IndexSlice<Promoted, Body<'tcx>>,
......@@ -198,7 +198,6 @@ pub(crate) fn type_check<'tcx>(
198198 debug!("encountered an error region; removing constraints!");
199199 constraints.outlives_constraints = Default::default();
200200 constraints.type_tests = Default::default();
201 root_cx.set_tainted_by_errors(guar);
202201 infcx.set_tainted_by_errors(guar);
203202 }
204203
......@@ -229,7 +228,7 @@ enum FieldAccessError {
229228/// way, it accrues region constraints -- these can later be used by
230229/// NLL region checking.
231230struct TypeChecker<'a, 'tcx> {
232 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
231 root_cx: &'a BorrowCheckRootCtxt<'tcx>,
233232 infcx: &'a BorrowckInferCtxt<'tcx>,
234233 last_span: Span,
235234 body: &'a Body<'tcx>,
compiler/rustc_codegen_cranelift/src/abi/mod.rs+1
......@@ -271,6 +271,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
271271 .map(|local| {
272272 let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty);
273273
274 // FIXME(splat): un-tuple splatted arguments in codegen, for performance
274275 // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
275276 if Some(local) == fx.mir.spread_arg {
276277 // This argument (e.g. the last argument in the "rust-call" ABI)
compiler/rustc_codegen_gcc/src/builder.rs+2-1
......@@ -993,7 +993,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
993993 loaded_value.to_rvalue()
994994 }
995995
996 fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
996 fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>, _: Align) -> RValue<'gcc> {
997 // FIXME(antoyo): set alignment.
997998 let ptr = self.context.new_cast(self.location, ptr, ty.make_volatile().make_pointer());
998999 // (FractalFir): We insert a local here, to ensure this volatile load can't move across
9991000 // blocks.
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs+4-3
......@@ -5,7 +5,7 @@ mod simd;
55use std::iter;
66
77use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp};
8use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange};
8use rustc_abi::{Align, BackendRepr, HasDataLayout, WrappingRange};
99use rustc_codegen_ssa::base::wants_msvc_seh;
1010use rustc_codegen_ssa::common::IntPredicate;
1111use rustc_codegen_ssa::errors::InvalidMonomorphization;
......@@ -368,8 +368,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
368368
369369 sym::volatile_load | sym::unaligned_volatile_load => {
370370 let ptr = args[0].immediate();
371 let load = self.volatile_load(result.layout.gcc_type(self), ptr);
372 // FIXME(antoyo): set alignment.
371 let abi_align = result_layout.align.abi;
372 let ptr_align = if name == sym::volatile_load { abi_align } else { Align::ONE };
373 let load = self.volatile_load(result.layout.gcc_type(self), ptr, ptr_align);
373374 if let BackendRepr::Scalar(scalar) = result.layout.backend_repr {
374375 self.to_immediate_scalar(load, scalar)
375376 } else {
compiler/rustc_codegen_llvm/src/builder.rs+2-2
......@@ -682,9 +682,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
682682 }
683683 }
684684
685 fn volatile_load(&mut self, ty: &'ll Type, ptr: &'ll Value) -> &'ll Value {
685 fn volatile_load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
686686 unsafe {
687 let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);
687 let load = self.load(ty, ptr, align);
688688 llvm::LLVMSetVolatile(load, llvm::TRUE);
689689 load
690690 }
compiler/rustc_codegen_llvm/src/context.rs+1-1
......@@ -978,7 +978,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
978978 }
979979
980980 fn intrinsic_call_expects_place_always(&self, name: Symbol) -> bool {
981 matches!(name, sym::volatile_load | sym::unaligned_volatile_load | sym::black_box)
981 matches!(name, sym::black_box)
982982 }
983983}
984984
compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs+2-4
......@@ -1,5 +1,6 @@
11// .debug_gdb_scripts binary section.
22
3use rustc_abi::Align;
34use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
45use rustc_codegen_ssa::traits::*;
56use rustc_hir::attrs::DebuggerVisualizerType;
......@@ -18,10 +19,7 @@ pub(crate) fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Buil
1819 let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
1920 // Load just the first byte as that's all that's necessary to force
2021 // LLVM to keep around the reference to the global.
21 let volatile_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
22 unsafe {
23 llvm::LLVMSetAlignment(volatile_load_instruction, 1);
24 }
22 bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section, Align::ONE);
2523 }
2624}
2725
compiler/rustc_codegen_llvm/src/intrinsic.rs+30-16
......@@ -354,25 +354,39 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
354354 }
355355
356356 sym::volatile_load | sym::unaligned_volatile_load => {
357 let result = PlaceRef {
358 val: result_place.unwrap(),
359 layout: result_layout,
360 };
361
357 // Note that we cannot just load the `llvm_type` because we should never load non-scalars.
358 // Trying to do so blows up horribly in some cases -- for example loading a
359 // `MaybeUninint<&dyn Trait>` would load as `{ [i64x2] }` which gives assertions later
360 // (if we're lucky) from things not being pointers that ought to be.
362361 let ptr = args[0].immediate();
363 let load = self.volatile_load(result_layout.llvm_type(self), ptr);
364 let align = if name == sym::unaligned_volatile_load {
365 1
362 let abi_align = result_layout.align.abi;
363 let ptr_align = if name == sym::volatile_load { abi_align } else { Align::ONE };
364 if result_layout.is_zst() {
365 return IntrinsicResult::Operand(OperandValue::ZeroSized);
366 } else if let BackendRepr::Scalar(scalar) = result_layout.backend_repr {
367 let load = self.volatile_load(self.type_from_scalar(scalar), ptr, ptr_align);
368 self.to_immediate_scalar(load, scalar)
366369 } else {
367 result_layout.align.bytes() as u32
368 };
369 unsafe {
370 llvm::LLVMSetAlignment(load, align);
371 }
372 if !result_layout.is_zst() {
373 self.store_to_place(load, result.val);
370 // One day Rust will probably want to define how we split up a volatile load
371 // of something that's *not* just an ordinary scalar, but for now we can just
372 // use an LLVM integer type of the correct width and let it split it however.
373 let llty = self.type_ix(result_layout.size.bits());
374 let temp = if let Some(result_place) = result_place {
375 PlaceRef {
376 val: result_place,
377 layout: result_layout,
378 }
379 } else {
380 PlaceRef::alloca(self, result_layout)
381 };
382 let llval = self.volatile_load(llty, ptr, ptr_align);
383 self.store(llval, temp.val.llval, abi_align);
384 return if result_place.is_none() {
385 IntrinsicResult::Operand(self.load_operand(temp).val)
386 } else {
387 IntrinsicResult::WroteIntoPlace
388 };
374389 }
375 return IntrinsicResult::WroteIntoPlace;
376390 }
377391 sym::volatile_store => {
378392 let dst = args[0].deref(self.cx());
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs+1
......@@ -375,6 +375,7 @@ fn push_debuginfo_type_name<'tcx>(
375375 output.push_str("fn(");
376376 }
377377
378 // FIXME(splat): should debuginfo be de-tupled in the callee (and caller)?
378379 if !sig.inputs().is_empty() {
379380 for &parameter_type in sig.inputs() {
380381 push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
compiler/rustc_codegen_ssa/src/mir/block.rs+1
......@@ -1202,6 +1202,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12021202 };
12031203
12041204 // Split the rust-call tupled arguments off.
1205 // FIXME(splat): un-tuple splatted arguments in codegen, for performance
12051206 let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall
12061207 && let Some((tup, args)) = args.split_last()
12071208 {
compiler/rustc_codegen_ssa/src/mir/mod.rs+1
......@@ -433,6 +433,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
433433 let arg_decl = &mir.local_decls[local];
434434 let arg_ty = fx.monomorphize(arg_decl.ty);
435435
436 // FIXME(splat): re-tuple splatted arguments that were un-tupled in the ABI
436437 if Some(local) == mir.spread_arg {
437438 // This argument (e.g., the last argument in the "rust-call" ABI)
438439 // is a tuple that was spread at the ABI level and now we have
compiler/rustc_codegen_ssa/src/traits/builder.rs+1-1
......@@ -242,7 +242,7 @@ pub trait BuilderMethods<'a, 'tcx>:
242242 fn alloca_with_ty(&mut self, layout: TyAndLayout<'tcx>) -> Self::Value;
243243
244244 fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
245 fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value;
245 fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
246246 fn atomic_load(
247247 &mut self,
248248 ty: Self::Type,
compiler/rustc_const_eval/src/const_eval/type_info.rs+17-1
......@@ -7,7 +7,7 @@ use rustc_ast::Mutability;
77use rustc_hir::LangItem;
88use rustc_middle::span_bug;
99use rustc_middle::ty::layout::TyAndLayout;
10use rustc_middle::ty::{self, Const, FnHeader, FnSigTys, ScalarInt, Ty, TyCtxt};
10use rustc_middle::ty::{self, Const, FnHeader, FnSigKind, FnSigTys, ScalarInt, Ty, TyCtxt};
1111use rustc_span::{Symbol, sym};
1212
1313use crate::const_eval::CompileTimeMachine;
......@@ -436,6 +436,22 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
436436 sym::variadic => {
437437 self.write_scalar(Scalar::from_bool(fn_sig_kind.c_variadic()), &field_place)?;
438438 }
439 sym::is_splatted => {
440 self.write_scalar(
441 Scalar::from_bool(fn_sig_kind.splatted().is_some()),
442 &field_place,
443 )?;
444 }
445 sym::splatted_index => {
446 self.write_scalar(
447 Scalar::from_u8(
448 // Currently the same encoding as FnSigKind.splatted
449 // FIXME(splat): make these two fields into a single Option<u8/u16>, or choose a stable encoding
450 fn_sig_kind.splatted().unwrap_or(FnSigKind::NO_SPLATTED_ARG_INDEX),
451 ),
452 &field_place,
453 )?;
454 }
439455 other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
440456 }
441457 }
compiler/rustc_const_eval/src/interpret/call.rs+1
......@@ -681,6 +681,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
681681 };
682682
683683 // Special handling for the closure ABI: untuple the last argument.
684 // FIXME(splat): un-tuple splatted arguments that were tupled in typecheck
684685 let args: Cow<'_, [FnArg<'tcx, M::Provenance>]> =
685686 if caller_abi == ExternAbi::RustCall && !args.is_empty() {
686687 // Untuple
compiler/rustc_hir/src/hir.rs+21-20
......@@ -4045,12 +4045,12 @@ pub struct Param<'hir> {
40454045#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40464046pub enum SplattedArgIndexError {
40474047 /// The splatted argument index is invalid.
4048 /// Currently the only unsupported index is `u16::MAX`, which is used to indicate that no argument
4049 /// is splatted.
4050 InvalidIndex { splatted_arg_index: u16 },
4048 /// A `u8::MAX` argument index used to indicate that no argument is splatted.
4049 /// Higher values are also not supported, for performance reasons.
4050 InvalidIndex { splatted_arg_index: u8 },
40514051
40524052 /// The splatted argument index is outside the bounds of the function arguments.
4053 OutOfBounds { splatted_arg_index: u16, args_len: u16 },
4053 OutOfBounds { splatted_arg_index: u8, args_len: u16 },
40544054}
40554055
40564056/// Contains the packed non-type fields of a function declaration.
......@@ -4061,9 +4061,9 @@ pub struct FnDeclFlags {
40614061 flags: u8,
40624062
40634063 /// Which function argument is splatted into multiple arguments in callers, if any?
4064 /// Splatting functions with `u16::MAX` arguments is not supported, see `FnSigKind` for
4064 /// Splatting functions with `>= u8::MAX` arguments is not supported, see `FnSigKind` for
40654065 /// details.
4066 splatted: u16,
4066 splatted: u8,
40674067}
40684068
40694069impl fmt::Debug for FnDeclFlags {
......@@ -4101,13 +4101,13 @@ impl FnDeclFlags {
41014101
41024102 /// Marker index for "no splatted argument".
41034103 /// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`.
4104 const NO_SPLATTED_ARG_INDEX: u16 = u16::MAX;
4104 const NO_SPLATTED_ARG_INDEX: u8 = u8::MAX;
41054105
41064106 /// Create a new FnDeclKind with no implicit self, no lifetime elision, no C-style variadic
41074107 /// argument, and no splatting.
41084108 /// To modify these flags, use the `set_*` methods, for readability.
41094109 // FIXME: use Default instead when that trait is const stable.
4110 pub const fn default() -> Self {
4110 pub fn default() -> Self {
41114111 Self { flags: 0, splatted: 0 }
41124112 .set_implicit_self(ImplicitSelfKind::None)
41134113 .set_lifetime_elision_allowed(false)
......@@ -4117,7 +4117,7 @@ impl FnDeclFlags {
41174117
41184118 /// Set the implicit self kind.
41194119 #[must_use = "this method does not modify the receiver"]
4120 pub const fn set_implicit_self(mut self, implicit_self: ImplicitSelfKind) -> Self {
4120 pub fn set_implicit_self(mut self, implicit_self: ImplicitSelfKind) -> Self {
41214121 self.flags &= !Self::IMPLICIT_SELF_MASK;
41224122
41234123 match implicit_self {
......@@ -4133,7 +4133,7 @@ impl FnDeclFlags {
41334133
41344134 /// Set the C-style variadic argument flag.
41354135 #[must_use = "this method does not modify the receiver"]
4136 pub const fn set_c_variadic(mut self, c_variadic: bool) -> Self {
4136 pub fn set_c_variadic(mut self, c_variadic: bool) -> Self {
41374137 if c_variadic {
41384138 self.flags |= Self::C_VARIADIC_FLAG;
41394139 } else {
......@@ -4145,7 +4145,7 @@ impl FnDeclFlags {
41454145
41464146 /// Set the lifetime elision allowed flag.
41474147 #[must_use = "this method does not modify the receiver"]
4148 pub const fn set_lifetime_elision_allowed(mut self, allowed: bool) -> Self {
4148 pub fn set_lifetime_elision_allowed(mut self, allowed: bool) -> Self {
41494149 if allowed {
41504150 self.flags |= Self::LIFETIME_ELISION_ALLOWED_FLAG;
41514151 } else {
......@@ -4158,16 +4158,17 @@ impl FnDeclFlags {
41584158 /// Set the splatted argument index.
41594159 /// The number of function arguments is used for error checking.
41604160 #[must_use = "this method does not modify the receiver"]
4161 pub const fn set_splatted(
4161 pub fn set_splatted(
41624162 mut self,
4163 splatted: Option<u16>,
4163 splatted: Option<u8>,
41644164 args_len: usize,
41654165 ) -> Result<Self, SplattedArgIndexError> {
41664166 if let Some(splatted_arg_index) = splatted {
41674167 if splatted_arg_index == Self::NO_SPLATTED_ARG_INDEX {
41684168 // This index value is used as a marker for "no splatting", so it is unsupported.
4169 // Higher values are also not supported, for performance reasons.
41694170 return Err(SplattedArgIndexError::InvalidIndex { splatted_arg_index });
4170 } else if splatted_arg_index as usize >= args_len {
4171 } else if usize::from(splatted_arg_index) >= args_len {
41714172 return Err(SplattedArgIndexError::OutOfBounds {
41724173 splatted_arg_index,
41734174 args_len: args_len as u16,
......@@ -4184,14 +4185,14 @@ impl FnDeclFlags {
41844185
41854186 /// Set "no splatted arguments" for the function declaration.
41864187 #[must_use = "this method does not modify the receiver"]
4187 pub const fn set_no_splatted_args(mut self) -> Self {
4188 pub fn set_no_splatted_args(mut self) -> Self {
41884189 self.splatted = Self::NO_SPLATTED_ARG_INDEX;
41894190
41904191 self
41914192 }
41924193
41934194 /// Get the implicit self kind.
4194 pub const fn implicit_self(self) -> ImplicitSelfKind {
4195 pub fn implicit_self(self) -> ImplicitSelfKind {
41954196 match self.flags & Self::IMPLICIT_SELF_MASK {
41964197 0 => ImplicitSelfKind::None,
41974198 1 => ImplicitSelfKind::Imm,
......@@ -4203,17 +4204,17 @@ impl FnDeclFlags {
42034204 }
42044205
42054206 /// Do the function arguments end with a C-style variadic argument?
4206 pub const fn c_variadic(self) -> bool {
4207 pub fn c_variadic(self) -> bool {
42074208 self.flags & Self::C_VARIADIC_FLAG != 0
42084209 }
42094210
42104211 /// Is lifetime elision allowed?
4211 pub const fn lifetime_elision_allowed(self) -> bool {
4212 pub fn lifetime_elision_allowed(self) -> bool {
42124213 self.flags & Self::LIFETIME_ELISION_ALLOWED_FLAG != 0
42134214 }
42144215
42154216 /// Get the splatted argument index, if any.
4216 pub const fn splatted(self) -> Option<u16> {
4217 pub fn splatted(self) -> Option<u8> {
42174218 if self.splatted == Self::NO_SPLATTED_ARG_INDEX { None } else { Some(self.splatted) }
42184219 }
42194220}
......@@ -4263,7 +4264,7 @@ impl<'hir> FnDecl<'hir> {
42634264 self.fn_decl_kind.lifetime_elision_allowed()
42644265 }
42654266
4266 pub fn splatted(&self) -> Option<u16> {
4267 pub fn splatted(&self) -> Option<u8> {
42674268 self.fn_decl_kind.splatted()
42684269 }
42694270
compiler/rustc_hir_analysis/src/check/mod.rs+3-1
......@@ -444,11 +444,13 @@ fn fn_sig_suggestion<'tcx>(
444444 predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
445445 assoc: ty::AssocItem,
446446) -> String {
447 let splatted_arg_index = sig.splatted().map(usize::from);
447448 let args = sig
448449 .inputs()
449450 .iter()
450451 .enumerate()
451452 .map(|(i, ty)| {
453 let splat = if splatted_arg_index == Some(i) { "#[splat] " } else { "" };
452454 let arg_ty = match ty.kind() {
453455 ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
454456 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
......@@ -477,7 +479,7 @@ fn fn_sig_suggestion<'tcx>(
477479 }
478480 }
479481 };
480 Some(format!("{arg_ty}"))
482 Some(format!("{splat}{arg_ty}"))
481483 })
482484 .chain(std::iter::once(if sig.c_variadic() { Some("...".to_string()) } else { None }))
483485 .flatten()
compiler/rustc_hir_analysis/src/check/wfcheck.rs+10-1
......@@ -1714,7 +1714,16 @@ fn check_fn_or_method<'tcx>(
17141714 let span = tcx.def_span(def_id);
17151715 let has_implicit_self = hir_decl.implicit_self().has_implicit_self();
17161716 let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 });
1717 // FIXME(splat): use `sig.splatted()` once FnSig has it
1717 // FIXME(splat): support the rest of closure splatting, or replace this code with an error
1718 if let Some(mut splatted_arg_index) = sig.splatted() {
1719 let mut inputs_count = sig.inputs().len();
1720 if has_implicit_self {
1721 splatted_arg_index = splatted_arg_index.strict_sub(1);
1722 inputs_count = inputs_count.strict_sub(1);
1723 }
1724 debug!(?splatted_arg_index, ?inputs_count, ?has_implicit_self, ?sig);
1725 sig = sig.set_splatted(Some(splatted_arg_index), inputs_count).unwrap();
1726 }
17181727 // Check that the argument is a tuple and is sized
17191728 if let Some(ty) = inputs.next() {
17201729 wfcx.register_bound(
compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs+3-2
......@@ -3582,11 +3582,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
35823582 debug!(?output_ty);
35833583
35843584 debug!(?abi, ?safety, ?decl.fn_decl_kind, input_tys_len = ?input_tys.len());
3585 // FIXME(splat): use `set_splatted()` once FnSig has it
35863585 let fn_sig_kind = FnSigKind::default()
35873586 .set_abi(abi)
35883587 .set_safety(safety)
3589 .set_c_variadic(decl.fn_decl_kind.c_variadic());
3588 .set_c_variadic(decl.fn_decl_kind.c_variadic())
3589 .set_splatted(decl.splatted(), input_tys.len())
3590 .unwrap();
35903591 let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, fn_sig_kind);
35913592 let fn_ptr_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
35923593
compiler/rustc_hir_typeck/src/callee.rs+35-10
......@@ -58,9 +58,13 @@ pub(crate) fn check_legal_trait_for_method_call(
5858 tcx.ensure_result().coherent_trait(trait_id)
5959}
6060
61/// State machine for typechecking a call, based on the callee type.
6162#[derive(Debug)]
6263enum CallStep<'tcx> {
64 /// Typecheck a call to a function definition or pointer.
65 /// Includes functions with splatted arguments.
6366 Builtin(Ty<'tcx>),
67 /// Deferred closure Fn* trait typechecking, when the callee is a closure.
6468 DeferredClosure(LocalDefId, ty::FnSig<'tcx>),
6569 /// Call overloading when callee implements one of the Fn* traits.
6670 Overloaded(MethodCallee<'tcx>),
......@@ -544,7 +548,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
544548 arg_exprs: &'tcx [hir::Expr<'tcx>],
545549 expected: Expectation<'tcx>,
546550 ) -> Ty<'tcx> {
547 let (fn_sig, def_id) = match *callee_ty.kind() {
551 let (fn_sig, def_id, callee_generic_args) = match *callee_ty.kind() {
548552 ty::FnDef(def_id, args) => {
549553 self.enforce_context_effects(Some(call_expr.hir_id), call_expr.span, def_id, args);
550554 let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args).skip_norm_wip();
......@@ -573,11 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
573577 .emit();
574578 }
575579 }
576 (fn_sig, Some(def_id))
580 (fn_sig, Some(def_id), Some(args))
577581 }
578582
579583 // FIXME(const_trait_impl): these arms should error because we can't enforce them
580 ty::FnPtr(sig_tys, hdr) => (sig_tys.with(hdr), None),
584 ty::FnPtr(sig_tys, hdr) => (sig_tys.with(hdr), None, None),
581585
582586 _ => unreachable!(),
583587 };
......@@ -595,12 +599,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
595599 let fn_sig = self.normalize(call_expr.span, Unnormalized::new_wip(fn_sig));
596600
597601 self.check_argument_types_maybe_method_like(
598 &fn_sig, call_expr, arg_exprs, expected, def_id,
602 &fn_sig,
603 call_expr,
604 arg_exprs,
605 expected,
606 TupleArgumentsFlag::with_fn_sig_kind(fn_sig.fn_sig_kind, false),
607 def_id,
608 callee_generic_args,
599609 );
600610
611 // Splatting is currently incompatible with RustCall.
601612 if fn_sig.abi() == rustc_abi::ExternAbi::RustCall {
602613 let sp = arg_exprs.last().map_or(call_expr.span, |expr| expr.span);
603 if let Some(ty) = fn_sig.inputs().last().copied() {
614 if let Some(ty) = fn_sig.inputs().last().copied()
615 && fn_sig.splatted().is_none()
616 {
604617 self.register_bound(
605618 ty,
606619 self.tcx.require_lang_item(hir::LangItem::Tuple, sp),
......@@ -627,7 +640,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
627640 call_expr: &'tcx hir::Expr<'tcx>,
628641 arg_exprs: &'tcx [hir::Expr<'tcx>],
629642 expected: Expectation<'tcx>,
643 tuple_arguments_flag: TupleArgumentsFlag,
630644 def_id: Option<DefId>,
645 callee_generic_args: Option<GenericArgsRef<'tcx>>,
631646 ) {
632647 let do_check = || {
633648 self.check_argument_types(
......@@ -638,8 +653,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
638653 expected,
639654 arg_exprs,
640655 fn_sig.c_variadic(),
641 TupleArgumentsFlag::DontTupleArguments,
656 tuple_arguments_flag,
642657 def_id,
658 callee_generic_args,
643659 );
644660 };
645661
......@@ -1009,9 +1025,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10091025 fn_sig.output(),
10101026 expected,
10111027 arg_exprs,
1012 fn_sig.c_variadic(),
1013 TupleArgumentsFlag::TupleArguments,
1028 fn_sig.fn_sig_kind.c_variadic(),
1029 TupleArgumentsFlag::rust_fn_trait_call(),
10141030 Some(closure_def_id.to_def_id()),
1031 None,
10151032 );
10161033
10171034 fn_sig.output()
......@@ -1092,6 +1109,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10921109 expected: Expectation<'tcx>,
10931110 method: MethodCallee<'tcx>,
10941111 ) -> Ty<'tcx> {
1112 // FIXME(splat): if we ever support splatting here, decrement the splatted index, because
1113 // the receiver argument is removed below.
1114 assert_eq!(
1115 method.sig.fn_sig_kind.splatted(),
1116 None,
1117 "splatting is not supported on RustCall tuples",
1118 );
10951119 self.check_argument_types(
10961120 call_expr.span,
10971121 call_expr,
......@@ -1099,9 +1123,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10991123 method.sig.output(),
11001124 expected,
11011125 arg_exprs,
1102 method.sig.c_variadic(),
1103 TupleArgumentsFlag::TupleArguments,
1126 method.sig.fn_sig_kind.c_variadic(),
1127 TupleArgumentsFlag::rust_fn_trait_call(),
11041128 Some(method.def_id),
1129 None,
11051130 );
11061131
11071132 self.write_method_call_and_enforce_effects(call_expr.hir_id, call_expr.span, method);
compiler/rustc_hir_typeck/src/closure.rs+1
......@@ -720,6 +720,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
720720 // in this binder we are creating.
721721 assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
722722 let bound_sig = expected_sig.sig.map_bound(|sig| {
723 // Ignore splatting, it is unsupported on closures.
723724 let fn_sig_kind = FnSigKind::default()
724725 .set_abi(ExternAbi::RustCall)
725726 .set_safety(hir::Safety::Safe)
compiler/rustc_hir_typeck/src/demand.rs+15-2
......@@ -3,11 +3,11 @@ use rustc_hir::def::Res;
33use rustc_hir::intravisit::Visitor;
44use rustc_hir::{self as hir, find_attr};
55use rustc_infer::infer::DefineOpaqueTypes;
6use rustc_middle::bug;
76use rustc_middle::ty::adjustment::AllowTwoPhase;
87use rustc_middle::ty::error::{ExpectedFound, TypeError};
98use rustc_middle::ty::print::with_no_trimmed_paths;
109use rustc_middle::ty::{self, AssocItem, BottomUpFolder, Ty, TypeFoldable, TypeVisitableExt};
10use rustc_middle::{bug, span_bug};
1111use rustc_span::{DUMMY_SP, Ident, Span, sym};
1212use rustc_trait_selection::infer::InferCtxtExt;
1313use rustc_trait_selection::traits::ObligationCause;
......@@ -402,9 +402,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
402402 // Unify the method signature with our incompatible arg, to
403403 // do inference in the *opposite* direction and to find out
404404 // what our ideal rcvr ty would look like.
405 let Some(input_arg) = method.sig.inputs().get(idx + 1) else {
406 if method.sig.splatted().is_some() {
407 // FIXME(splat): when the arg is splatted, adjust its index, to handle the type mismatch properly
408 return None;
409 } else {
410 span_bug!(
411 self.tcx.def_span(method.def_id),
412 "arg index {} out of bounds for method with {} inputs",
413 idx + 1,
414 method.sig.inputs().len(),
415 );
416 }
417 };
405418 let _ = self
406419 .at(&ObligationCause::dummy(), self.param_env)
407 .eq(DefineOpaqueTypes::Yes, method.sig.inputs()[idx + 1], arg_ty)
420 .eq(DefineOpaqueTypes::Yes, *input_arg, arg_ty)
408421 .ok()?;
409422 self.select_obligations_where_possible(|errs| {
410423 // Yeet the errors, we're already reporting errors.
compiler/rustc_hir_typeck/src/diagnostics.rs+1
......@@ -100,6 +100,7 @@ impl IntoDiagArg for ReturnLikeStatementKind {
100100 }
101101}
102102
103// FIXME(splat): add "non-splatted" to all 4 instances of this error message
103104#[derive(Diagnostic)]
104105#[diag("functions with the \"rust-call\" ABI must take a single non-self tuple argument")]
105106pub(crate) struct RustCallIncorrectArgs {
compiler/rustc_hir_typeck/src/expr.rs+11-3
......@@ -1463,16 +1463,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14631463 Ok(method) => {
14641464 self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
14651465
1466 // Handle splatted method arguments
1467 // self is already handled as `rcvr`, so it's never splatted here
1468 let method_inputs = &method.sig.inputs()[1..];
1469 let method_tuple_args_flag =
1470 TupleArgumentsFlag::with_fn_sig_kind(method.sig.fn_sig_kind, true);
1471
14661472 self.check_argument_types(
14671473 segment.ident.span,
14681474 expr,
1469 &method.sig.inputs()[1..],
1475 method_inputs,
14701476 method.sig.output(),
14711477 expected,
14721478 args,
1473 method.sig.c_variadic(),
1474 TupleArgumentsFlag::DontTupleArguments,
1479 method.sig.fn_sig_kind.c_variadic(),
1480 method_tuple_args_flag,
14751481 Some(method.def_id),
1482 Some(method.args),
14761483 );
14771484
14781485 self.check_call_abi(method.sig.abi(), expr.span);
......@@ -1495,6 +1502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14951502 false,
14961503 TupleArgumentsFlag::DontTupleArguments,
14971504 None,
1505 Some(GenericArgsRef::default()),
14981506 );
14991507
15001508 err_output
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs+38-3
......@@ -27,8 +27,8 @@ use rustc_middle::ty::adjustment::{
2727};
2828use rustc_middle::ty::{
2929 self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity,
30 SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, Unnormalized,
31 UserArgs, UserSelfTy,
30 SizedTraitKind, SplattedDef, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt,
31 Unnormalized, UserArgs, UserSelfTy,
3232};
3333use rustc_middle::{bug, span_bug};
3434use rustc_session::lint;
......@@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
143143 /// also select obligations if it seems useful, in an effort
144144 /// to get more type information.
145145 // FIXME(-Znext-solver): A lot of the calls to this method should
146 // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead.
146 // probably be `resolve_vars_with_obligations` or `structurally_resolve_type` instead.
147147 #[instrument(skip(self), level = "debug", ret)]
148148 pub(crate) fn resolve_vars_with_obligations<T: TypeFoldable<TyCtxt<'tcx>>>(
149149 &self,
......@@ -236,6 +236,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
236236 self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
237237 }
238238
239 #[instrument(level = "debug", skip(self))]
240 pub(crate) fn write_splatted_resolution(
241 &self,
242 hir_id: HirId,
243 r: Result<SplattedDef, ErrorGuaranteed>,
244 ) {
245 self.typeck_results.borrow_mut().splatted_defs_mut().insert(hir_id, r);
246 }
247
239248 #[instrument(level = "debug", skip(self))]
240249 pub(crate) fn write_method_call_and_enforce_effects(
241250 &self,
......@@ -248,6 +257,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
248257 self.write_args(hir_id, method.args);
249258 }
250259
260 #[instrument(level = "debug", skip(self))]
261 pub(crate) fn write_splatted_call(
262 &self,
263 hir_id: HirId,
264 span: Span,
265 callee_def_id: Option<DefId>,
266 callee_generic_args: Option<GenericArgsRef<'tcx>>,
267 first_tupled_arg_index: u16,
268 tupled_args_count: u16,
269 ) {
270 // FIXME(const_trait_impl): enforce constness using enforce_context_effects() and add
271 // _and_enforce_effects to this method's name
272
273 self.write_splatted_resolution(
274 hir_id,
275 Ok(SplattedDef {
276 def_id: callee_def_id,
277 arg_index: first_tupled_arg_index,
278 arg_count: tupled_args_count,
279 }),
280 );
281 if let Some(callee_generic_args) = callee_generic_args {
282 self.write_args(hir_id, callee_generic_args);
283 }
284 }
285
251286 fn write_args(&self, node_id: HirId, args: GenericArgsRef<'tcx>) {
252287 if !args.is_empty() {
253288 debug!("write_args({:?}, {:?}) in fcx {}", node_id, args, self.tag());
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs+351-73
......@@ -50,6 +50,19 @@ rustc_index::newtype_index! {
5050 pub(crate) struct GenericIdx {}
5151}
5252
53/// Outcome of checking arguments that are tupled by "rust-call" or `#[splat]`.
54#[derive(Debug, Clone, Eq, PartialEq)]
55struct TupledArgCheckOutcome<'tcx> {
56 /// The error code to emit if the arguments are not compatible.
57 new_err_code: Option<ErrCode>,
58
59 /// The formal input types after checking.
60 untupled_formal_input_tys: Vec<Ty<'tcx>>,
61
62 /// The expected input types after checking.
63 untupled_expected_input_tys: Option<Vec<Ty<'tcx>>>,
64}
65
5366impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5467 pub(in super::super) fn check_casts(&mut self) {
5568 let mut deferred_cast_checks = self.root_ctxt.deferred_cast_checks.borrow_mut();
......@@ -185,13 +198,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
185198 expectation: Expectation<'tcx>,
186199 // The expressions for each provided argument
187200 provided_args: &'tcx [hir::Expr<'tcx>],
188 // Whether the function is variadic, for example when imported from C
189 // FIXME(splat): maybe change this to FnSigKind?
201 // Whether the function is variadic (e.g. from C)
190202 c_variadic: bool,
191 // Whether the arguments have been bundled in a tuple (ex: closures)
203 // Whether all the arguments have been bundled in a tuple (ex: closures), or one has been splatted
192204 tuple_arguments: TupleArgumentsFlag,
193205 // The DefId for the function being called, for better error messages
194206 fn_def_id: Option<DefId>,
207 // The generics of the function being called. Only used for splatting
208 callee_generic_args: Option<ty::GenericArgsRef<'tcx>>,
195209 ) {
196210 let tcx = self.tcx;
197211
......@@ -220,11 +234,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
220234 }
221235
222236 // First, let's unify the formal method signature with the expectation eagerly.
223 // We use this to guide coercion inference; it's output is "fudged" which means
237 // We use this to guide coercion inference; its output is "fudged" which means
224238 // any remaining type variables are assigned to new, unrelated variables. This
225239 // is because the inference guidance here is only speculative.
240 // FIXME(splat): do we need to splat arguments before this type inference?
226241 let formal_output = self.resolve_vars_with_obligations(formal_output);
227 let expected_input_tys: Option<Vec<_>> = expectation
242 let mut expected_input_tys: Option<Vec<_>> = expectation
228243 .only_has_type(self)
229244 .and_then(|expected_output| {
230245 // FIXME(#149379): This operation results in expected input
......@@ -272,45 +287,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
272287
273288 let mut err_code = E0061;
274289
275 // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
276 let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
277 let tuple_type = self.structurally_resolve_type(call_span, formal_input_tys[0]);
278 match tuple_type.kind() {
279 // We expected a tuple and got a tuple
280 ty::Tuple(arg_types) => {
281 // Argument length differs
282 if arg_types.len() != provided_args.len() {
283 err_code = E0057;
284 }
285 let expected_input_tys = match expected_input_tys {
286 Some(expected_input_tys) => match expected_input_tys.get(0) {
287 Some(ty) => match ty.kind() {
288 ty::Tuple(tys) => Some(tys.iter().collect()),
289 _ => None,
290 },
291 None => None,
292 },
293 None => None,
294 };
295 (arg_types.iter().collect(), expected_input_tys)
296 }
297 _ => {
298 // Otherwise, there's a mismatch, so clear out what we're expecting, and set
299 // our input types to err_args so we don't blow up the error messages
300 let guar = struct_span_code_err!(
301 self.dcx(),
302 call_span,
303 E0059,
304 "cannot use call notation; the first type parameter \
305 for the function trait is neither a tuple nor unit"
306 )
307 .emit();
308 (self.err_args(provided_args.len(), guar), None)
309 }
290 let mut formal_input_tys = formal_input_tys.to_vec();
291
292 // If the arguments should be wrapped in a tuple (ex: closures, splats), unwrap them here
293 if tuple_arguments.is_tupled() {
294 // Caller arguments are tupled before typechecking, starting at the given index.
295 // Tupling makes the callee and caller argument counts match.
296 let outcome = self.check_tupled_arguments(
297 call_span,
298 call_expr,
299 formal_input_tys,
300 provided_args,
301 expected_input_tys,
302 c_variadic,
303 tuple_arguments,
304 fn_def_id,
305 callee_generic_args,
306 );
307 let TupledArgCheckOutcome {
308 new_err_code,
309 untupled_formal_input_tys,
310 untupled_expected_input_tys,
311 } = outcome;
312 if let Some(new_err_code) = new_err_code {
313 err_code = new_err_code;
310314 }
311 } else {
312 (formal_input_tys.to_vec(), expected_input_tys)
313 };
315 formal_input_tys = untupled_formal_input_tys;
316 expected_input_tys = untupled_expected_input_tys;
317 }
314318
315319 // If there are no external expectations at the call site, just use the types from the function defn
316320 let expected_input_tys = if let Some(expected_input_tys) = expected_input_tys {
......@@ -556,6 +560,257 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
556560 }
557561 }
558562
563 /// Check arguments that are tupled by "rust-call" or `#[splat]`.
564 fn check_tupled_arguments(
565 &self,
566 // Span enclosing the call site
567 call_span: Span,
568 // Expression of the call site
569 call_expr: &'tcx hir::Expr<'tcx>,
570 // Types (as defined in the *signature* of the target function)
571 mut formal_input_tys: Vec<Ty<'tcx>>,
572 // The expressions for each provided argument
573 provided_args: &'tcx [hir::Expr<'tcx>],
574 // The expected input types from the context of the call site
575 mut expected_input_tys: Option<Vec<Ty<'tcx>>>,
576 // Whether the function is variadic (e.g. from C)
577 c_variadic: bool,
578 // Whether all the arguments have been bundled in a tuple (ex: closures).
579 // Splatting is handled separately.
580 tuple_arguments: TupleArgumentsFlag,
581 // The DefId for the function being called, for better error messages
582 fn_def_id: Option<DefId>,
583 // The generics of the function being called. Only used for splatting
584 callee_generic_args: Option<ty::GenericArgsRef<'tcx>>,
585 ) -> TupledArgCheckOutcome<'tcx> {
586 let (first_tupled_arg_index, is_self_splatted) = tuple_arguments.tupled_arg_index();
587 let Some(first_tupled_arg_index) = first_tupled_arg_index else {
588 // If we're not tupling any of the current arguments, we're done.
589 return TupledArgCheckOutcome {
590 new_err_code: None,
591 untupled_formal_input_tys: formal_input_tys,
592 untupled_expected_input_tys: expected_input_tys,
593 };
594 };
595
596 // The argument difference can range from -1 to u16::MAX - 1, so we count the number
597 // of tupled arguments instead.
598 // (An empty argument list becomes a unit tuple in the callee.)
599 // 0: f() -> f(#[splat] _: ())
600 // 1: f(a) -> f(#[splat] _: (A,))
601 // 2: f(a, b) -> f(#[splat] _: (A, B))
602 // The Fn* traits ensure this by construction, and `#[splat]` can only be applied to
603 // an actual argument.
604 let tupled_args_count = (1 + provided_args.len()).checked_sub(formal_input_tys.len());
605 debug!(
606 ?first_tupled_arg_index, ?is_self_splatted,
607 ?tupled_args_count, ?tuple_arguments, ?c_variadic,
608 provided_args_len = ?provided_args.len(), formal_input_tys_len = ?formal_input_tys.len()
609 );
610
611 // If earlier code has modified the FnSig argument list without adjusting the splatted
612 // argument, indexing into the formal input types will panic.
613 if first_tupled_arg_index >= formal_input_tys.len() {
614 span_bug!(
615 call_span,
616 "splatted argument index is out of bounds: {first_tupled_arg_index:?} >= {}, \
617 is_self_splatted = {is_self_splatted:?}, \
618 tupled_args_count = {tupled_args_count:?}, {tuple_arguments:?}, \
619 c_variadic = {c_variadic:?}, provided_args: {}",
620 formal_input_tys.len(),
621 provided_args.len(),
622 );
623 }
624
625 // Keep the type variable if the argument is splatted, so we can force it to be a tuple later.
626 let tuple_type = if tuple_arguments.is_splatted() {
627 let callee_tuple_type =
628 self.resolve_vars_with_obligations(formal_input_tys[first_tupled_arg_index]);
629 if callee_tuple_type.is_ty_var()
630 && let Some(tupled_args_count) = tupled_args_count
631 {
632 // Make the original type variable resolve to a tuple containing new type variables
633 let ocx = ObligationCtxt::new(self);
634 let origin = self.misc(call_span);
635
636 let new_tupled_type = Ty::new_tup_from_iter(
637 self.tcx,
638 iter::repeat_with(|| self.next_ty_var(call_span)).take(tupled_args_count),
639 );
640
641 // FIXME(splat): should this be a sub/super type relationship?
642 let ocx_error = ocx.eq(&origin, self.param_env, callee_tuple_type, new_tupled_type);
643 if let Err(ocx_error) = ocx_error {
644 // FIXME(splat): add a test for this error and the one below, if they are reachable
645 struct_span_code_err!(
646 self.dcx(),
647 call_span,
648 // FIXME(splat): add a new error code before stabilization (and below as well)
649 E0277,
650 "cannot resolve splatted arguments; splatted type parameters \
651 must be a tuple or unit type: {:?}",
652 ocx_error,
653 )
654 .emit();
655 }
656
657 let type_errors = ocx.try_evaluate_obligations();
658 if type_errors.is_empty() {
659 new_tupled_type
660 } else {
661 let guar = struct_span_code_err!(
662 self.dcx(),
663 call_span,
664 E0277,
665 "cannot resolve splatted arguments; splatted type parameters \
666 must be a tuple or unit type: {:?}",
667 type_errors,
668 )
669 .emit();
670 Ty::new_error(self.tcx, guar)
671 }
672 } else {
673 // Otherwise, just let the argument type checker make a suggestion
674 callee_tuple_type
675 }
676 } else {
677 self.structurally_resolve_type(call_span, formal_input_tys[first_tupled_arg_index])
678 };
679
680 // We expected a tuple and got a tuple (or made one ourselves).
681 // If it's not a tuple, we error out in the next block.
682 let mut err_code = None;
683 if let ty::Tuple(detup_formal_arg_tys) = tuple_type.kind() {
684 // Argument length differs
685 // FIXME(splat): update the error code E0057 docs when splat is stabilized
686 if Some(detup_formal_arg_tys.len()) != tupled_args_count {
687 err_code = Some(E0057);
688 }
689 if let Some(ref mut expected_input_tys) = expected_input_tys
690 && let Some(ty) = expected_input_tys.get(first_tupled_arg_index)
691 && let ty::Tuple(detup_expected_arg_tys) = ty.kind()
692 {
693 let substitute_tys = if Some(detup_expected_arg_tys.len()) == tupled_args_count {
694 detup_expected_arg_tys.iter()
695 } else {
696 // Just fall back to the formal argument types
697 detup_formal_arg_tys.iter()
698 };
699
700 expected_input_tys
701 .splice(first_tupled_arg_index..=first_tupled_arg_index, substitute_tys);
702 } else {
703 expected_input_tys = None;
704 }
705 // If splatting, record this call in a side-table, so MIR lowering can tuple the caller's arguments
706 if tuple_arguments.is_splatted() {
707 // FIXME(const_trait_impl): does not enforce constness yet
708 self.write_splatted_call(
709 call_expr.hir_id,
710 call_span,
711 fn_def_id,
712 callee_generic_args,
713 first_tupled_arg_index.try_into().unwrap(),
714 tupled_args_count.unwrap().try_into().unwrap(),
715 );
716 }
717
718 formal_input_tys.splice(
719 first_tupled_arg_index..=first_tupled_arg_index,
720 detup_formal_arg_tys.iter(),
721 );
722 if let Some(ref expected_input_tys) = expected_input_tys {
723 assert_eq!(
724 formal_input_tys.len(),
725 expected_input_tys.len(),
726 "incorrectly constructed input type tuples, argument counts must match: \
727 tuple_arguments: {tuple_arguments:?}",
728 )
729 }
730 }
731
732 // Otherwise, there's a mismatch during splatting or a rust-call.
733 // So clear out what we're expecting, and set our input types to err_args so we don't
734 // blow up the error messages.
735 let guar =
736 if tuple_arguments == TupleAllCallArgs && !matches!(tuple_type.kind(), ty::Tuple(_)) {
737 let guar = struct_span_code_err!(
738 self.dcx(),
739 call_span,
740 E0059,
741 "cannot use call notation; the first type parameter \
742 for the function trait is neither a tuple nor unit"
743 )
744 .emit();
745
746 Some(guar)
747 } else if tuple_arguments.is_splatted() {
748 // If we don't check argument counts here, and there's a subtle bug in the code above,
749 // later compilation stages can fail in unrelated places with confusing errors.
750 if !matches!(tuple_type.kind(), ty::Tuple(_)) {
751 let spans = if let Some(def_id) = fn_def_id
752 && let Some(hir_node) = self.tcx.hir_get_if_local(def_id)
753 && let Some(fn_decl) = hir_node.fn_decl()
754 && let Some(arg_ty) = fn_decl.inputs.get(first_tupled_arg_index)
755 {
756 let arg_def_span = arg_ty.span;
757 vec![call_span, arg_def_span]
758 } else {
759 vec![call_span]
760 };
761 let guar = struct_span_code_err!(
762 self.dcx(),
763 spans,
764 // FIXME(splat): add a new error code before stabilization
765 E0277,
766 "cannot use splat attribute; the splatted argument type \
767 must be a tuple or unit, not a {:?} ({:?})",
768 tuple_type.kind(),
769 self.structurally_resolve_type(
770 call_span,
771 formal_input_tys[first_tupled_arg_index]
772 )
773 .kind(),
774 )
775 .emit();
776
777 Some(guar)
778 } else if formal_input_tys.len() != provided_args.len() {
779 // FIXME(splat): suggest alternative argument counts, if there are any
780 let guar = struct_span_code_err!(
781 self.dcx(),
782 call_span,
783 E0057,
784 "this splatted function takes {} arguments, but {} {} provided",
785 formal_input_tys.len(),
786 provided_args.len(),
787 if provided_args.len() == 1 { "was" } else { "were" },
788 )
789 .emit();
790
791 Some(guar)
792 } else {
793 None
794 }
795 } else {
796 None
797 };
798
799 if let Some(guar) = guar {
800 TupledArgCheckOutcome {
801 new_err_code: err_code,
802 untupled_formal_input_tys: self.err_args(provided_args.len(), guar),
803 untupled_expected_input_tys: None,
804 }
805 } else {
806 TupledArgCheckOutcome {
807 new_err_code: err_code,
808 untupled_formal_input_tys: formal_input_tys,
809 untupled_expected_input_tys: expected_input_tys,
810 }
811 }
812 }
813
559814 /// If `unsized_fn_params` is active, check that unsized values are place expressions. Since
560815 /// the removal of `unsized_locals` in <https://github.com/rust-lang/rust/pull/142911> we can't
561816 /// store them in MIR locals as temporaries.
......@@ -581,6 +836,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
581836 fn_def_id: Option<DefId>,
582837 call_span: Span,
583838 call_expr: &'tcx hir::Expr<'tcx>,
839 // FIXME(splat): when the feature design is settled, improve the errors here
584840 tuple_arguments: TupleArgumentsFlag,
585841 ) -> ErrorGuaranteed {
586842 // Next, let's construct the error
......@@ -1354,8 +1610,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13541610 // If we're calling a method of a Fn/FnMut/FnOnce trait object implicitly
13551611 // (eg invoking a closure) we want to point at the underlying callable,
13561612 // not the method implicitly invoked (eg call_once).
1357 // TupleArguments is set only when this is an implicit call (my_closure(...)) rather than explicit (my_closure.call(...))
1358 if tuple_arguments == TupleArguments
1613 // TupleAllCallArgs is set only when this is an implicit call `my_closure(...)` rather
1614 // than explicit `my_closure.call(...)`.
1615 if tuple_arguments == TupleAllCallArgs
13591616 && let Some(assoc_item) = self.tcx.opt_associated_item(def_id)
13601617 // Since this is an associated item, it might point at either an impl or a trait item.
13611618 // We want it to always point to the trait item.
......@@ -1442,25 +1699,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14421699 deps: SmallVec<[ExpectedIdx; 4]>,
14431700 }
14441701
1445 debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
1702 // FIXME(splat): fix the generic mismatch earlier, so it doesn't reach here
1703 if !tuple_arguments.is_splatted() {
1704 debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
1705 }
14461706 // Gather all mismatched parameters with generics.
14471707 let mut mismatched_params = Vec::<MismatchedParam<'_>>::new();
1708 let mut use_splat_fallback = false;
14481709 if let Some(expected_idx) = expected_idx {
14491710 let expected_idx = ExpectedIdx::from_usize(expected_idx);
1450 let &(expected_generic, ref expected_param) =
1451 &params_with_generics[expected_idx];
1452 if let Some(expected_generic) = expected_generic {
1453 mismatched_params.push(MismatchedParam {
1454 idx: expected_idx,
1455 generic: expected_generic,
1456 param: expected_param,
1457 deps: SmallVec::new(),
1458 });
1459 } else {
1460 // Still mark the mismatched parameter
1461 spans.push_span_label(expected_param.span(), "");
1462 }
1463 } else {
1711 match params_with_generics.get(expected_idx) {
1712 Some(&(Some(expected_generic), ref expected_param)) => mismatched_params
1713 .push(MismatchedParam {
1714 idx: expected_idx,
1715 generic: expected_generic,
1716 param: expected_param,
1717 deps: SmallVec::new(),
1718 }),
1719 Some((None, expected_param)) => {
1720 // Still mark the mismatched parameter
1721 spans.push_span_label(expected_param.span(), "");
1722 }
1723 None => {
1724 if tuple_arguments.is_splatted() {
1725 // FIXME(splat): when the arg is splatted, adjust its index, to handle the type mismatch properly
1726 use_splat_fallback = true;
1727 } else {
1728 span_bug!(
1729 self.tcx.def_span(def_id),
1730 "arg index {} out of bounds for method with {} inputs",
1731 expected_idx.as_usize(),
1732 params_with_generics.len(),
1733 );
1734 }
1735 }
1736 };
1737 }
1738
1739 if expected_idx.is_none() || use_splat_fallback {
14641740 mismatched_params.extend(
14651741 params_with_generics.iter_enumerated().zip(matched_inputs).filter_map(
14661742 |((idx, &(generic, ref param)), matched_idx)| {
......@@ -1671,15 +1947,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16711947 provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>,
16721948 formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
16731949 is_method: bool,
1950 is_splat: bool,
16741951 ) {
16751952 let Some(def_id) = callable_def_id else {
16761953 return;
16771954 };
16781955
16791956 if let Some((params_with_generics, _)) = self.get_hir_param_info(def_id, is_method) {
1680 debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
1957 // FIXME(splat): fix the generic mismatch earlier, so it doesn't reach here
1958 if !is_splat {
1959 debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
1960 }
16811961 for (idx, (generic_param, _)) in params_with_generics.iter_enumerated() {
1682 if matched_inputs[idx].is_none() {
1962 if matched_inputs.get(idx).flatten_ref().is_none() {
16831963 continue;
16841964 }
16851965
......@@ -1701,7 +1981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17011981 let Some(other_generic_param) = other_generic_param else {
17021982 return false;
17031983 };
1704 if matched_inputs[other_idx].is_some() {
1984 if matched_inputs.get(other_idx).flatten_ref().is_some() {
17051985 return false;
17061986 }
17071987 other_generic_param == generic_param
......@@ -2004,7 +2284,11 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
20042284 self.arg_matching_ctxt.args_ctxt.call_metadata.full_call_span,
20052285 format!(
20062286 "{call_name} takes {}{} but {} {} supplied",
2007 if self.c_variadic { "at least " } else { "" },
2287 if self.arg_matching_ctxt.args_ctxt.c_variadic {
2288 "at least "
2289 } else {
2290 ""
2291 },
20082292 potentially_plural_count(
20092293 self.formal_and_expected_inputs.len(),
20102294 "argument"
......@@ -2147,14 +2431,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
21472431 format!("arguments to this {call_name} are incorrect"),
21482432 );
21492433
2150 self.fn_ctxt.label_generic_mismatches(
2151 &mut err,
2152 self.fn_def_id,
2153 &self.matched_inputs,
2154 &self.provided_arg_tys,
2155 &self.formal_and_expected_inputs,
2156 self.call_metadata.is_method,
2157 );
2434 self.label_generic_mismatches(&mut err);
21582435
21592436 if let hir::ExprKind::MethodCall(_, rcvr, _, _) =
21602437 self.arg_matching_ctxt.args_ctxt.call_ctxt.call_expr.kind
......@@ -2237,7 +2514,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
22372514 format!(
22382515 "this {} takes {}{} but {} {} supplied",
22392516 self.call_metadata.call_name,
2240 if self.c_variadic { "at least " } else { "" },
2517 if self.arg_matching_ctxt.args_ctxt.c_variadic { "at least " } else { "" },
22412518 potentially_plural_count(self.formal_and_expected_inputs.len(), "argument"),
22422519 potentially_plural_count(self.provided_args.len(), "argument"),
22432520 pluralize!("was", self.provided_args.len())
......@@ -2614,6 +2891,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
26142891 &self.provided_arg_tys,
26152892 &self.formal_and_expected_inputs,
26162893 self.call_metadata.is_method,
2894 self.arg_matching_ctxt.tuple_arguments.is_splatted(),
26172895 );
26182896 }
26192897
compiler/rustc_hir_typeck/src/lib.rs+69-8
......@@ -3,6 +3,7 @@
33#![feature(iter_intersperse)]
44#![feature(iter_order_by)]
55#![feature(never_type)]
6#![feature(option_reference_flattening)]
67#![feature(trim_prefix_suffix)]
78// tidy-alphabetical-end
89
......@@ -50,7 +51,7 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
5051use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
5152use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
5253use rustc_middle::query::Providers;
53use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized};
54use rustc_middle::ty::{self, FnSigKind, Ty, TyCtxt, Unnormalized};
5455use rustc_middle::{bug, span_bug};
5556use rustc_session::config;
5657use rustc_span::Span;
......@@ -589,12 +590,10 @@ fn report_unexpected_variant_res(
589590 .emit()
590591}
591592
592/// Controls whether the arguments are tupled. This is used for the call
593/// operator.
593/// Controls whether all arguments are tupled. This is used for the call operator only.
594594///
595/// Tupling means that all call-side arguments are packed into a tuple and
596/// passed as a single parameter. For example, if tupling is enabled, this
597/// function:
595/// Tupling means that all call-side arguments are packed into a tuple and passed as a single
596/// parameter. For example, if tupling is enabled, this function:
598597/// ```
599598/// fn f(x: (isize, isize)) {}
600599/// ```
......@@ -608,10 +607,72 @@ fn report_unexpected_variant_res(
608607/// # fn f(x: (isize, isize)) {}
609608/// f((1, 2));
610609/// ```
611#[derive(Copy, Clone, Eq, PartialEq)]
610///
611/// Note: splatted arguments are handled separately.
612#[derive(Copy, Clone, Debug, Eq, PartialEq)]
612613enum TupleArgumentsFlag {
614 /// Arguments are typechecked unchanged.
613615 DontTupleArguments,
614 TupleArguments,
616 /// This is a call operator: all caller arguments are tupled before typechecking.
617 /// Set based on the "rust-call" ABI and Fn* traits.
618 TupleAllCallArgs,
619 /// The `self` method argument is splatted, so `Self` should be tupled before typechecking.
620 TupleSplattedSelfArg,
621 /// A non-self argument is splatted, so that argument should be tupled before typechecking.
622 TupleSplattedArg(u8),
623}
624
625impl TupleArgumentsFlag {
626 /// Returns the TupleArgumentsFlag for a known RustCall function.
627 fn rust_fn_trait_call() -> Self {
628 Self::TupleAllCallArgs
629 }
630
631 /// Returns the appropriate TupleArgumentsFlag for the given FnSigKind and method flag.
632 fn with_fn_sig_kind<'tcx>(fn_sig_kind: FnSigKind<'tcx>, is_method: bool) -> Self {
633 if let Some(splatted_arg_index) = fn_sig_kind.splatted() {
634 if is_method {
635 if let Some(splatted_arg_index) = splatted_arg_index.checked_sub(1) {
636 return Self::TupleSplattedArg(splatted_arg_index);
637 } else {
638 // In `check_argument_types`, this is effectively `TupleSplattedArg(-1)`
639 return Self::TupleSplattedSelfArg;
640 }
641 }
642
643 return Self::TupleSplattedArg(splatted_arg_index);
644 }
645
646 Self::DontTupleArguments
647 }
648
649 /// Returns true if the arguments are tupled through "rust-call" or splatting.
650 fn is_tupled(self) -> bool {
651 match self {
652 Self::DontTupleArguments => false,
653 Self::TupleAllCallArgs | Self::TupleSplattedSelfArg | Self::TupleSplattedArg(_) => true,
654 }
655 }
656
657 /// Returns true if the arguments are tupled through splatting.
658 /// (But false if they are "rust-call" or not tupled.)
659 fn is_splatted(self) -> bool {
660 match self {
661 Self::TupleSplattedSelfArg | Self::TupleSplattedArg(_) => true,
662 Self::DontTupleArguments | Self::TupleAllCallArgs => false,
663 }
664 }
665
666 /// Returns the tupled argument index, and whether the `self` argument is splatted.
667 /// Returns `None` if the arguments are not tupled, or if the `self` argument is splatted.
668 fn tupled_arg_index(self) -> (Option<usize>, bool /* is_self_splatted */) {
669 match self {
670 Self::TupleSplattedArg(index) => (Some(usize::from(index)), false),
671 Self::TupleAllCallArgs => (Some(0), false),
672 Self::TupleSplattedSelfArg => (None, true),
673 Self::DontTupleArguments => (None, false),
674 }
675 }
615676}
616677
617678fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! {
compiler/rustc_hir_typeck/src/writeback.rs+5
......@@ -663,6 +663,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
663663 self.typeck_results.type_dependent_defs_mut().insert(hir_id, def);
664664 }
665665
666 // Export splatted function call resolutions.
667 if let Some(def) = self.fcx.typeck_results.borrow_mut().splatted_defs_mut().remove(hir_id) {
668 self.typeck_results.splatted_defs_mut().insert(hir_id, def);
669 }
670
666671 // Resolve any borrowings for the node with id `node_id`
667672 self.visit_adjustments(span, hir_id);
668673
compiler/rustc_interface/src/passes.rs+2-2
......@@ -803,8 +803,8 @@ fn resolver_for_lowering_raw<'tcx>(
803803 );
804804 let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
805805
806 // Make sure we don't mutate the cstore from here on.
807 tcx.untracked().cstore.freeze();
806 // Don't mutate the cstore or stable crate id map from here on.
807 tcx.untracked().freeze_cstore();
808808
809809 let ResolverOutputs {
810810 global_ctxt: untracked_resolutions,
compiler/rustc_lint/src/foreign_modules.rs+8
......@@ -329,6 +329,14 @@ fn structurally_same_type_impl<'tcx>(
329329 let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig);
330330 let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig);
331331
332 // FIXME(splat): Is splatting ever repr(C)?
333 // Can two splatted functions to have the same structure?
334 // Can a splatted and non-splatted function have the same structure?
335 // For now, we require splatting to match exactly.
336 if a_sig.splatted() != b_sig.splatted() {
337 return false;
338 }
339
332340 (a_sig.abi(), a_sig.safety(), a_sig.c_variadic())
333341 == (b_sig.abi(), b_sig.safety(), b_sig.c_variadic())
334342 && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs+6-6
......@@ -556,15 +556,15 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
556556 )
557557 },
558558 crates: |tcx, ()| {
559 // The list of loaded crates is now frozen in query cache,
560 // so make sure cstore is not mutably accessed from here on.
561 tcx.untracked().cstore.freeze();
559 // The loaded-crate list is now frozen in the query cache; stop
560 // mutating the cstore and stable crate id map from here on.
561 tcx.untracked().freeze_cstore();
562562 tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum))
563563 },
564564 used_crates: |tcx, ()| {
565 // The list of loaded crates is now frozen in query cache,
566 // so make sure cstore is not mutably accessed from here on.
567 tcx.untracked().cstore.freeze();
565 // The loaded-crate list is now frozen in the query cache; stop
566 // mutating the cstore and stable crate id map from here on.
567 tcx.untracked().freeze_cstore();
568568 tcx.arena.alloc_from_iter(
569569 CStore::from_tcx(tcx)
570570 .iter_crate_data()
compiler/rustc_middle/src/ty/context.rs+2
......@@ -2085,6 +2085,8 @@ impl<'tcx> TyCtxt<'tcx> {
20852085 ty::Tuple(params) => *params,
20862086 _ => bug!(),
20872087 };
2088 // Ignore splatting, it is unsupported on closures.
2089 assert!(s.splatted().is_none());
20882090 self.mk_fn_sig(
20892091 params,
20902092 s.output(),
compiler/rustc_middle/src/ty/error.rs+14
......@@ -96,6 +96,20 @@ impl<'tcx> TypeError<'tcx> {
9696 if values.found { "variadic" } else { "non-variadic" }
9797 )
9898 .into(),
99 TypeError::SplatMismatch(ref values) => format!(
100 "expected fn with {}, found fn with {}",
101 if let Some(index) = values.expected {
102 format!("arg {index} splatted")
103 } else {
104 "no splatted arg".to_string()
105 },
106 if let Some(index) = values.found {
107 format!("arg {index} splatted")
108 } else {
109 "no splatted arg".to_string()
110 }
111 )
112 .into(),
99113 TypeError::ProjectionMismatched(ref values) => format!(
100114 "expected `{}`, found `{}`",
101115 tcx.alias_term_kind_def_path_str(values.expected),
compiler/rustc_middle/src/ty/mod.rs+2-1
......@@ -113,7 +113,8 @@ pub use self::sty::{
113113pub use self::trait_def::TraitDef;
114114pub use self::typeck_results::{
115115 CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
116 Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
116 Rust2024IncompatiblePatInfo, SplattedDef, TypeckResults, UserType, UserTypeAnnotationIndex,
117 UserTypeKind,
117118};
118119use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
119120use crate::metadata::{AmbigModChild, ModChild};
compiler/rustc_middle/src/ty/print/pretty.rs+13-2
......@@ -1435,6 +1435,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
14351435 p.pretty_print_fn_sig(
14361436 tys,
14371437 false,
1438 // FIXME(splat): support splatted arguments here?
1439 None,
14381440 proj.skip_binder().term.as_type().expect("Return type was a const"),
14391441 )?;
14401442 resugared = true;
......@@ -1538,10 +1540,19 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
15381540 &mut self,
15391541 inputs: &[Ty<'tcx>],
15401542 c_variadic: bool,
1543 splatted: Option<u8>,
15411544 output: Ty<'tcx>,
15421545 ) -> Result<(), PrintError> {
15431546 write!(self, "(")?;
1544 self.comma_sep(inputs.iter().copied())?;
1547 let splatted_arg_index = splatted.map(usize::from);
1548 let mut input_iter = inputs.iter().copied();
1549 if let Some(index) = splatted_arg_index {
1550 self.comma_sep((&mut input_iter).take(usize::from(index)))?;
1551 write!(self, ", #[splat]")?;
1552 self.comma_sep(input_iter)?;
1553 } else {
1554 self.comma_sep(input_iter)?;
1555 }
15451556 if c_variadic {
15461557 if !inputs.is_empty() {
15471558 write!(self, ", ")?;
......@@ -3150,7 +3161,7 @@ define_print! {
31503161 }
31513162
31523163 write!(p, "fn")?;
3153 p.pretty_print_fn_sig(self.inputs(), self.c_variadic(), self.output())?;
3164 p.pretty_print_fn_sig(self.inputs(), self.c_variadic(), self.splatted(), self.output())?;
31543165 }
31553166
31563167 ty::TraitRef<'tcx> {
compiler/rustc_middle/src/ty/typeck_results.rs+35
......@@ -36,6 +36,9 @@ pub struct TypeckResults<'tcx> {
3636 /// method calls, including those of overloaded operators.
3737 type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
3838
39 /// Resolved definitions for splatted function calls.
40 splatted_defs: ItemLocalMap<Result<SplattedDef, ErrorGuaranteed>>,
41
3942 /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
4043 /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
4144 /// about the field you also need definition of the variant to which the field
......@@ -229,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> {
229232 TypeckResults {
230233 hir_owner,
231234 type_dependent_defs: Default::default(),
235 splatted_defs: Default::default(),
232236 field_indices: Default::default(),
233237 user_provided_types: Default::default(),
234238 user_provided_sigs: Default::default(),
......@@ -287,6 +291,21 @@ impl<'tcx> TypeckResults<'tcx> {
287291 LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
288292 }
289293
294 pub fn splatted_defs(&self) -> LocalTableInContext<'_, Result<SplattedDef, ErrorGuaranteed>> {
295 LocalTableInContext { hir_owner: self.hir_owner, data: &self.splatted_defs }
296 }
297
298 pub fn splatted_def(&self, id: HirId) -> Option<SplattedDef> {
299 validate_hir_id_for_typeck_results(self.hir_owner, id);
300 self.splatted_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
301 }
302
303 pub fn splatted_defs_mut(
304 &mut self,
305 ) -> LocalTableInContextMut<'_, Result<SplattedDef, ErrorGuaranteed>> {
306 LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.splatted_defs }
307 }
308
290309 pub fn field_indices(&self) -> LocalTableInContext<'_, FieldIdx> {
291310 LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
292311 }
......@@ -407,6 +426,10 @@ impl<'tcx> TypeckResults<'tcx> {
407426 matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
408427 }
409428
429 pub fn is_splatted_call(&self, expr: &hir::Expr<'_>) -> bool {
430 matches!(self.splatted_defs().get(expr.hir_id), Some(Ok(SplattedDef { .. })))
431 }
432
410433 /// Returns the computed binding mode for a `PatKind::Binding` pattern
411434 /// (after match ergonomics adjustments).
412435 pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> BindingMode {
......@@ -569,6 +592,18 @@ impl<'tcx> TypeckResults<'tcx> {
569592 }
570593}
571594
595/// A resolved splatted function call.
596#[derive(Debug, Copy, Clone, PartialEq, Eq, StableHash, TyEncodable, TyDecodable)]
597pub struct SplattedDef {
598 /// The function DefId, if available (FnPtrs don't have DefIds)
599 pub def_id: Option<DefId>,
600 /// The index of the first argument in the callee's splatted tuple, and the index of the
601 /// splatted tuple argument in the caller.
602 pub arg_index: u16,
603 /// The number of arguments in the splatted tuple.
604 pub arg_count: u16,
605}
606
572607/// Validate that the given HirId (respectively its `local_id` part) can be
573608/// safely used as a key in the maps of a TypeckResults. For that to be
574609/// the case, the HirId must have the same `owner` as all the other IDs in
compiler/rustc_mir_build/src/builder/mod.rs+1
......@@ -547,6 +547,7 @@ fn construct_fn<'tcx>(
547547
548548 body.spread_arg = if abi == ExternAbi::RustCall {
549549 // RustCall pseudo-ABI untuples the last argument.
550 // FIXME(splat): splat can untuple any argument, set spread_arg here
550551 Some(Local::new(arguments.len()))
551552 } else {
552553 None
compiler/rustc_mir_build/src/thir/cx/expr.rs+136-15
......@@ -18,8 +18,8 @@ use rustc_middle::ty::adjustment::{
1818 Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, DerefAdjustKind, PointerCoercion,
1919};
2020use rustc_middle::ty::{
21 self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, TyCtxt,
22 UpvarArgs,
21 self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, SplattedDef, Ty,
22 TyCtxt, UpvarArgs,
2323};
2424use rustc_middle::{bug, span_bug};
2525use rustc_span::{DesugaringKind, Span};
......@@ -369,19 +369,26 @@ impl<'tcx> ThirBuildCx<'tcx> {
369369 let kind = match expr.kind {
370370 // Here comes the interesting stuff:
371371 hir::ExprKind::MethodCall(segment, receiver, args, fn_span) => {
372 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
373 let expr = self.method_callee(expr, segment.ident.span, None);
374 info!("Using method span: {:?}", expr.span);
375 let args = std::iter::once(receiver)
376 .chain(args.iter())
377 .map(|expr| self.mirror_expr(expr))
378 .collect();
379 ExprKind::Call {
380 ty: expr.ty,
381 fun: self.thir.exprs.push(expr),
382 args,
383 from_hir_call: true,
384 fn_span,
372 if self.typeck_results.is_splatted_call(expr) {
373 // The callee has a splatted tuple argument.
374 // rewrite `receiver.f(a, u, v)` into `receiver.f(a, #[splat] (u, v))`
375 self.convert_splatted_callee(expr, fn_span, args, Some(receiver))
376 } else {
377 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
378 let expr = self.method_callee(expr, segment.ident.span, None);
379 info!("Using method span: {:?}", expr.span);
380
381 let args = std::iter::once(receiver)
382 .chain(args.iter())
383 .map(|expr| self.mirror_expr(expr))
384 .collect();
385 ExprKind::Call {
386 ty: expr.ty,
387 fun: self.thir.exprs.push(expr),
388 args,
389 from_hir_call: true,
390 fn_span,
391 }
385392 }
386393 }
387394
......@@ -412,6 +419,10 @@ impl<'tcx> ThirBuildCx<'tcx> {
412419 from_hir_call: true,
413420 fn_span: expr.span,
414421 }
422 } else if self.typeck_results.is_splatted_call(expr) {
423 // The callee has a splatted tuple argument.
424 // rewrite `f(a, u, v)` into `f(a, #[splat] (u, v))`
425 self.convert_splatted_callee(expr, fun.span, args, None)
415426 } else {
416427 // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
417428 let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind
......@@ -1205,6 +1216,116 @@ impl<'tcx> ThirBuildCx<'tcx> {
12051216 }
12061217 }
12071218
1219 fn splatted_callee(
1220 &mut self,
1221 expr: &hir::Expr<'_>,
1222 span: Span,
1223 ) -> (Expr<'tcx>, u16 /* arg_index */, u16 /* arg_count */) {
1224 let SplattedDef { def_id, arg_index, arg_count } =
1225 self.typeck_results.splatted_def(expr.hir_id).unwrap_or_else(|| {
1226 span_bug!(expr.span, "no splatted def for function or method callee")
1227 });
1228 let def_id = def_id.unwrap_or_else(|| {
1229 span_bug!(expr.span, "no splatted def for function or method callee")
1230 });
1231 let def_kind = self.tcx.def_kind(def_id);
1232 let user_ty = self.user_args_applied_to_res(expr.hir_id, Res::Def(def_kind, def_id));
1233 debug!(
1234 "splatted_callee: user_ty={:?} def_kind={:?} def_id={:?} arg_index={:?} arg_count={:?}",
1235 user_ty, def_kind, def_id, arg_index, arg_count
1236 );
1237
1238 (
1239 Expr {
1240 temp_scope_id: expr.hir_id.local_id,
1241 ty: Ty::new_fn_def(self.tcx, def_id, self.typeck_results.node_args(expr.hir_id)),
1242 span,
1243 kind: ExprKind::ZstLiteral { user_ty },
1244 },
1245 arg_index,
1246 arg_count,
1247 )
1248 }
1249
1250 /// The callee has a splatted tuple argument.
1251 /// Rewrite a splatted call `receiver.f(a, u, v)` into `receiver.f(a, #[splat] (u, v))`.
1252 /// The receiver is optional.
1253 fn convert_splatted_callee(
1254 &mut self,
1255 expr: &hir::Expr<'_>,
1256 fn_span: Span,
1257 args: &'tcx [hir::Expr<'tcx>],
1258 receiver: Option<&'tcx hir::Expr<'tcx>>,
1259 ) -> ExprKind<'tcx> {
1260 let tcx = self.tcx;
1261
1262 // The callee has a splatted tuple argument.
1263 let (func, tupled_arg_index, tupled_args_count) = self.splatted_callee(expr, fn_span);
1264 let tupled_arg_index = usize::from(tupled_arg_index);
1265 let tupled_args_count = usize::from(tupled_args_count);
1266
1267 // Splatting an empty tuple is permitted: `a.f() -> Trait::f(a, #[splat] ())`.
1268 // In that case, the tupled arg index is one past the end of the args.
1269 if tupled_arg_index + tupled_args_count > args.len() {
1270 span_bug!(
1271 expr.span,
1272 "splatted arg index out of bounds of function args: {:?} + {:?} > {:?} for function call: receiver {:?}, args {:?}",
1273 tupled_arg_index,
1274 tupled_args_count,
1275 args.len(),
1276 receiver,
1277 args,
1278 );
1279 }
1280
1281 info!("Using splatted function span: {:?}", func.span);
1282
1283 // Split into non-tupled and tupled arguments
1284 let initial_non_tupled_args =
1285 args.iter().take(tupled_arg_index).map(|e| self.mirror_expr(e)).collect_vec();
1286 let tupled_args = if tupled_arg_index == args.len() || tupled_args_count == 0 {
1287 // Splatting an empty tuple, in the ABI this gets ignored
1288 Default::default()
1289 } else {
1290 &args[tupled_arg_index..(tupled_arg_index + tupled_args_count)]
1291 };
1292 let final_non_tupled_args = args
1293 .iter()
1294 .skip(tupled_arg_index + tupled_args_count)
1295 .map(|e| self.mirror_expr(e))
1296 .collect_vec();
1297
1298 let tupled_arg_tys = tupled_args.iter().map(|e| self.typeck_results.expr_ty_adjusted(e));
1299
1300 let temp_scope_id =
1301 if receiver.is_some() { func.temp_scope_id } else { expr.hir_id.local_id };
1302 let tupled_args = Expr {
1303 ty: Ty::new_tup_from_iter(tcx, tupled_arg_tys),
1304 temp_scope_id,
1305 span: expr.span,
1306 kind: ExprKind::Tuple { fields: self.mirror_exprs(tupled_args) },
1307 };
1308
1309 let tupled_args = self.thir.exprs.push(tupled_args);
1310
1311 let mut args =
1312 if let Some(receiver) = receiver { vec![self.mirror_expr(receiver)] } else { vec![] };
1313 args.extend(initial_non_tupled_args);
1314 args.push(tupled_args);
1315 args.extend(final_non_tupled_args);
1316
1317 // We need the tupled arguments in HIR/MIR for type checking, but codegen can
1318 // de-tuple them for performance
1319 let fn_span = if receiver.is_some() { func.span } else { expr.span };
1320 ExprKind::Call {
1321 ty: func.ty,
1322 fun: self.thir.exprs.push(func),
1323 args: args.into_boxed_slice(),
1324 from_hir_call: true,
1325 fn_span,
1326 }
1327 }
1328
12081329 fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
12091330 let arm = Arm {
12101331 pattern: self.pattern_from_hir(&arm.pat),
compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs+3-3
......@@ -462,7 +462,7 @@ where
462462 Ok(i) => Ok(i),
463463 Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution),
464464 Err(NoSolutionOrRerunNonErased::RerunNonErased(_)) => {
465 // check th t the opaque_accesses state mirrors the result we got.
465 // Check that the opaque_accesses state mirrors the result we got.
466466 assert!(opaque_accesses.should_bail().is_err());
467467 Err(NoSolution)
468468 }
......@@ -1442,7 +1442,7 @@ where
14421442 uv: ty::UnevaluatedConst<I>,
14431443 ) -> Result<Option<I::Const>, RerunNonErased> {
14441444 if self.typing_mode().is_erased_not_coherence() {
1445 self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)?;
1445 match self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)? {}
14461446 }
14471447
14481448 Ok(self.delegate.evaluate_const(param_env, uv))
......@@ -1515,7 +1515,7 @@ where
15151515 symbol: I::Symbol,
15161516 ) -> Result<bool, RerunNonErased> {
15171517 if self.typing_mode().is_erased_not_coherence() {
1518 self.opaque_accesses.rerun_always(RerunReason::MayUseUnstableFeature)?;
1518 match self.opaque_accesses.rerun_always(RerunReason::MayUseUnstableFeature)? {}
15191519 }
15201520
15211521 Ok(may_use_unstable_feature(&**self.delegate, param_env, symbol))
compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs+2-4
......@@ -98,10 +98,8 @@ where
9898
9999 outer.opaque_accesses.update(nested.opaque_accesses)?;
100100
101 let r = match r.map_err_to_rerun()? {
102 Ok(i) => Ok(i),
103 Err(NoSolution) => Err(NoSolution),
104 };
101 // Unwrap is unreachable, we would have returned on the line above.
102 let r = r.map_err_to_rerun().unwrap();
105103
106104 if !nested.inspect.is_noop() {
107105 let probe_kind = probe_kind(&r);
compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs+18-32
......@@ -81,15 +81,10 @@ where
8181 None
8282 },
8383 |ecx| {
84 ecx.probe(|&result| ProbeKind::RigidAlias { result })
85 .enter(|this| {
86 this.structurally_instantiate_normalizes_to_term(
87 goal,
88 goal.predicate.alias,
89 );
90 this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
91 })
92 .map_err(Into::into)
84 ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
85 this.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
86 this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
87 })
9388 },
9489 )
9590 }
......@@ -351,11 +346,9 @@ where
351346 GoalSource::Misc,
352347 goal.with(cx, PredicateKind::Ambiguous),
353348 )?;
354 return ecx
355 .evaluate_added_goals_and_make_canonical_response(
356 Certainty::Yes,
357 )
358 .map_err(Into::into);
349 return ecx.evaluate_added_goals_and_make_canonical_response(
350 Certainty::Yes,
351 );
359352 }
360353 // Outside of coherence, we treat the associated item as rigid instead.
361354 ty::TypingMode::Typeck { .. }
......@@ -367,11 +360,9 @@ where
367360 goal,
368361 goal.predicate.alias,
369362 );
370 return ecx
371 .evaluate_added_goals_and_make_canonical_response(
372 Certainty::Yes,
373 )
374 .map_err(Into::into);
363 return ecx.evaluate_added_goals_and_make_canonical_response(
364 Certainty::Yes,
365 );
375366 }
376367 };
377368 }
......@@ -401,10 +392,10 @@ where
401392 // This is not the case here and we only prefer adding an ambiguous
402393 // nested goal for consistency.
403394 ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous))?;
404 return then(ecx, Certainty::Yes).map_err(Into::into);
395 return then(ecx, Certainty::Yes);
405396 } else {
406397 ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
407 return then(ecx, Certainty::Yes).map_err(Into::into);
398 return then(ecx, Certainty::Yes);
408399 }
409400 } else {
410401 return error_response(ecx, cx.delay_bug("missing item"));
......@@ -472,7 +463,7 @@ where
472463 };
473464
474465 ecx.instantiate_normalizes_to_term(goal, term)?;
475 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes).map_err(Into::into)
466 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
476467 })
477468 }
478469
......@@ -572,7 +563,6 @@ where
572563 pred,
573564 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
574565 )
575 .map_err(Into::into)
576566 }
577567
578568 fn consider_builtin_async_fn_trait_candidates(
......@@ -759,8 +749,9 @@ where
759749 // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
760750 // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
761751 // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
762 let alias_bound_result =
763 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
752 let alias_bound_result = ecx
753 .probe_builtin_trait_candidate(BuiltinImplSource::Misc)
754 .enter(|ecx| {
764755 let sized_predicate = ty::TraitRef::new(
765756 cx,
766757 cx.require_trait_lang_item(SolverTraitLangItem::Sized),
......@@ -769,12 +760,8 @@ where
769760 ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate))?;
770761 ecx.instantiate_normalizes_to_term(goal, Ty::new_unit(cx).into())?;
771762 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
772 });
773
774 let alias_bound_result = match alias_bound_result.map_err_to_rerun()? {
775 Ok(i) => Ok(i),
776 Err(NoSolution) => Err(NoSolution),
777 };
763 })
764 .map_err_to_rerun()?;
778765
779766 // In case the dummy alias-bound candidate does not apply, we instead treat this projection
780767 // as rigid.
......@@ -900,7 +887,6 @@ where
900887 // but that's already proven by the generator being WF.
901888 [],
902889 )
903 .map_err(Into::into)
904890 }
905891
906892 fn consider_builtin_fused_iterator_candidate(
compiler/rustc_next_trait_solver/src/solve/search_graph.rs+3-12
......@@ -4,7 +4,7 @@ use std::marker::PhantomData;
44use rustc_type_ir::data_structures::ensure_sufficient_stack;
55use rustc_type_ir::search_graph::{self, PathKind};
66use rustc_type_ir::solve::{
7 AccessedOpaques, CanonicalInput, Certainty, NoSolution, NoSolutionOrRerunNonErased, QueryResult,
7 AccessedOpaques, CanonicalInput, Certainty, NoSolution, QueryResult, RerunResultExt,
88};
99use rustc_type_ir::{Interner, MayBeErased, TypingMode};
1010
......@@ -141,17 +141,8 @@ where
141141 ) -> (QueryResult<I>, AccessedOpaques<I>) {
142142 ensure_sufficient_stack(|| {
143143 EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| {
144 let result = ecx.compute_goal(goal);
145
146 // if we're in `RerunNonErased`, don't even bother with inspect,
147 // and immediately return
148 let result = match result {
149 Ok(i) => Ok(i),
150 Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution),
151 Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => {
152 return Err(e.into());
153 }
154 };
144 // if we're in `RerunNonErased`, don't even bother with inspect, and immediately return
145 let result = ecx.compute_goal(goal).map_err_to_rerun()?;
155146
156147 ecx.inspect.query_result(result);
157148 result.map_err(Into::into)
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+6-11
......@@ -119,7 +119,7 @@ where
119119 .map(|pred| goal.with(cx, pred)),
120120 )?;
121121
122 then(ecx, maximal_certainty).map_err(Into::into)
122 then(ecx, maximal_certainty)
123123 })
124124 }
125125
......@@ -399,7 +399,6 @@ where
399399 pred,
400400 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
401401 )
402 .map_err(Into::into)
403402 }
404403
405404 fn consider_builtin_async_fn_trait_candidates(
......@@ -450,7 +449,6 @@ where
450449 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
451450 .map(|goal| (GoalSource::ImplWhereBound, goal)),
452451 )
453 .map_err(Into::into)
454452 }
455453
456454 fn consider_builtin_async_fn_kind_helper_candidate(
......@@ -696,7 +694,7 @@ where
696694 goal.predicate.trait_ref.args.type_at(1),
697695 assume,
698696 )?;
699 ecx.evaluate_added_goals_and_make_canonical_response(certainty).map_err(Into::into)
697 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
700698 },
701699 )
702700 }
......@@ -1085,7 +1083,6 @@ where
10851083 ecx.try_evaluate_added_goals()
10861084 },
10871085 )
1088 .map_err(Into::into)
10891086 })
10901087 .is_ok()
10911088 };
......@@ -1124,11 +1121,9 @@ where
11241121 return Err(NoSolution.into());
11251122 };
11261123 if matching_projections.next().is_some() {
1127 return ecx
1128 .evaluate_added_goals_and_make_canonical_response(
1129 Certainty::AMBIGUOUS,
1130 )
1131 .map_err(Into::into);
1124 return ecx.evaluate_added_goals_and_make_canonical_response(
1125 Certainty::AMBIGUOUS,
1126 );
11321127 }
11331128 ecx.enter_forall_with_assumptions(
11341129 target_projection,
......@@ -1156,7 +1151,7 @@ where
11561151 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
11571152 )?;
11581153
1159 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes).map_err(Into::into)
1154 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
11601155 })
11611156 }
11621157
compiler/rustc_parse/src/parser/diagnostics.rs+3-1
......@@ -602,7 +602,9 @@ impl<'a> Parser<'a> {
602602 // Look for usages of '=>' where '>=' was probably intended
603603 if self.token == token::FatArrow
604604 && expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le))
605 && !expected.iter().any(|tok| matches!(tok, TokenType::FatArrow | TokenType::Comma))
605 && !expected
606 .iter()
607 .any(|tok| matches!(tok, TokenType::FatArrow | TokenType::CloseBrace))
606608 {
607609 err.span_suggestion(
608610 self.token.span,
compiler/rustc_passes/src/check_attr.rs+1-8
......@@ -220,7 +220,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
220220 AttributeKind::NonExhaustive(attr_span) => {
221221 self.check_non_exhaustive(*attr_span, span, target, item)
222222 }
223 &AttributeKind::FfiPure(attr_span) => self.check_ffi_pure(attr_span, attrs),
224223 AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span),
225224 AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target),
226225 AttributeKind::MacroExport { span, .. } => {
......@@ -272,6 +271,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
272271 AttributeKind::ExportStable => (),
273272 AttributeKind::Feature(..) => (),
274273 AttributeKind::FfiConst => (),
274 AttributeKind::FfiPure(..) => (),
275275 AttributeKind::Fundamental => (),
276276 AttributeKind::Ignore { .. } => (),
277277 AttributeKind::InstructionSet(..) => (),
......@@ -1113,13 +1113,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
11131113 }
11141114 }
11151115
1116 fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute]) {
1117 if find_attr!(attrs, FfiConst) {
1118 // `#[ffi_const]` functions cannot be `#[ffi_pure]`
1119 self.dcx().emit_err(diagnostics::BothFfiConstAndPure { attr_span });
1120 }
1121 }
1122
11231116 /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl.
11241117 fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) {
11251118 let hir::Node::GenericParam(
compiler/rustc_passes/src/diagnostics.rs-7
......@@ -152,13 +152,6 @@ pub(crate) struct DocMaskedNotExternCrateSelf {
152152 pub item_span: Span,
153153}
154154
155#[derive(Diagnostic)]
156#[diag("`#[ffi_const]` function cannot be `#[ffi_pure]`", code = E0757)]
157pub(crate) struct BothFfiConstAndPure {
158 #[primary_span]
159 pub attr_span: Span,
160}
161
162155#[derive(Diagnostic)]
163156#[diag("`#[optimize(none)]` cannot be used with `#[inline]` attributes")]
164157pub(crate) struct BothOptimizeNoneAndInline {
compiler/rustc_public/src/unstable/convert/internal.rs+1
......@@ -312,6 +312,7 @@ impl RustcInternal for FnSig {
312312 tables: &mut Tables<'_, BridgeTys>,
313313 tcx: impl InternalCx<'tcx>,
314314 ) -> Self::T<'tcx> {
315 // FIXME(splat): When `#[splat]` is complete (or stable), add splatted to the public FnSig
315316 let fn_sig_kind = rustc_ty::FnSigKind::default()
316317 .set_abi(self.abi.internal(tables, tcx))
317318 .set_safety(self.safety.internal(tables, tcx))
compiler/rustc_resolve/src/lib.rs+2-2
......@@ -2091,8 +2091,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
20912091 .time("resolve_postprocess", || self.cstore_mut().postprocess(self.tcx, krate));
20922092 });
20932093
2094 // Make sure we don't mutate the cstore from here on.
2095 self.tcx.untracked().cstore.freeze();
2094 // Don't mutate the cstore or stable crate id map from here on.
2095 self.tcx.untracked().freeze_cstore();
20962096 }
20972097
20982098 fn traits_in_scope(
compiler/rustc_session/src/cstore.rs+10
......@@ -224,3 +224,13 @@ pub struct Untracked {
224224 /// The interned [StableCrateId]s.
225225 pub stable_crate_ids: FreezeLock<StableCrateIdMap>,
226226}
227
228impl Untracked {
229 /// Freezes the cstore and, with it, the `StableCrateId` map, making reads of
230 /// both lock-free. The cstore is frozen first so any in-flight crate loading
231 /// (which writes the map) finishes before the map is frozen.
232 pub fn freeze_cstore(&self) {
233 self.cstore.freeze();
234 self.stable_crate_ids.freeze();
235 }
236}
compiler/rustc_span/src/symbol.rs+2
......@@ -1142,6 +1142,7 @@ symbols! {
11421142 irrefutable_let_patterns,
11431143 is,
11441144 is_auto,
1145 is_splatted,
11451146 is_val_statically_known,
11461147 isa_attribute,
11471148 isize,
......@@ -2001,6 +2002,7 @@ symbols! {
20012002 speed,
20022003 spirv,
20032004 splat,
2005 splatted_index,
20042006 spotlight,
20052007 sqrtf16,
20062008 sqrtf32,
compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs+10
......@@ -823,9 +823,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
823823 // ^^^^^
824824 let len1 = sig1.inputs().len();
825825 let len2 = sig2.inputs().len();
826 let splatted_arg_index1 = sig1.splatted().map(usize::from);
827 let splatted_arg_index2 = sig2.splatted().map(usize::from);
826828 if len1 == len2 {
827829 for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
828830 self.push_comma(&mut values.0, &mut values.1, i);
831 if Some(i) == splatted_arg_index1 {
832 values.0.push("#[splat]", splatted_arg_index1 != splatted_arg_index2);
833 values.0.push_normal(" ");
834 }
835 if Some(i) == splatted_arg_index2 {
836 values.1.push("#[splat]", splatted_arg_index1 != splatted_arg_index2);
837 values.1.push_normal(" ");
838 }
829839 let (x1, x2) = self.cmp(*l, *r);
830840 (values.0).0.extend(x1.0);
831841 (values.1).0.extend(x2.0);
compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs+1
......@@ -4962,6 +4962,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
49624962 && let fn_sig @ ty::FnSig {
49634963 ..
49644964 } = fn_ty.fn_sig(tcx).skip_binder()
4965 // FIXME(splat): this might need to change if the Fn* traits start using/supporting splat
49654966 && fn_sig.abi() == ExternAbi::Rust
49664967 && !fn_sig.c_variadic()
49674968 && fn_sig.safety() == hir::Safety::Safe
compiler/rustc_ty_utils/src/opaque_types.rs+12-7
......@@ -317,6 +317,9 @@ fn opaque_types_defined_by<'tcx>(
317317 tcx: TyCtxt<'tcx>,
318318 item: LocalDefId,
319319) -> &'tcx ty::List<LocalDefId> {
320 if tcx.is_typeck_child(item.to_def_id()) {
321 return tcx.opaque_types_defined_by(tcx.local_parent(item));
322 }
320323 let kind = tcx.def_kind(item);
321324 trace!(?kind);
322325 let mut collector = OpaqueTypeCollector::new(tcx, item);
......@@ -332,13 +335,6 @@ fn opaque_types_defined_by<'tcx>(
332335 | DefKind::AnonConst => {
333336 collector.collect_taits_declared_in_body();
334337 }
335 // Closures and coroutines are type checked with their parent
336 // Note that we also support `SyntheticCoroutineBody` since we create
337 // a MIR body for the def kind, and some MIR passes (like promotion)
338 // may require doing analysis using its typing env.
339 DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody => {
340 collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item)));
341 }
342338 DefKind::AssocTy | DefKind::TyAlias | DefKind::GlobalAsm => {}
343339 DefKind::OpaqueTy
344340 | DefKind::Mod
......@@ -349,6 +345,15 @@ fn opaque_types_defined_by<'tcx>(
349345 | DefKind::Trait
350346 | DefKind::ForeignTy
351347 | DefKind::TraitAlias
348
349 // Closures and coroutines are type checked with their parent
350 // Note that we also support `SyntheticCoroutineBody` since we create
351 // a MIR body for the def kind, and some MIR passes (like promotion)
352 // may require doing analysis using its typing env.
353 | DefKind::Closure
354 | DefKind::InlineConst
355 | DefKind::SyntheticCoroutineBody
356
352357 | DefKind::TyParam
353358 | DefKind::ConstParam
354359 | DefKind::Ctor(_, _)
compiler/rustc_ty_utils/src/ty.rs+3
......@@ -149,6 +149,9 @@ fn adt_sizedness_constraint<'tcx>(
149149
150150/// See `ParamEnv` struct definition for details.
151151fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
152 if tcx.is_typeck_child(def_id) {
153 return tcx.param_env(tcx.typeck_root_def_id(def_id));
154 }
152155 // Compute the bounds on Self and the type parameters.
153156 let ty::InstantiatedPredicates { predicates, .. } =
154157 tcx.predicates_of(def_id).instantiate_identity(tcx);
compiler/rustc_type_ir/src/error.rs+2-1
......@@ -41,6 +41,7 @@ pub enum TypeError<I: Interner> {
4141 ArgumentSorts(ExpectedFound<I::Ty>, usize),
4242 Traits(ExpectedFound<I::TraitId>),
4343 VariadicMismatch(ExpectedFound<bool>),
44 SplatMismatch(ExpectedFound<Option<u8>>),
4445
4546 /// Instantiating a type variable with the given type would have
4647 /// created a cycle (because it appears somewhere within that
......@@ -76,7 +77,7 @@ impl<I: Interner> TypeError<I> {
7677 match self {
7778 CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch
7879 | AbiMismatch(_) | ArraySize(_) | ArgumentSorts(..) | Sorts(_)
79 | VariadicMismatch(_) | TargetFeatureCast(_) => false,
80 | VariadicMismatch(_) | SplatMismatch(_) | TargetFeatureCast(_) => false,
8081
8182 Mutability
8283 | ArgumentMutability(_)
compiler/rustc_type_ir/src/fast_reject.rs+16-7
......@@ -256,13 +256,12 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
256256 match rhs.kind() {
257257 // Start by checking whether the `rhs` type may unify with
258258 // pretty much everything. Just return `true` in that case.
259 ty::Param(_) => {
259 ty::Param(_) | ty::Alias(ty::IsRigid::Yes, _) => {
260260 if INSTANTIATE_RHS_WITH_INFER {
261261 return true;
262262 }
263263 }
264 // FIXME(#155345): we should fast-path for rigid aliases here.
265 ty::Error(_) | ty::Alias(..) | ty::Bound(..) => return true,
264 ty::Error(_) | ty::Alias(ty::IsRigid::No, _) | ty::Bound(..) => return true,
266265 ty::Infer(var) => return self.var_and_ty_may_unify(var, lhs),
267266
268267 // These types only unify with inference variables or their own
......@@ -339,12 +338,22 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
339338
340339 ty::Infer(var) => self.var_and_ty_may_unify(var, rhs),
341340
341 // Since we ensure that the rhs is not non-rigid alias,
342 // lhs rigid alias can only unify with it if it's a rigid alias of the same kind.
343 ty::Alias(ty::IsRigid::Yes, lhs_alias) => {
344 INSTANTIATE_LHS_WITH_INFER
345 || match rhs.kind() {
346 ty::Alias(ty::IsRigid::Yes, rhs_alias) => {
347 lhs_alias.kind == rhs_alias.kind
348 && self.args_may_unify_inner(lhs_alias.args, rhs_alias.args, depth)
349 }
350 _ => false,
351 }
352 }
342353 // As we're walking the whole type, it may encounter projections
343354 // inside of binders and what not, so we're just going to assume that
344 // projections can unify with other stuff.
345 //
346 // Looking forward to lazy normalization this is the safer strategy anyways.
347 ty::Alias(..) => true,
355 // non-rigid alias can unify with anything.
356 ty::Alias(ty::IsRigid::No, _) => true,
348357
349358 ty::Int(_)
350359 | ty::Uint(_)
compiler/rustc_type_ir/src/macros.rs+1
......@@ -45,6 +45,7 @@ TrivialTypeTraversalImpls! {
4545 (),
4646 bool,
4747 usize,
48 u8,
4849 u16,
4950 u32,
5051 u64,
compiler/rustc_type_ir/src/relate.rs+4
......@@ -169,6 +169,10 @@ impl<I: Interner> Relate<I> for ty::FnSig<I> {
169169 return Err(TypeError::AbiMismatch(ExpectedFound::new(a.abi(), b.abi())));
170170 };
171171
172 if a.splatted() != b.splatted() {
173 return Err(TypeError::SplatMismatch(ExpectedFound::new(a.splatted(), b.splatted())));
174 }
175
172176 let a_inputs = a.inputs();
173177 let b_inputs = b.inputs();
174178 if a_inputs.len() != b_inputs.len() {
compiler/rustc_type_ir/src/ty_kind.rs+135-20
......@@ -888,8 +888,19 @@ pub struct TypeAndMut<I: Interner> {
888888
889889impl<I: Interner> Eq for TypeAndMut<I> {}
890890
891/// Error type for splatted argument index errors.
892#[derive(Debug, Clone, Copy, PartialEq, Eq)]
893pub enum SplattedArgIndexError {
894 /// The splatted argument index is invalid.
895 /// A `u8::MAX` argument index used to indicate that no argument is splatted.
896 /// Higher values are also not supported, for performance reasons.
897 InvalidIndex { splatted_arg_index: u8 },
898
899 /// The splatted argument index is outside the bounds of the function arguments.
900 OutOfBounds { splatted_arg_index: u8, args_len: u16 },
901}
902
891903/// Contains the packed non-type fields of a function signature.
892// FIXME(splat): add the splatted argument index as a u16
893904#[derive_where(Copy, Clone, PartialEq, Eq, Hash; I: Interner)]
894905#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
895906#[cfg_attr(
......@@ -903,6 +914,15 @@ pub struct FnSigKind<I: Interner> {
903914 #[type_visitable(ignore)]
904915 #[type_foldable(identity)]
905916 flags: u8,
917
918 /// Which function argument is splatted into multiple arguments in callers, if any?
919 /// Splatting functions with `>= u8::MAX` arguments is not supported, for performance reasons.
920 /// (And spending an extra byte on an edge case is not worth the perf.)
921 #[lift(identity)]
922 #[type_visitable(ignore)]
923 #[type_foldable(identity)]
924 splatted: u8,
925
906926 #[type_visitable(ignore)]
907927 #[type_foldable(identity)]
908928 _marker: PhantomData<fn() -> I>,
......@@ -922,12 +942,28 @@ impl<I: Interner> fmt::Debug for FnSigKind<I> {
922942
923943 if self.c_variadic() {
924944 f.field(&"CVariadic");
925 };
945 }
946
947 if let Some(index) = self.splatted() {
948 f.field(&format!("Splatted({})", index));
949 }
926950
927951 f.finish()
928952 }
929953}
930954
955impl<I: Interner> Default for FnSigKind<I> {
956 /// Create a new FnSigKind with the "Rust" ABI, "Unsafe" safety, and no C-style variadic or splatted arguments.
957 /// To modify these flags, use the `set_*` methods, for readability.
958 fn default() -> Self {
959 Self { flags: 0, splatted: 0, _marker: PhantomData }
960 .set_abi(ExternAbi::Rust)
961 .set_safety(I::Safety::unsafe_mode())
962 .set_c_variadic(false)
963 .set_no_splatted_args()
964 }
965}
966
931967impl<I: Interner> FnSigKind<I> {
932968 /// Mask for the `ExternAbi` variant, including the unwind flag.
933969 const EXTERN_ABI_MASK: u8 = 0b111111;
......@@ -938,19 +974,34 @@ impl<I: Interner> FnSigKind<I> {
938974 /// Bitflag for a trailing C-style variadic argument.
939975 const C_VARIADIC_FLAG: u8 = 1 << 7;
940976
941 /// Create a new FnSigKind with the "Rust" ABI, "Unsafe" safety, and no C-style variadic argument.
942 /// To modify these flags, use the `set_*` methods, for readability.
943 // FIXME: use Default instead when that trait is const stable.
944 pub fn default() -> Self {
945 Self { flags: 0, _marker: PhantomData }
946 .set_abi(ExternAbi::Rust)
947 .set_safety(I::Safety::unsafe_mode())
948 .set_c_variadic(false)
949 }
977 /// The marker index for "no splatted arguments". Higher values are also not supported, for
978 /// performance reasons.
979 ///
980 /// Must have the same value as `FnDeclFlags::NO_SPLATTED_ARG_INDEX` and
981 /// `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`.
982 ///
983 /// This is an implementation detail, which should only be used in low-level encoding.
984 pub const NO_SPLATTED_ARG_INDEX: u8 = u8::MAX;
950985
951 /// Create a new FnSigKind with the given ABI, safety, and C-style variadic flag.
952 pub fn new(abi: ExternAbi, safety: I::Safety, c_variadic: bool) -> Self {
953 Self::default().set_abi(abi).set_safety(safety).set_c_variadic(c_variadic)
986 /// Create a new FnSigKind with the given ABI, safety, C-style variadic, and splatted argument
987 /// index.
988 pub fn new(
989 abi: ExternAbi,
990 safety: I::Safety,
991 c_variadic: bool,
992 splatted: Option<u8>,
993 args_len: usize,
994 ) -> Result<Self, SplattedArgIndexError> {
995 Self::default()
996 .set_abi(abi)
997 .set_safety(safety)
998 .set_c_variadic(c_variadic)
999 .set_splatted(splatted, args_len)
1000 }
1001
1002 /// Create a new safe FnSigKind with the `extern "Rust"` ABI, that isn't C-style variadic or splatted.
1003 pub fn dummy() -> Self {
1004 Self::default().set_safety(I::Safety::safe())
9541005 }
9551006
9561007 /// Set the ABI, including the unwind flag.
......@@ -989,6 +1040,41 @@ impl<I: Interner> FnSigKind<I> {
9891040 self
9901041 }
9911042
1043 /// Set the splatted argument index.
1044 /// The number of function arguments is used for error checking.
1045 #[must_use = "this method does not modify the receiver"]
1046 pub fn set_splatted(
1047 mut self,
1048 splatted: Option<u8>,
1049 args_len: usize,
1050 ) -> Result<Self, SplattedArgIndexError> {
1051 if let Some(splatted_arg_index) = splatted {
1052 if splatted_arg_index == Self::NO_SPLATTED_ARG_INDEX {
1053 // This index value is used as a marker for "no splatting", so it is unsupported.
1054 // Higher values are also not supported, for performance reasons.
1055 return Err(SplattedArgIndexError::InvalidIndex { splatted_arg_index });
1056 } else if usize::from(splatted_arg_index) >= args_len {
1057 return Err(SplattedArgIndexError::OutOfBounds {
1058 splatted_arg_index,
1059 args_len: args_len as u16,
1060 });
1061 }
1062
1063 self.splatted = splatted_arg_index;
1064 } else {
1065 self.splatted = Self::NO_SPLATTED_ARG_INDEX;
1066 }
1067
1068 Ok(self)
1069 }
1070
1071 /// Set the splatted argument index to "no splatted arguments".
1072 #[must_use = "this method does not modify the receiver"]
1073 pub fn set_no_splatted_args(mut self) -> Self {
1074 self.splatted = Self::NO_SPLATTED_ARG_INDEX;
1075 self
1076 }
1077
9921078 /// Get the ABI, including the unwind flag.
9931079 pub fn abi(self) -> ExternAbi {
9941080 let abi_index = self.flags & Self::EXTERN_ABI_MASK;
......@@ -1009,6 +1095,11 @@ impl<I: Interner> FnSigKind<I> {
10091095 pub fn c_variadic(self) -> bool {
10101096 self.flags & Self::C_VARIADIC_FLAG != 0
10111097 }
1098
1099 /// Get the index of the splatted argument, if any.
1100 pub fn splatted(self) -> Option<u8> {
1101 if self.splatted == Self::NO_SPLATTED_ARG_INDEX { None } else { Some(self.splatted) }
1102 }
10121103}
10131104
10141105#[derive_where(Clone, Copy, PartialEq, Hash; I: Interner)]
......@@ -1039,8 +1130,21 @@ impl<I: Interner> FnSig<I> {
10391130 !self.c_variadic() && self.safety().is_safe() && self.abi() == ExternAbi::Rust
10401131 }
10411132
1133 /// Set the safety flag.
1134 #[must_use = "this method does not modify the receiver"]
10421135 pub fn set_safety(self, safety: I::Safety) -> Self {
1043 Self { fn_sig_kind: FnSigKind::new(self.abi(), safety, self.c_variadic()), ..self }
1136 Self { fn_sig_kind: self.fn_sig_kind.set_safety(safety), ..self }
1137 }
1138
1139 /// Set the splatted argument index.
1140 /// The number of function arguments is used for error checking.
1141 #[must_use = "this method does not modify the receiver"]
1142 pub fn set_splatted(
1143 self,
1144 splatted: Option<u8>,
1145 args_len: usize,
1146 ) -> Result<Self, SplattedArgIndexError> {
1147 Ok(Self { fn_sig_kind: self.fn_sig_kind.set_splatted(splatted, args_len)?, ..self })
10441148 }
10451149
10461150 pub fn safety(self) -> I::Safety {
......@@ -1055,11 +1159,14 @@ impl<I: Interner> FnSig<I> {
10551159 self.fn_sig_kind.c_variadic()
10561160 }
10571161
1162 pub fn splatted(self) -> Option<u8> {
1163 self.fn_sig_kind.splatted()
1164 }
1165
1166 /// Create a new safe FnSig with no arguments or return type, using the `extern "Rust"` ABI,
1167 /// that isn't C-style variadic or splatted.
10581168 pub fn dummy() -> Self {
1059 Self {
1060 inputs_and_output: Default::default(),
1061 fn_sig_kind: FnSigKind::new(ExternAbi::Rust, I::Safety::safe(), false),
1062 }
1169 Self { inputs_and_output: Default::default(), fn_sig_kind: FnSigKind::dummy() }
10631170 }
10641171}
10651172
......@@ -1092,6 +1199,10 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> {
10921199 self.skip_binder().c_variadic()
10931200 }
10941201
1202 pub fn splatted(self) -> Option<u8> {
1203 self.skip_binder().splatted()
1204 }
1205
10951206 pub fn safety(self) -> I::Safety {
10961207 self.skip_binder().safety()
10971208 }
......@@ -1127,6 +1238,9 @@ impl<I: Interner> fmt::Debug for FnSig<I> {
11271238 if i > 0 {
11281239 write!(f, ", ")?;
11291240 }
1241 if Some(i) == fn_sig_kind.splatted().map(usize::from) {
1242 write!(f, "#[splat] ")?;
1243 }
11301244 write!(f, "{ty:?}")?;
11311245 }
11321246 if fn_sig_kind.c_variadic() {
......@@ -1288,8 +1402,9 @@ impl<I: Interner> FnHeader<I> {
12881402 self.fn_sig_kind.abi()
12891403 }
12901404
1405 /// Create a new safe FnHeader with the `extern "Rust"` ABI, that isn't C-style variadic or splatted.
12911406 pub fn dummy() -> Self {
1292 Self { fn_sig_kind: FnSigKind::new(ExternAbi::Rust, I::Safety::safe(), false) }
1407 Self { fn_sig_kind: FnSigKind::dummy() }
12931408 }
12941409}
12951410
compiler/rustc_type_ir/src/ty_kind/closure.rs+1-1
......@@ -364,7 +364,7 @@ pub struct CoroutineClosureSignature<I: Interner> {
364364 // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types
365365 // never actually differ. But we save them rather than recreating them
366366 // from scratch just for good measure.
367 /// Always safe, RustCall, non-c-variadic
367 /// Always safe, RustCall, non-c-variadic, non-splatted
368368 #[type_visitable(ignore)]
369369 #[type_foldable(identity)]
370370 pub fn_sig_kind: FnSigKind<I>,
library/alloc/src/vec/mod.rs+5-1
......@@ -1760,7 +1760,11 @@ impl<T, A: Allocator> Vec<T, A> {
17601760 #[must_use]
17611761 pub fn into_array<const N: usize>(self) -> Result<Box<[T; N], A>, Self> {
17621762 if self.len() == N {
1763 Ok(self.into_boxed_slice().into_array().ok().unwrap())
1763 // SAFETY: `Box::into_array` is guaranteed to return `Ok` if the
1764 // length of the slice is equal to `N`.
1765 // `self.into_boxed_slice().len()` is equal to `self.len()`,
1766 // which we just checked.
1767 Ok(unsafe { self.into_boxed_slice().into_array().unwrap_unchecked() })
17641768 } else {
17651769 Err(self)
17661770 }
library/core/src/fmt/num.rs+1-1
......@@ -361,7 +361,7 @@ macro_rules! impl_Display {
361361
362362 #[cfg(feature = "optimize_for_size")]
363363 fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 const MAX_DEC_N: usize = $T::MAX.ilog(10) as usize + 1;
364 const MAX_DEC_N: usize = $T::MAX.ilog10() as usize + 1;
365365 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
366366
367367 let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
library/core/src/fmt/num_buffer.rs+4-5
......@@ -17,13 +17,13 @@ macro_rules! impl_NumBufferTrait {
1717 #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")]
1818 impl NumBufferTrait for $signed {
1919 // `+ 2` and not `+ 1` to include the `-` character.
20 const DEFAULT: Self::Buf = [MaybeUninit::<u8>::uninit(); $signed::MAX.ilog(10) as usize + 2];
21 type Buf = [MaybeUninit<u8>; $signed::MAX.ilog(10) as usize + 2];
20 const DEFAULT: Self::Buf = [MaybeUninit::<u8>::uninit(); $signed::MAX.ilog10() as usize + 2];
21 type Buf = [MaybeUninit<u8>; $signed::MAX.ilog10() as usize + 2];
2222 }
2323 #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")]
2424 impl NumBufferTrait for $unsigned {
25 const DEFAULT: Self::Buf = [MaybeUninit::<u8>::uninit(); $unsigned::MAX.ilog(10) as usize + 1];
26 type Buf = [MaybeUninit<u8>; $unsigned::MAX.ilog(10) as usize + 1];
25 const DEFAULT: Self::Buf = [MaybeUninit::<u8>::uninit(); $unsigned::MAX.ilog10() as usize + 1];
26 type Buf = [MaybeUninit<u8>; $unsigned::MAX.ilog10() as usize + 1];
2727 }
2828 )*
2929 }
......@@ -74,7 +74,6 @@ impl<T: NumBufferTrait> NumBuffer<T> {
7474 #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")]
7575 #[rustc_const_stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")]
7676 pub const fn new() -> Self {
77 // FIXME: Once const generics feature is working, use `T::BUF_SIZE` instead of 40.
7877 NumBuffer { buf: T::DEFAULT, phantom: core::marker::PhantomData }
7978 }
8079}
library/core/src/mem/type_info.rs+17-1
......@@ -215,7 +215,7 @@ pub struct Variant {
215215 pub name: &'static str,
216216 /// All fields of the variant.
217217 pub fields: &'static [Field],
218 /// Whether the enum variant fields is non-exhaustive.
218 /// Whether the enum variant fields are non-exhaustive.
219219 pub non_exhaustive: bool,
220220}
221221
......@@ -342,6 +342,22 @@ pub struct FnPtr {
342342
343343 /// Vardiadic function, e.g. extern "C" fn add(n: usize, mut args: ...);
344344 pub variadic: bool,
345
346 // FIXME(splat): should these fields be private, or merged into an Option<u8/u16>?
347 /// Is any function argument splatted?
348 pub is_splatted: bool,
349
350 /// The index of the splatted function argument in `inputs`, only valid if `is_splatted` is true.
351 /// e.g. in `fn overload(a: u8, #[splat] b: (f32, usize))` the index is 1, and it can be called
352 /// as `overload(a, 1.0, 2)`.
353 pub splatted_index: u8,
354}
355
356impl FnPtr {
357 /// Returns the splatted function argument index, or `None` if no argument is splatted.
358 pub const fn splatted(&self) -> Option<u8> {
359 if self.is_splatted { Some(self.splatted_index) } else { None }
360 }
345361}
346362
347363#[derive(Debug, Default)]
library/core/src/slice/index.rs+4
......@@ -139,6 +139,8 @@ pub impl(crate) const unsafe trait SliceIndex<T: ?Sized> {
139139 /// Returns a pointer to the output at this location, without
140140 /// performing any bounds checking.
141141 ///
142 /// # Safety
143 ///
142144 /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
143145 /// is *[undefined behavior]* even if the resulting pointer is not used.
144146 ///
......@@ -149,6 +151,8 @@ pub impl(crate) const unsafe trait SliceIndex<T: ?Sized> {
149151 /// Returns a mutable pointer to the output at this location, without
150152 /// performing any bounds checking.
151153 ///
154 /// # Safety
155 ///
152156 /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
153157 /// is *[undefined behavior]* even if the resulting pointer is not used.
154158 ///
library/coretests/tests/mem/fn_ptr.rs+66
......@@ -5,6 +5,7 @@ const STRING_TY: TypeId = const { TypeId::of::<String>() };
55const U8_TY: TypeId = const { TypeId::of::<u8>() };
66const _U8_REF_TY: TypeId = const { TypeId::of::<&u8>() };
77const UNIT_TY: TypeId = const { TypeId::of::<()>() };
8const TUPLE_STRING_U8_TY: TypeId = const { TypeId::of::<(String, u8)>() };
89
910#[test]
1011fn test_fn_ptrs() {
......@@ -14,6 +15,8 @@ fn test_fn_ptrs() {
1415 inputs: &[],
1516 output,
1617 variadic: false,
18 is_splatted: false,
19 splatted_index: _,
1720 }) = (const { Type::of::<fn()>().kind })
1821 else {
1922 panic!();
......@@ -31,6 +34,8 @@ fn test_ref() {
3134 inputs: &[ty1, ty2],
3235 output,
3336 variadic: false,
37 is_splatted: false,
38 splatted_index: _,
3439 }) = (const { Type::of::<fn(&u8, &u8)>().kind })
3540 else {
3641 panic!();
......@@ -61,6 +66,8 @@ fn test_unsafe() {
6166 inputs: &[],
6267 output,
6368 variadic: false,
69 is_splatted: false,
70 splatted_index: _,
6471 }) = (const { Type::of::<unsafe fn()>().kind })
6572 else {
6673 panic!();
......@@ -75,6 +82,8 @@ fn test_abi() {
7582 inputs: &[],
7683 output,
7784 variadic: false,
85 is_splatted: false,
86 splatted_index: _,
7887 }) = (const { Type::of::<extern "Rust" fn()>().kind })
7988 else {
8089 panic!();
......@@ -87,6 +96,8 @@ fn test_abi() {
8796 inputs: &[],
8897 output,
8998 variadic: false,
99 is_splatted: false,
100 splatted_index: _,
90101 }) = (const { Type::of::<extern "C" fn()>().kind })
91102 else {
92103 panic!();
......@@ -99,6 +110,8 @@ fn test_abi() {
99110 inputs: &[],
100111 output,
101112 variadic: false,
113 is_splatted: false,
114 splatted_index: _,
102115 }) = (const { Type::of::<unsafe extern "system" fn()>().kind })
103116 else {
104117 panic!();
......@@ -114,6 +127,8 @@ fn test_inputs() {
114127 inputs: &[ty1, ty2],
115128 output,
116129 variadic: false,
130 is_splatted: false,
131 splatted_index: _,
117132 }) = (const { Type::of::<fn(String, u8)>().kind })
118133 else {
119134 panic!();
......@@ -128,6 +143,8 @@ fn test_inputs() {
128143 inputs: &[ty1, ty2],
129144 output,
130145 variadic: false,
146 is_splatted: false,
147 splatted_index: _,
131148 }) = (const { Type::of::<fn(val: String, p2: u8)>().kind })
132149 else {
133150 panic!();
......@@ -145,6 +162,8 @@ fn test_output() {
145162 inputs: &[],
146163 output,
147164 variadic: false,
165 is_splatted: false,
166 splatted_index: _,
148167 }) = (const { Type::of::<fn() -> u8>().kind })
149168 else {
150169 panic!();
......@@ -160,6 +179,8 @@ fn test_variadic() {
160179 inputs: [ty1],
161180 output,
162181 variadic: true,
182 is_splatted: false,
183 splatted_index: _,
163184 }) = &(const { Type::of::<extern "C" fn(u8, ...)>().kind })
164185 else {
165186 panic!();
......@@ -167,3 +188,48 @@ fn test_variadic() {
167188 assert_eq!(output, &UNIT_TY);
168189 assert_eq!(*ty1, U8_TY);
169190}
191
192#[test]
193fn test_splat() {
194 #[rustfmt::skip]
195 let TypeKind::FnPtr(fn_ptr_ty) = &(const { Type::of::<fn(#[splat] (String, u8))>().kind }) else {
196 panic!();
197 };
198 let FnPtr {
199 unsafety: false,
200 abi: Abi::ExternRust,
201 inputs: [ty1],
202 output,
203 variadic: false,
204 is_splatted: true,
205 splatted_index: 0,
206 } = fn_ptr_ty
207 else {
208 panic!();
209 };
210 assert_eq!(output, &UNIT_TY);
211 assert_eq!(*ty1, TUPLE_STRING_U8_TY);
212 assert_eq!(fn_ptr_ty.splatted(), Some(0));
213}
214
215#[test]
216fn test_not_splat() {
217 let TypeKind::FnPtr(fn_ptr_ty) = &(const { Type::of::<fn((String, u8))>().kind }) else {
218 panic!();
219 };
220 let FnPtr {
221 unsafety: false,
222 abi: Abi::ExternRust,
223 inputs: [ty1],
224 output,
225 variadic: false,
226 is_splatted: false,
227 splatted_index: _,
228 } = fn_ptr_ty
229 else {
230 panic!();
231 };
232 assert_eq!(output, &UNIT_TY);
233 assert_eq!(*ty1, TUPLE_STRING_U8_TY);
234 assert_eq!(fn_ptr_ty.splatted(), None);
235}
library/std/src/attribute_docs.rs+250
......@@ -85,3 +85,253 @@
8585/// [`unused_must_use`]: ../rustc/lints/listing/warn-by-default.html#unused-must-use
8686/// [the `must_use` attribute]: ../reference/attributes/diagnostics.html#the-must_use-attribute
8787mod must_use_attribute {}
88
89#[doc(attribute = "allow")]
90//
91/// The `allow` attribute suppresses lint diagnostics that would otherwise produce
92/// warnings or errors. It can be used on any lint or lint group (except those
93/// set to `forbid`).
94///
95/// ```rust
96/// #[allow(dead_code)]
97/// fn unused_function() {
98/// // ...
99/// }
100///
101/// fn main() {
102/// // `unused_function` does not generate a compiler warning.
103/// }
104/// ```
105///
106/// Without `#[allow(dead_code)]`, the example above would emit:
107///
108/// ```text
109/// warning: function `unused_function` is never used
110/// --> main.rs:1:4
111/// |
112/// 1 | fn unused_function() {
113/// | ^^^^^^^^^^^^^^^
114/// |
115/// = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
116///
117/// warning: 1 warning emitted
118/// ```
119///
120/// Multiple lints can be set to `allow` at once with commas:
121///
122/// ```rust
123/// #[allow(unused_variables, unused_mut)]
124/// fn main() {
125/// let mut x: u32 = 42;
126/// }
127/// ```
128///
129/// This is mostly used to prevent lint warnings or errors while still under development.
130///
131/// It cannot override a lint that has been set to `forbid`.
132///
133/// It's also important to consider that overusing `allow` could make code harder to maintain
134/// and possibly hide issues. To mitigate this issue, using the `expect` attribute is preferred.
135///
136/// `allow` can be overridden by `warn`, `deny`, and `forbid`.
137///
138/// The lint checks supported by rustc can be found via `rustc -W help`,
139/// along with their default settings and are documented in [the `rustc` book].
140///
141/// [the `rustc` book]: ../rustc/lints/listing/index.html
142///
143/// For more information, see the Reference on [the `allow` attribute].
144///
145/// [the `allow` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
146mod allow_attribute {}
147
148#[doc(attribute = "cfg")]
149//
150/// Used for conditional compilation.
151///
152/// The `cfg` attribute allows compiling an item under specific conditions, otherwise it
153/// will be ignored.
154///
155/// ```rust
156/// // Only compiles this function for Linux.
157/// #[cfg(target_os = "linux")]
158/// fn platform_specific() {
159/// println!("Running on Linux");
160/// }
161///
162/// // Only compiles this function if not for Linux.
163/// #[cfg(not(target_os = "linux"))]
164/// fn platform_specific() {
165/// println!("Running on something else");
166/// }
167/// ```
168///
169/// Depending on the platform you're targeting, only one of these two functions will be considered
170/// during the compilation.
171///
172/// Conditions can also be combined with `all(...)`, `any(...)`, and `not(...)`.
173///
174/// * `all`: True if all given predicates are true.
175/// * `any`: True if at least one of the given predicates is true.
176/// * `not`: True if the predicate is false and false if the predicate is true.
177///
178/// ```rust
179/// #[cfg(all(unix, target_pointer_width = "64"))]
180/// fn unix_64bit() {
181/// }
182/// ```
183///
184/// If you want to use this mechanism in an `if` condition in your code, you
185/// can use the [`cfg!`] macro. To conditionally apply an attribute,
186/// see [`cfg_attr`].
187///
188/// For more information, see the Reference on [the `cfg` attribute].
189///
190/// [`cfg_attr`]: ../reference/conditional-compilation.html#the-cfg_attr-attribute
191/// [the `cfg` attribute]: ../reference/conditional-compilation.html#the-cfg-attribute
192mod cfg_attribute {}
193
194#[doc(attribute = "deny")]
195//
196/// Emits an error, preventing the compilation from finishing, when a lint check has failed.
197/// This is useful for enforcing rules or preventing certain patterns:
198///
199/// ```rust,compile_fail
200/// #[deny(unused)]
201/// fn foo() {
202/// let x = 42; // Emits an error because x is unused.
203/// }
204/// ```
205///
206/// `deny` can be overridden by `allow`, `warn`, and `forbid`:
207///
208/// ```rust
209/// #![deny(unused)]
210///
211/// #[allow(unused)] // We override the `deny` for this function.
212/// fn foo() {
213/// let x = 42; // No lint emitted even though `x` is unused.
214/// }
215/// ```
216///
217/// Multiple lints can also be set to `deny` at once:
218///
219/// ```rust,compile_fail
220/// #![deny(unused_imports, unused_variables)]
221/// use std::collections::*;
222///
223/// fn main() {
224/// let mut x = 10;
225/// }
226/// ```
227///
228/// The lint checks supported by rustc can be found via `rustc -W help`,
229/// along with their default settings and are documented in [the `rustc` book].
230///
231/// [the `rustc` book]: ../rustc/lints/listing/index.html
232///
233/// For more information, see the Reference on [the `deny` attribute].
234///
235/// [the `deny` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
236mod deny_attribute {}
237
238#[doc(attribute = "forbid")]
239//
240/// Emits an error, preventing the compilation from finishing, when a lint check has failed.
241///
242/// A lint set to `forbid` cannot be overridden by `allow` or `warn`.
243/// Attempting either will result in a compilation error. Writing `#[deny(...)]` on the same lint inside a
244/// `forbid` scope is permitted, but has no effect; the lint remains at the `forbid` level.
245///
246/// This is useful for enforcing strict policies that should not be relaxed
247/// anywhere in the codebase. Example:
248///
249/// ```rust
250/// #![forbid(unsafe_code)]
251///
252/// // This would cause a compilation error if uncommented:
253/// // #[allow(unsafe_code)] // error: cannot override `forbid`
254/// ```
255///
256/// Multiple lints can be set to `forbid` at once:
257///
258/// ```rust
259/// #![forbid(unsafe_code, unused)]
260/// ```
261///
262/// The lint checks supported by rustc can be found via `rustc -W help`,
263/// along with their default settings and are documented in [the `rustc` book].
264///
265/// [the `rustc` book]: ../rustc/lints/listing/index.html
266///
267/// For more information, see the Reference on [the `forbid` attribute].
268///
269/// [the `forbid` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
270mod forbid_attribute {}
271
272#[doc(attribute = "deprecated")]
273//
274/// Emits a warning during compilation when an item with this attribute is used.
275/// `since` and `note` are optional fields giving more detail about why the item is deprecated.
276///
277/// * `since`: the version since when the item is deprecated.
278/// * `note`: the reason why an item is deprecated.
279///
280/// Example:
281///
282/// ```rust
283/// #[deprecated(since = "1.0.0", note = "Use bar instead")]
284/// struct Foo;
285/// struct Bar;
286/// ```
287///
288/// `deprecated` attribute helps developers transition away from old code by providing warnings when
289/// deprecated items are used. Note that during `Cargo` builds, warnings on dependencies get silenced
290/// by default, so you may not see a deprecation warning unless you build that dependency directly.
291///
292/// For more information, see the Reference on [the `deprecated` attribute].
293///
294/// [the `deprecated` attribute]: ../reference/attributes/diagnostics.html#the-deprecated-attribute
295mod deprecated_attribute {}
296
297#[doc(attribute = "warn")]
298//
299/// Emits a warning during compilation when a lint check failed.
300///
301/// Unlike `deny` or `forbid`, `warn` does not produce a hard error: the compilation continues, but
302/// the compiler emits a warning message. `warn` can be overridden by `allow`, `deny`, and `forbid`.
303///
304/// Example:
305///
306/// ```rust,compile_fail
307/// #![allow(unused)]
308///
309/// #[warn(unused)] // We override the allowed `unused` lint.
310/// fn foo() {
311/// // This lint warns by default even without #[warn(unused)] being explicitly set
312/// let x = 42; // warning: unused variable `x`
313/// }
314/// ```
315///
316///
317/// Many lints, including `unused`, are already set to `warn` by default so this attribute is
318/// mainly useful for lints that are normally `allow` by default.
319///
320/// Multiple lints can be set to `warn` at once:
321///
322/// ```rust,compile_fail
323/// #[warn(unused_mut, unused_variables)]
324/// fn main() {
325/// let mut x = 42;
326/// }
327/// ```
328///
329/// The lint checks supported by rustc can be found via `rustc -W help`,
330/// along with their default settings and are documented in [the `rustc` book].
331///
332/// [the `rustc` book]: ../rustc/lints/listing/index.html
333///
334/// For more information, see the Reference on [the `warn` attribute].
335///
336/// [the `warn` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
337mod warn_attribute {}
library/std/src/sys/thread/unix.rs+6
......@@ -392,6 +392,7 @@ pub fn current_os_id() -> Option<u64> {
392392 target_os = "vxworks",
393393 target_os = "cygwin",
394394 target_vendor = "apple",
395 target_os = "netbsd",
395396))]
396397fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
397398 let mut result = [0; MAX_WITH_NUL];
......@@ -463,7 +464,12 @@ pub fn set_name(name: &CStr) {
463464
464465#[cfg(target_os = "netbsd")]
465466pub fn set_name(name: &CStr) {
467 // See https://github.com/NetBSD/src/blob/8d40872b4c550a802379f3b9c22a40212d5e149d/lib/libpthread/pthread.h#L281
468 // FIXME: move to libc.
469 const PTHREAD_MAX_NAMELEN_NP: usize = 32;
470
466471 unsafe {
472 let name = truncate_cstr::<{ PTHREAD_MAX_NAMELEN_NP }>(name);
467473 let res = libc::pthread_setname_np(
468474 libc::pthread_self(),
469475 c"%s".as_ptr(),
src/tools/enzyme+1-1
......@@ -1 +1 @@
1Subproject commit 7c0141f133a3592daa12cc6cc07f297a5222a42e
1Subproject commit a8668c7ca3579c3304d628bca518bafc0fcc62d1
src/tools/miri/src/helpers.rs+2
......@@ -406,6 +406,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
406406 let sig = this.tcx.mk_fn_sig(
407407 args.iter().map(|a| a.layout.ty),
408408 dest.layout.ty,
409 // FIXME(splat): Do we need to set splatted here?
410 // (Currently this also ignores c_variadic)
409411 FnSigKind::default().set_abi(caller_abi).set_safety(rustc_hir::Safety::Safe),
410412 );
411413 let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
src/tools/miri/src/shims/sig.rs+1-1
......@@ -274,7 +274,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
274274 inputs_and_output.push(shim_sig.ret);
275275 let fn_sig_binder = Binder::dummy(FnSig {
276276 inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output),
277 // Safety does not matter for the ABI.
277 // Safety and splatted do not matter for the ABI.
278278 fn_sig_kind: FnSigKind::default()
279279 .set_abi(shim_sig.abi)
280280 .set_safety(rustc_hir::Safety::Safe),
src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs+2
......@@ -173,6 +173,8 @@ impl<'db> InferenceContext<'_, 'db> {
173173 // impl forces the closure kind to `FnOnce` i.e. `u8`.
174174 let kind_ty = autoderef.ctx().table.next_ty_var(call_expr.into());
175175 let interner = autoderef.ctx().interner();
176
177 // Ignore splatting, it is unsupported on closures.
176178 let call_sig = interner.mk_fn_sig(
177179 [coroutine_closure_sig.tupled_inputs_ty],
178180 coroutine_closure_sig.to_coroutine(
src/tools/rust-analyzer/crates/hir-ty/src/lib.rs+1
......@@ -464,6 +464,7 @@ pub fn callable_sig_from_fn_trait<'db>(
464464 args.tuple_fields(),
465465 ret,
466466 false,
467 // FIXME(splat): handle splatted arguments
467468 Safety::Safe,
468469 ExternAbi::Rust,
469470 ));
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs+1
......@@ -637,6 +637,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
637637 fn_.abi,
638638 if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
639639 fn_.is_varargs,
640 // FIXME(splat): handle splatted arguments
640641 ),
641642 inputs_and_output: Tys::new_from_slice(&args),
642643 }),
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs+1
......@@ -2238,6 +2238,7 @@ impl<'db> DbInterner<'db> {
22382238 self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate)
22392239 }
22402240
2241 // FIXME: add splat support when the experiment is complete
22412242 pub fn mk_fn_sig<I>(
22422243 self,
22432244 inputs: I,
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs+1
......@@ -1514,6 +1514,7 @@ impl<'db> DbInterner<'db> {
15141514 TyKind::Tuple(params) => params,
15151515 _ => panic!(),
15161516 };
1517 // Ignore splatting, it is unsupported on closures.
15171518 self.mk_fn_sig(params, s.output(), s.c_variadic(), safety, ExternAbi::Rust)
15181519 })
15191520 }
tests/codegen-llvm/i128-x86-align.rs+2-4
......@@ -5,8 +5,6 @@
55// while rustc wants it to have 16 byte alignment. This test checks that we handle this
66// correctly.
77
8// CHECK: %ScalarPair = type { i32, [3 x i32], i128 }
9
108#![feature(core_intrinsics)]
119
1210#[repr(C)]
......@@ -62,8 +60,8 @@ pub fn load_volatile(x: &ScalarPair) -> ScalarPair {
6260 // CHECK-SAME: dereferenceable(32) %_0,
6361 // CHECK-SAME: align 16
6462 // CHECK-SAME: dereferenceable(32) %x
65 // CHECK: [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16
66 // CHECK-NEXT: store %ScalarPair [[LOAD]], ptr %_0, align 16
63 // CHECK: [[LOAD:%.*]] = load volatile i256, ptr %x, align 16
64 // CHECK-NEXT: store i256 [[LOAD]], ptr %_0, align 16
6765 // CHECK-NEXT: ret void
6866 unsafe { std::intrinsics::volatile_load(x) }
6967}
tests/codegen-llvm/intrinsics/volatile.rs+117-4
......@@ -5,6 +5,11 @@
55
66use std::intrinsics;
77
8#[repr(align(32))]
9pub struct CustomZst;
10
11type UninitFatPointer = std::mem::MaybeUninit<&'static dyn std::fmt::Debug>;
12
813// CHECK-LABEL: @volatile_copy_memory
914#[no_mangle]
1015pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) {
......@@ -28,8 +33,62 @@ pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) {
2833
2934// CHECK-LABEL: @volatile_load
3035#[no_mangle]
31pub unsafe fn volatile_load(a: *const u8) -> u8 {
32 // CHECK: load volatile
36pub unsafe fn volatile_load(a: *const u16) -> u16 {
37 // CHECK: [[TEMP:%.+]] = load volatile i16, ptr %a
38 // CHECK-SAME: align 2{{,|$}}
39 // CHECK-NEXT: ret i16 [[TEMP]]
40 intrinsics::volatile_load(a)
41}
42
43// CHECK-LABEL: @volatile_load_bool
44#[no_mangle]
45pub unsafe fn volatile_load_bool(a: *const bool) -> bool {
46 // CHECK: [[TEMP:%.+]] = load volatile i8, ptr %a
47 // CHECK-SAME: align 1{{,|$}}
48 // CHECK: [[TRUNC:%.+]] = trunc nuw i8 [[TEMP]] to i1
49 // CHECK: ret i1 [[TRUNC]]
50 intrinsics::volatile_load(a)
51}
52
53// CHECK-LABEL: @volatile_load_zst
54#[no_mangle]
55pub unsafe fn volatile_load_zst(a: *const CustomZst) -> CustomZst {
56 // CHECK: start:
57 // CHECK-NEXT: ret void
58 intrinsics::volatile_load(a)
59}
60
61// CHECK-LABEL: @volatile_load_array
62// CHECK-SAME: ptr{{.+}}sret([16 x i8]){{.+}}%_0
63#[no_mangle]
64pub unsafe fn volatile_load_array(a: *const [u16; 8]) -> [u16; 8] {
65 // CHECK-NOT: alloca
66 // CHECK: [[TEMP:%.+]] = load volatile i128, ptr %a,
67 // CHECK-SAME: align 2{{,|$}}
68 // CHECK: store i128 [[TEMP]], ptr %_0,
69 // CHECK-SAME: align 2{{,|$}}
70 // CHECK-NEXT: ret void
71 intrinsics::volatile_load(a)
72}
73
74// CHECK-LABEL: @volatile_load_fat
75#[no_mangle]
76pub unsafe fn volatile_load_fat(a: *const UninitFatPointer) -> UninitFatPointer {
77 // CHECK: [[ALLOCA:%.+]] = alloca
78 // CHECK-SAME: [[SIZE:4|8|16]] x i8
79 // CHECK-SAME: align [[ALIGN:2|4|8]]
80
81 // CHECK: [[TEMP:%.+]] = load volatile [[INT:i32|i64|i128]], ptr %a,
82 // CHECK-SAME: align [[ALIGN]]{{,|$}}
83 // CHECK: store [[INT]] [[TEMP]], ptr [[ALLOCA]],
84 // CHECK-SAME: align [[ALIGN]]{{,|$}}
85
86 // CHECK: [[T0:%.+]] = load ptr, ptr [[ALLOCA]], align [[ALIGN]]
87 // CHECK: [[T1:%.+]] = getelementptr inbounds i8, ptr [[ALLOCA]]
88 // CHECK: [[T2:%.+]] = load ptr, ptr [[T1]], align [[ALIGN]]
89 // CHECK: [[P1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[T0]], 0
90 // CHECK: [[P2:%.+]] = insertvalue { ptr, ptr } [[P1]], ptr [[T2]], 1
91 // CHECK: ret { ptr, ptr } [[P2]]
3392 intrinsics::volatile_load(a)
3493}
3594
......@@ -42,8 +101,62 @@ pub unsafe fn volatile_store(a: *mut u8, b: u8) {
42101
43102// CHECK-LABEL: @unaligned_volatile_load
44103#[no_mangle]
45pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 {
46 // CHECK: load volatile
104pub unsafe fn unaligned_volatile_load(a: *const u16) -> u16 {
105 // CHECK: [[TEMP:%.+]] = load volatile i16, ptr %a
106 // CHECK-SAME: align 1{{,|$}}
107 // CHECK-NEXT: ret i16 [[TEMP]]
108 intrinsics::unaligned_volatile_load(a)
109}
110
111// CHECK-LABEL: @unaligned_volatile_load_bool
112#[no_mangle]
113pub unsafe fn unaligned_volatile_load_bool(a: *const bool) -> bool {
114 // CHECK: [[TEMP:%.+]] = load volatile i8, ptr %a
115 // CHECK-SAME: align 1{{,|$}}
116 // CHECK: [[TRUNC:%.+]] = trunc nuw i8 [[TEMP]] to i1
117 // CHECK: ret i1 [[TRUNC]]
118 intrinsics::unaligned_volatile_load(a)
119}
120
121// CHECK-LABEL: @unaligned_volatile_load_zst
122#[no_mangle]
123pub unsafe fn unaligned_volatile_load_zst(a: *const CustomZst) -> CustomZst {
124 // CHECK: start:
125 // CHECK-NEXT: ret void
126 intrinsics::unaligned_volatile_load(a)
127}
128
129// CHECK-LABEL: @unaligned_volatile_load_array
130// CHECK-SAME: ptr{{.+}}sret([16 x i8]){{.+}}%_0,
131#[no_mangle]
132pub unsafe fn unaligned_volatile_load_array(a: *const [u16; 8]) -> [u16; 8] {
133 // CHECK-NOT: alloca
134 // CHECK: [[TEMP:%.+]] = load volatile i128, ptr %a,
135 // CHECK-SAME: align 1{{,|$}}
136 // CHECK: store i128 [[TEMP]], ptr %_0,
137 // CHECK-SAME: align 2{{,|$}}
138 // CHECK-NEXT: ret void
139 intrinsics::unaligned_volatile_load(a)
140}
141
142// CHECK-LABEL: @unaligned_volatile_load_fat
143#[no_mangle]
144pub unsafe fn unaligned_volatile_load_fat(a: *const UninitFatPointer) -> UninitFatPointer {
145 // CHECK: [[ALLOCA:%.+]] = alloca
146 // CHECK-SAME: [[SIZE]] x i8
147 // CHECK-SAME: align [[ALIGN]]
148
149 // CHECK: [[TEMP:%.+]] = load volatile [[INT]], ptr %a,
150 // CHECK-SAME: align 1{{,|$}}
151 // CHECK: store [[INT]] [[TEMP]], ptr [[ALLOCA]],
152 // CHECK-SAME: align [[ALIGN]]{{,|$}}
153
154 // CHECK: [[T0:%.+]] = load ptr, ptr [[ALLOCA]], align [[ALIGN]]
155 // CHECK: [[T1:%.+]] = getelementptr inbounds i8, ptr [[ALLOCA]]
156 // CHECK: [[T2:%.+]] = load ptr, ptr [[T1]], align [[ALIGN]]
157 // CHECK: [[P1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[T0]], 0
158 // CHECK: [[P2:%.+]] = insertvalue { ptr, ptr } [[P1]], ptr [[T2]], 1
159 // CHECK: ret { ptr, ptr } [[P2]]
47160 intrinsics::unaligned_volatile_load(a)
48161}
49162
tests/ui/asm/parse-error.stderr+6
......@@ -57,6 +57,12 @@ error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
5757 |
5858LL | asm!("{}", in(reg) foo => bar);
5959 | ^^ expected one of 7 possible tokens
60 |
61help: you might have meant to write a "greater than or equal to" comparison
62 |
63LL - asm!("{}", in(reg) foo => bar);
64LL + asm!("{}", in(reg) foo >= bar);
65 |
6066
6167error: expected a path for argument to `sym`
6268 --> $DIR/parse-error.rs:32:24
tests/ui/lifetimes/issue-76168-hr-outlives-3.rs+2-3
......@@ -8,10 +8,9 @@ async fn wrapper<F>(f: F)
88//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
99//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
1010where
11F:,
12for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
11 F:,
12 for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
1313{
14 //~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
1514 let mut i = 41;
1615 &mut i;
1716}
tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr+4-16
......@@ -3,9 +3,9 @@ error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
33 |
44LL | / async fn wrapper<F>(f: F)
55... |
6LL | | F:,
7LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
8 | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
6LL | | F:,
7LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
8 | |______________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
99 |
1010 = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32`
1111
......@@ -26,18 +26,6 @@ LL | async fn wrapper<F>(f: F)
2626 = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32`
2727 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
2828
29error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
30 --> $DIR/issue-76168-hr-outlives-3.rs:13:1
31 |
32LL | / {
33LL | |
34LL | | let mut i = 41;
35LL | | &mut i;
36LL | | }
37 | |_^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
38 |
39 = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32`
40
41error: aborting due to 4 previous errors
29error: aborting due to 3 previous errors
4230
4331For more information about this error, try `rustc --explain E0277`.
tests/ui/moves/unconstrained-impl-param-clone-suggestion.rs created+20
......@@ -0,0 +1,20 @@
1// Regression test for https://github.com/rust-lang/rust/issues/148631
2
3struct C;
4
5struct S<T>(T);
6
7trait Tr {}
8
9impl<T> Clone for S<C>
10//~^ ERROR the type parameter `T` is not constrained
11where
12 S<T>: Tr,
13{
14 fn clone(&self) -> Self {
15 *self
16 //~^ ERROR cannot move out of `*self`
17 }
18}
19
20fn main() {}
tests/ui/moves/unconstrained-impl-param-clone-suggestion.stderr created+19
......@@ -0,0 +1,19 @@
1error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
2 --> $DIR/unconstrained-impl-param-clone-suggestion.rs:9:6
3 |
4LL | impl<T> Clone for S<C>
5 | -^-
6 | ||
7 | |unconstrained type parameter
8 | help: remove the unused type parameter `T`
9
10error[E0507]: cannot move out of `*self` which is behind a shared reference
11 --> $DIR/unconstrained-impl-param-clone-suggestion.rs:15:9
12 |
13LL | *self
14 | ^^^^^ move occurs because `*self` has type `S<C>`, which does not implement the `Copy` trait
15
16error: aborting due to 2 previous errors
17
18Some errors have detailed explanations: E0207, E0507.
19For more information about an error, try `rustc --explain E0207`.
tests/ui/parser/eq-gt-to-gt-eq.fixed+6
......@@ -43,3 +43,9 @@ fn b() {
4343 _ => todo!(),
4444 }
4545}
46
47fn closure() {
48 let a = 0;
49 let b = 1;
50 let _ = [a].iter().any(|x| x >= &b); //~ERROR
51}
tests/ui/parser/eq-gt-to-gt-eq.rs+6
......@@ -43,3 +43,9 @@ fn b() {
4343 _ => todo!(),
4444 }
4545}
46
47fn closure() {
48 let a = 0;
49 let b = 1;
50 let _ = [a].iter().any(|x| x => &b); //~ERROR
51}
tests/ui/parser/eq-gt-to-gt-eq.stderr+13-1
......@@ -109,5 +109,17 @@ LL - match a => b {
109109LL + match a >= b {
110110 |
111111
112error: aborting due to 7 previous errors
112error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
113 --> $DIR/eq-gt-to-gt-eq.rs:50:34
114 |
115LL | let _ = [a].iter().any(|x| x => &b);
116 | ^^ expected one of 8 possible tokens
117 |
118help: you might have meant to write a "greater than or equal to" comparison
119 |
120LL - let _ = [a].iter().any(|x| x => &b);
121LL + let _ = [a].iter().any(|x| x >= &b);
122 |
123
124error: aborting due to 8 previous errors
113125
tests/ui/splat/splat-255-limit-fail.rs created+199
......@@ -0,0 +1,199 @@
1// ignore-tidy-linelength
2//! Test `#[splat]` fails over the 255th argument index (or higher).
3//! FIXME(splat): The 255 argument limit is a temporary performance hack.
4
5#![allow(incomplete_features)]
6#![feature(splat)]
7#![expect(dead_code)]
8
9type A = ();
10
11// These types and functions are deliberately formatted with 17 arguments in 15 lines, to show they
12// have ~255 arguments.
13#[rustfmt::skip]
14type Tuple256 = (
15 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
16 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
17 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
18 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
19 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
20 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
21 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
22 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
23 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
24 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
25 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
26 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
27 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
28 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
29 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
30 A,
31);
32
33#[rustfmt::skip]
34fn s_255_terminal(
35 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
36 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
37 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
38 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
39 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
40 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
41 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
42 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
43 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
44 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
45 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
46 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
47 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
48 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
49 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
50 #[splat] (_a, _b): (u32, i8), //~ ERROR `#[splat]` is not supported on argument index 255
51) {}
52
53#[rustfmt::skip]
54fn s_256_terminal(
55 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
56 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
57 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
58 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
59 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
60 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
61 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
62 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
63 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
64 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
65 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
66 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
67 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
68 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
69 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
70 _: A,
71 #[splat] (_a, _b): (u32, i8), //~ ERROR `#[splat]` is not supported on argument index 256
72) {}
73
74#[rustfmt::skip]
75fn s_255_non_terminal(
76 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
77 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
78 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
79 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
80 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
81 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
82 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
83 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
84 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
85 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
86 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
87 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
88 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
89 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
90 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
91 #[splat] (_a, _b): (u32, i8), //~ ERROR `#[splat]` is not supported on argument index 255
92 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
93) {}
94
95#[rustfmt::skip]
96fn s_256_non_terminal(
97 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
98 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
99 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
100 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
101 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
102 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
103 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
104 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
105 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
106 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
107 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
108 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
109 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
110 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
111 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
112 _: A,
113 #[splat] (_a, _b): (u32, i8), //~ ERROR `#[splat]` is not supported on argument index 256
114 _: A,
115) {}
116
117// It's only the splatted index that's constrained to 255, not the argument count of the caller or callee.
118fn more_than_255_splatted_args(#[splat] _t: Tuple256) {}
119
120fn main() {
121 let a = ();
122
123 #[rustfmt::skip]
124 more_than_255_splatted_args( //~ ERROR this splatted function takes 256 arguments, but 255 were provided [E0057]
125 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
126 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
127 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
128 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
129 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
130 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
131 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
132 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
133 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
134 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
135 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
136 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
137 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
138 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
139 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
140 /* missing: a, */
141 );
142
143 #[rustfmt::skip]
144 more_than_255_splatted_args( //~ ERROR this splatted function takes 256 arguments, but 257 were provided [E0057]
145 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
146 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
147 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
148 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
149 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
150 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
151 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
152 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
153 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
154 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
155 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
156 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
157 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
158 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
159 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
160 a, /* unexpected: */ a,
161 );
162
163 #[rustfmt::skip]
164 more_than_255_splatted_args( //~ ERROR this splatted function takes 256 arguments, but 512 were provided [E0057]
165 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
166 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
167 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
168 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
169 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
170 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
171 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
172 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
173 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
174 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
175 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
176 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
177 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
178 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
179 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
180 a,
181 /* unexpected: */
182 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
183 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
184 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
185 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
186 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
187 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
188 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
189 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
190 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
191 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
192 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
193 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
194 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
195 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
196 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
197 a,
198 );
199}
tests/ui/splat/splat-255-limit-fail.stderr created+71
......@@ -0,0 +1,71 @@
1error: `#[splat]` is not supported on argument index 255
2 --> $DIR/splat-255-limit-fail.rs:50:5
3 |
4LL | #[splat] (_a, _b): (u32, i8),
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `#[splat]` is not supported here
6 |
7 = help: remove `#[splat]`, or use it on an argument closer to the start of the argument list
8
9error: `#[splat]` is not supported on argument index 256
10 --> $DIR/splat-255-limit-fail.rs:71:5
11 |
12LL | #[splat] (_a, _b): (u32, i8),
13 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `#[splat]` is not supported here
14 |
15 = help: remove `#[splat]`, or use it on an argument closer to the start of the argument list
16
17error: `#[splat]` is not supported on argument index 255
18 --> $DIR/splat-255-limit-fail.rs:91:5
19 |
20LL | #[splat] (_a, _b): (u32, i8),
21 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `#[splat]` is not supported here
22 |
23 = help: remove `#[splat]`, or use it on an argument closer to the start of the argument list
24
25error: `#[splat]` is not supported on argument index 256
26 --> $DIR/splat-255-limit-fail.rs:113:5
27 |
28LL | #[splat] (_a, _b): (u32, i8),
29 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `#[splat]` is not supported here
30 |
31 = help: remove `#[splat]`, or use it on an argument closer to the start of the argument list
32
33error[E0057]: this splatted function takes 256 arguments, but 255 were provided
34 --> $DIR/splat-255-limit-fail.rs:124:5
35 |
36LL | / more_than_255_splatted_args(
37LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
38LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
39LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
40... |
41LL | | /* missing: a, */
42LL | | );
43 | |_____^
44
45error[E0057]: this splatted function takes 256 arguments, but 257 were provided
46 --> $DIR/splat-255-limit-fail.rs:144:5
47 |
48LL | / more_than_255_splatted_args(
49LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
50LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
51LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
52... |
53LL | | a, /* unexpected: */ a,
54LL | | );
55 | |_____^
56
57error[E0057]: this splatted function takes 256 arguments, but 512 were provided
58 --> $DIR/splat-255-limit-fail.rs:164:5
59 |
60LL | / more_than_255_splatted_args(
61LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
62LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
63LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
64... |
65LL | | a,
66LL | | );
67 | |_____^
68
69error: aborting due to 7 previous errors
70
71For more information about this error, try `rustc --explain E0057`.
tests/ui/splat/splat-255-limit-pass.rs created+201
......@@ -0,0 +1,201 @@
1//@ run-pass
2// ignore-tidy-linelength
3//! Test `#[splat]` on the 255th argument index (or lower).
4//! FIXME(splat): The 255 argument limit is a temporary performance hack.
5
6#![allow(incomplete_features)]
7#![feature(splat)]
8#![expect(dead_code)]
9
10type A = ();
11
12// These types and functions are deliberately formatted with 17 arguments in 15 lines, to show they
13// have ~255 arguments.
14#[rustfmt::skip]
15type Tuple256 = (
16 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
17 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
18 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
19 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
20 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
21 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
22 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
23 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
24 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
25 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
26 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
27 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
28 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
29 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
30 A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
31 A,
32);
33
34#[rustfmt::skip]
35fn s_253_terminal(
36 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
37 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
38 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
39 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
40 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
41 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
42 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
43 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
44 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
45 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
46 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
47 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
48 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
49 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
50 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
51 #[splat] (_a, _b): (u32, i8),
52) {}
53
54#[rustfmt::skip]
55fn s_254_terminal(
56 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
57 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
58 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
59 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
60 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
61 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
62 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
63 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
64 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
65 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
66 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
67 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
68 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
69 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
70 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
71 #[splat] (_a, _b): (u32, i8),
72) {}
73
74#[rustfmt::skip]
75fn s_254_non_terminal_272_args(
76 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
77 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
78 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
79 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
80 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
81 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
82 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
83 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
84 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
85 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
86 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
87 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
88 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
89 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
90 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
91 #[splat] (_a, _b): (u32, i8),
92 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
93) {}
94
95#[rustfmt::skip]
96fn s_0_initial_253_args(
97 #[splat] (_a, _b): (u32, i8),
98 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
99 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
100 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
101 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
102 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
103 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
104 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
105 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
106 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
107 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
108 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
109 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
110 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
111 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
112 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
113) {}
114
115#[rustfmt::skip]
116fn s_0_initial_254_args(
117 #[splat] (_a, _b): (u32, i8),
118 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
119 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
120 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
121 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
122 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
123 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
124 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
125 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
126 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
127 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
128 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
129 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
130 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
131 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
132 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
133) {}
134
135#[rustfmt::skip]
136fn s_0_initial_255_args(
137 #[splat] (_a, _b): (u32, i8),
138 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
139 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
140 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
141 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
142 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
143 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
144 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
145 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
146 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
147 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
148 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
149 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
150 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
151 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
152 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
153) {}
154
155// It's only the splatted index that's constrained to 255, not the argument count of the caller or callee.
156#[rustfmt::skip]
157fn s_0_initial_256_args(
158 #[splat] (_a, _b): (u32, i8),
159 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
160 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
161 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
162 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
163 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
164 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
165 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
166 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
167 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
168 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
169 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
170 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
171 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
172 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
173 _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A, _: A,
174 _: A,
175) {}
176
177fn more_than_255_splatted_args(#[splat] _t: Tuple256) {}
178
179fn main() {
180 let a = ();
181
182 #[rustfmt::skip]
183 more_than_255_splatted_args(
184 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
185 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
186 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
187 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
188 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
189 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
190 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
191 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
192 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
193 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
194 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
195 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
196 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
197 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
198 a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
199 a,
200 );
201}
tests/ui/splat/splat-assoc-fn-tuple-simple.rs created+22
......@@ -0,0 +1,22 @@
1//@ run-pass
2//! Test using `#[splat]` on associated function tuple arguments (no receivers).
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7struct Foo;
8
9impl Foo {
10 fn tuple_1(#[splat] (_a,): (u32,)) {}
11
12 fn tuple_3(#[splat] (_a, _b, _c): (u32, i32, i8)) {}
13}
14
15fn main() {
16 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
17 // Add a tupled test for each call if they are.
18 //Foo::tuple_1((1u32,));
19
20 Foo::tuple_1(1u32);
21 Foo::tuple_3(1u32, 2i32, 3i8);
22}
tests/ui/splat/splat-async-fn-tuple-fail.rs created+17
......@@ -0,0 +1,17 @@
1//@ edition:2024
2//! Test that using `#[splat]` incorrectly on async functions gives errors.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7async fn async_wrong_type(#[splat] _x: u32) {}
8//~^ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32
9
10async fn async_multi_splat(#[splat] (_a, _b): (u32, i8), #[splat] (_c, _d): (u32, i8)) {}
11//~^ ERROR multiple `#[splat]`s are not allowed in the same function
12
13fn main() {
14 async_wrong_type(1u32);
15 async_multi_splat(1u32, 2i8, 3u32, 4i8);
16 //~^ ERROR this splatted function takes 3 arguments, but 4 were provided
17}
tests/ui/splat/splat-async-fn-tuple-fail.stderr created+27
......@@ -0,0 +1,27 @@
1error: multiple `#[splat]`s are not allowed in the same function
2 --> $DIR/splat-async-fn-tuple-fail.rs:10:28
3 |
4LL | async fn async_multi_splat(#[splat] (_a, _b): (u32, i8), #[splat] (_c, _d): (u32, i8)) {}
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 |
7 = help: remove `#[splat]` from all but one argument
8
9error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32 (u32)
10 --> $DIR/splat-async-fn-tuple-fail.rs:7:40
11 |
12LL | async fn async_wrong_type(#[splat] _x: u32) {}
13 | ^^^
14...
15LL | async_wrong_type(1u32);
16 | ^^^^^^^^^^^^^^^^^^^^^^
17
18error[E0057]: this splatted function takes 3 arguments, but 4 were provided
19 --> $DIR/splat-async-fn-tuple-fail.rs:15:5
20 |
21LL | async_multi_splat(1u32, 2i8, 3u32, 4i8);
22 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23
24error: aborting due to 3 previous errors
25
26Some errors have detailed explanations: E0057, E0277.
27For more information about an error, try `rustc --explain E0057`.
tests/ui/splat/splat-async-fn-tuple.rs created+18
......@@ -0,0 +1,18 @@
1//@ run-pass
2//@ edition:2024
3//! Test using `#[splat]` on tuple arguments of async functions.
4
5#![allow(incomplete_features)]
6#![feature(splat)]
7
8async fn async_tuple_args(#[splat] (_a, _b): (u32, i8)) {}
9
10async fn async_splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {}
11
12fn main() {
13 let _ = async_tuple_args(1u32, 2i8);
14 let _ = async_tuple_args(1, 2);
15
16 let _ = async_splat_non_terminal_arg(1u32, 2i8, 3.5f64);
17 let _ = async_splat_non_terminal_arg(1, 2, 3.5);
18}
tests/ui/splat/splat-cannot-resolve.rs created+49
......@@ -0,0 +1,49 @@
1//! Test that using `#[splat]` on un-resolvable types is an error.
2
3#![allow(incomplete_features)]
4#![allow(unconditional_recursion)]
5#![feature(splat)]
6#![feature(tuple_trait)]
7
8fn tuple(#[splat] t: impl Sized) -> impl Sized {
9 //~^ ERROR cannot resolve opaque type
10 tuple(tuple((t, ())))
11}
12
13fn tuple_trait(#[splat] t: impl std::marker::Tuple) -> impl std::marker::Tuple {
14 //~^ ERROR cannot resolve opaque type
15 tuple_trait(tuple_trait((t, ())))
16}
17
18trait Trait {
19 type MaybeTup;
20 type Tup: std::marker::Tuple;
21}
22
23fn ambig(#[splat] t: Trait::MaybeTup) {}
24//~^ ERROR ambiguous associated type
25//~| ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a
26//~| ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a
27//~| ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a
28fn ambig_tup(#[splat] t: Trait::Tup) {}
29//~^ ERROR ambiguous associated type
30//~| ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a
31//~| ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a
32//~| ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a
33
34fn main() {
35 tuple();
36 tuple_trait();
37 ambig();
38 ambig_tup();
39
40 tuple(1);
41 tuple_trait(1);
42 ambig(1);
43 ambig_tup(1);
44
45 tuple(1, 2.0);
46 tuple_trait(1, 2.0);
47 ambig(1, 2.0);
48 ambig_tup(1, 2.0);
49}
tests/ui/splat/splat-cannot-resolve.stderr created+94
......@@ -0,0 +1,94 @@
1error[E0223]: ambiguous associated type
2 --> $DIR/splat-cannot-resolve.rs:23:22
3 |
4LL | fn ambig(#[splat] t: Trait::MaybeTup) {}
5 | ^^^^^^^^^^^^^^^
6 |
7help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
8 |
9LL - fn ambig(#[splat] t: Trait::MaybeTup) {}
10LL + fn ambig(#[splat] t: <Example as Trait>::MaybeTup) {}
11 |
12
13error[E0223]: ambiguous associated type
14 --> $DIR/splat-cannot-resolve.rs:28:26
15 |
16LL | fn ambig_tup(#[splat] t: Trait::Tup) {}
17 | ^^^^^^^^^^
18 |
19help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
20 |
21LL - fn ambig_tup(#[splat] t: Trait::Tup) {}
22LL + fn ambig_tup(#[splat] t: <Example as Trait>::Tup) {}
23 |
24
25error[E0720]: cannot resolve opaque type
26 --> $DIR/splat-cannot-resolve.rs:8:37
27 |
28LL | fn tuple(#[splat] t: impl Sized) -> impl Sized {
29 | ^^^^^^^^^^
30
31error[E0720]: cannot resolve opaque type
32 --> $DIR/splat-cannot-resolve.rs:13:56
33 |
34LL | fn tuple_trait(#[splat] t: impl std::marker::Tuple) -> impl std::marker::Tuple {
35 | ^^^^^^^^^^^^^^^^^^^^^^^
36
37error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a {type error} ({type error})
38 --> $DIR/splat-cannot-resolve.rs:23:22
39 |
40LL | fn ambig(#[splat] t: Trait::MaybeTup) {}
41 | ^^^^^^^^^^^^^^^
42...
43LL | ambig();
44 | ^^^^^^^
45
46error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a {type error} ({type error})
47 --> $DIR/splat-cannot-resolve.rs:28:26
48 |
49LL | fn ambig_tup(#[splat] t: Trait::Tup) {}
50 | ^^^^^^^^^^
51...
52LL | ambig_tup();
53 | ^^^^^^^^^^^
54
55error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a {type error} ({type error})
56 --> $DIR/splat-cannot-resolve.rs:23:22
57 |
58LL | fn ambig(#[splat] t: Trait::MaybeTup) {}
59 | ^^^^^^^^^^^^^^^
60...
61LL | ambig(1);
62 | ^^^^^^^^
63
64error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a {type error} ({type error})
65 --> $DIR/splat-cannot-resolve.rs:28:26
66 |
67LL | fn ambig_tup(#[splat] t: Trait::Tup) {}
68 | ^^^^^^^^^^
69...
70LL | ambig_tup(1);
71 | ^^^^^^^^^^^^
72
73error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a {type error} ({type error})
74 --> $DIR/splat-cannot-resolve.rs:23:22
75 |
76LL | fn ambig(#[splat] t: Trait::MaybeTup) {}
77 | ^^^^^^^^^^^^^^^
78...
79LL | ambig(1, 2.0);
80 | ^^^^^^^^^^^^^
81
82error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a {type error} ({type error})
83 --> $DIR/splat-cannot-resolve.rs:28:26
84 |
85LL | fn ambig_tup(#[splat] t: Trait::Tup) {}
86 | ^^^^^^^^^^
87...
88LL | ambig_tup(1, 2.0);
89 | ^^^^^^^^^^^^^^^^^
90
91error: aborting due to 10 previous errors
92
93Some errors have detailed explanations: E0223, E0277, E0720.
94For more information about an error, try `rustc --explain E0223`.
tests/ui/splat/splat-const-fn-tuple-generic.rs created+34
......@@ -0,0 +1,34 @@
1//@ run-pass
2//! Test using `#[splat]` on tuple arguments of const functions with generics.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7// Generic type in first position
8const fn const_generic_first<T: Copy>(#[splat] _: (T, u32)) {}
9
10// Generic type in second position
11const fn const_generic_second<T: Copy>(#[splat] _: (u32, T)) {}
12
13// Multiple generic types
14const fn const_generic_both<T: Copy, U: Copy>(#[splat] _: (T, U)) {}
15
16// Generic with extra non-splatted arg
17const fn const_generic_extra<T: Copy>(#[splat] _: (T, u32), _extra: i32) {}
18
19fn main() {
20 const_generic_first(1i8, 2u32);
21 const_generic_first(true, 2u32);
22 const_generic_first(1u64, 2u32);
23
24 const_generic_second(1u32, 2i8);
25 const_generic_second(1u32, true);
26 const_generic_second(1u32, 2u64);
27
28 const_generic_both(1u32, 2i8);
29 const_generic_both(true, 2u64);
30 const_generic_both(1i8, false);
31
32 const_generic_extra(1i8, 2u32, 42i32);
33 const_generic_extra(true, 2u32, 42i32);
34}
tests/ui/splat/splat-const-fn-tuple.rs created+17
......@@ -0,0 +1,17 @@
1//@ run-pass
2//! Test using `#[splat]` on tuple arguments of const functions.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7const fn sum(#[splat] (a, b): (u32, u32)) -> u32 {
8 a + b
9}
10
11const RESULT: u32 = sum(1, 2);
12
13fn main() {
14 assert_eq!(RESULT, 3);
15 assert_eq!(sum(12, 18) , 30);
16 assert_eq!(sum(1, 2), 3);
17}
tests/ui/splat/splat-dyn-asref-tuple-fail.rs created+14
......@@ -0,0 +1,14 @@
1//! Test that `#[splat]` on `&dyn AsRef<T>` where `T: Tuple` is an error.
2
3#![allow(incomplete_features)]
4#![feature(splat)]
5#![feature(tuple_trait)]
6
7fn dyn_asref_splat<T>(#[splat] _t: &dyn AsRef<T>) where T: std::marker::Tuple {}
8//~^ ERROR cannot use splat attribute
9
10fn main() {
11 let s: String = "hello".to_owned();
12 dyn_asref_splat::<String>(&s);
13 //~^ ERROR `String` is not a tuple
14}
tests/ui/splat/splat-dyn-asref-tuple-fail.stderr created+24
......@@ -0,0 +1,24 @@
1error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a &'?3 dyn [Binder { value: Trait(std::convert::AsRef<std::string::String>), bound_vars: [] }] + '?3 (&'?3 dyn [Binder { value: Trait(std::convert::AsRef<std::string::String>), bound_vars: [] }] + '?3)
2 --> $DIR/splat-dyn-asref-tuple-fail.rs:7:36
3 |
4LL | fn dyn_asref_splat<T>(#[splat] _t: &dyn AsRef<T>) where T: std::marker::Tuple {}
5 | ^^^^^^^^^^^^^
6...
7LL | dyn_asref_splat::<String>(&s);
8 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9
10error[E0277]: `String` is not a tuple
11 --> $DIR/splat-dyn-asref-tuple-fail.rs:12:23
12 |
13LL | dyn_asref_splat::<String>(&s);
14 | ^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `String`
15 |
16note: required by a bound in `dyn_asref_splat`
17 --> $DIR/splat-dyn-asref-tuple-fail.rs:7:60
18 |
19LL | fn dyn_asref_splat<T>(#[splat] _t: &dyn AsRef<T>) where T: std::marker::Tuple {}
20 | ^^^^^^^^^^^^^^^^^^ required by this bound in `dyn_asref_splat`
21
22error: aborting due to 2 previous errors
23
24For more information about this error, try `rustc --explain E0277`.
tests/ui/splat/splat-fn-ptr-tuple.rs created+53
......@@ -0,0 +1,53 @@
1//@ failure-status: 101
2
3//@ normalize-stderr: ".*error:.*compiler/([^:]+):\d{1,}:\d{1,}:(.*)" -> "error: compiler/$1:LL:CC:$2"
4//@ normalize-stderr: "thread.*panicked at .*compiler.*" -> ""
5//@ normalize-stderr: "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}"
6//@ normalize-stderr: "note: compiler flags.*\n\n" -> ""
7//@ normalize-stderr: " +\d{1,}: .*\n" -> ""
8//@ normalize-stderr: " + at .*\n" -> ""
9//@ normalize-stderr: ".*omitted \d{1,} frames?.*\n" -> ""
10//@ normalize-stderr: ".*note: Some details are omitted.*\n" -> ""
11//@ normalize-stderr: ".*--> .*/splat-fn-ptr-tuple.rs:\d{1,}:\d{1,}.*\n" -> ""
12
13//! Test using `#[splat]` on tuple arguments of simple functions.
14//! Currently ICEs, but if we fix it, we'll want to know and update this test to pass.
15
16#![allow(incomplete_features)]
17#![feature(splat)]
18
19fn tuple_args(#[splat] (_a, _b): (u32, i8)) {}
20
21fn splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {}
22
23fn main() {
24 // FIXME(splat): not currently supported, can be supported when we no longer require a DefId in
25 // MIR lowering
26 // FIXME(rustfmt): the attribute gets deleted by rustfmt
27 // Functions
28 #[rustfmt::skip]
29 let fn_ptr: fn(#[splat] (u32, i8)) = tuple_args;
30 fn_ptr(1, 2); //~ ERROR no splatted def for function or method callee
31 fn_ptr(1u32, 2i8);
32
33 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
34 // Add a tupled test for each call if they are.
35 //fn_ptr((1, 2)); // ERROR this splatted function takes 2 arguments, but 1 was provided
36
37 #[rustfmt::skip]
38 let fn_ptr: fn(#[splat] (u32, i8), f64) = splat_non_terminal_arg;
39 fn_ptr(1, 2, 3.5);
40 fn_ptr(1u32, 2i8, 3.5f64);
41
42 // Function pointers
43 #[rustfmt::skip]
44 let fn_ptr: *const fn(#[splat] (u32, i8)) = tuple_args as *const fn(#[splat] (u32, i8));
45 (*fn_ptr)(1, 2);
46 (*fn_ptr)(1u32, 2i8);
47
48 #[rustfmt::skip]
49 let fn_ptr: *const fn(#[splat] (u32, i8), f64) =
50 splat_non_terminal_arg as *const fn(#[splat] (u32, i8), f64);
51 (*fn_ptr)(1, 2, 3.5);
52 (*fn_ptr)(1u32, 2i8, 3.5f64);
53}
tests/ui/splat/splat-fn-ptr-tuple.stderr created+23
......@@ -0,0 +1,23 @@
1error: compiler/rustc_mir_build/src/thir/cx/expr.rs:LL:CC: no splatted def for function or method callee
2 |
3LL | fn_ptr(1, 2);
4 | ^^^^^^^^^^^^
5
6
7
8Box<dyn Any>
9stack backtrace:
10
11note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
12
13note: please make sure that you have updated to the latest nightly
14
15note: rustc {version} running on {platform}
16
17query stack during panic:
18#0 [thir_body] building THIR for `main`
19#1 [check_unsafety] unsafety-checking `main`
20#2 [analysis] running analysis passes on crate `splat_fn_ptr_tuple`
21end of query stack
22error: aborting due to 1 previous error
23
tests/ui/splat/splat-fn-tuple-generic-fail.rs created+27
......@@ -0,0 +1,27 @@
1//! Test failing use of `#[splat]` on tuple trait arguments of generic functions.
2
3#![allow(incomplete_features)]
4#![feature(splat)]
5#![feature(tuple_trait)]
6
7fn splat_generic_tuple<T: std::marker::Tuple>(#[splat] _t: T) {}
8
9fn main() {
10 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
11
12 // Calling with un-splatted arguments might look like it works, but the actual generic type is
13 // a tuple inside another tuple. Aren't generics great?
14 splat_generic_tuple((1, 2));
15 splat_generic_tuple((1u32, 2i8));
16
17 // FIXME(splat): Make the splat generic handling code handle tuples inside tuples
18 // (if we want to support tupled calls)
19 splat_generic_tuple::<(((u32, i8)))>((1, 2)); //~ ERROR this splatted function takes 2 arguments, but 1 was provided
20 splat_generic_tuple::<(((u32, i8)))>((1u32, 2i8)); //~ ERROR this splatted function takes 2 arguments, but 1 was provided
21
22 splat_generic_tuple::<((u32, i8))>((1, 2)); //~ ERROR this splatted function takes 2 arguments, but 1 was provided
23 splat_generic_tuple::<((u32, i8))>((1u32, 2i8)); //~ ERROR this splatted function takes 2 arguments, but 1 was provided
24
25 splat_generic_tuple::<(u32, i8)>((1, 2)); //~ ERROR this splatted function takes 2 arguments, but 1 was provided
26 splat_generic_tuple::<(u32, i8)>((1u32, 2i8)); //~ ERROR this splatted function takes 2 arguments, but 1 was provided
27}
tests/ui/splat/splat-fn-tuple-generic-fail.stderr created+39
......@@ -0,0 +1,39 @@
1error[E0057]: this splatted function takes 2 arguments, but 1 was provided
2 --> $DIR/splat-fn-tuple-generic-fail.rs:19:5
3 |
4LL | splat_generic_tuple::<(((u32, i8)))>((1, 2));
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6
7error[E0057]: this splatted function takes 2 arguments, but 1 was provided
8 --> $DIR/splat-fn-tuple-generic-fail.rs:20:5
9 |
10LL | splat_generic_tuple::<(((u32, i8)))>((1u32, 2i8));
11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12
13error[E0057]: this splatted function takes 2 arguments, but 1 was provided
14 --> $DIR/splat-fn-tuple-generic-fail.rs:22:5
15 |
16LL | splat_generic_tuple::<((u32, i8))>((1, 2));
17 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18
19error[E0057]: this splatted function takes 2 arguments, but 1 was provided
20 --> $DIR/splat-fn-tuple-generic-fail.rs:23:5
21 |
22LL | splat_generic_tuple::<((u32, i8))>((1u32, 2i8));
23 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24
25error[E0057]: this splatted function takes 2 arguments, but 1 was provided
26 --> $DIR/splat-fn-tuple-generic-fail.rs:25:5
27 |
28LL | splat_generic_tuple::<(u32, i8)>((1, 2));
29 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30
31error[E0057]: this splatted function takes 2 arguments, but 1 was provided
32 --> $DIR/splat-fn-tuple-generic-fail.rs:26:5
33 |
34LL | splat_generic_tuple::<(u32, i8)>((1u32, 2i8));
35 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36
37error: aborting due to 6 previous errors
38
39For more information about this error, try `rustc --explain E0057`.
tests/ui/splat/splat-fn-tuple-generic.rs created+23
......@@ -0,0 +1,23 @@
1//@ run-pass
2//! Test using `#[splat]` on tuple trait arguments of generic functions.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6#![feature(tuple_trait)]
7
8fn splat_generic_tuple<T: std::marker::Tuple>(#[splat] _t: T) {}
9
10fn main() {
11 // Calling with un-splatted arguments might look like it works, but the actual generic type is
12 // a tuple inside another tuple. Aren't generics great?
13 splat_generic_tuple((1, 2));
14 splat_generic_tuple((1u32, 2i8));
15
16 // Generic tuple trait implementers are resolved during caller typeck.
17 splat_generic_tuple::<(u32, i8)>(1u32, 2i8);
18 splat_generic_tuple(1u32, 2i8);
19 splat_generic_tuple(1, 2);
20
21 splat_generic_tuple::<()>();
22 splat_generic_tuple();
23}
tests/ui/splat/splat-fn-tuple-simple.rs created+32
......@@ -0,0 +1,32 @@
1//@ run-pass
2//! Test using `#[splat]` on tuple arguments of simple functions.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7fn tuple_args(#[splat] (_a, _b): (u32, i8)) {}
8
9fn splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {}
10
11fn main() {
12 tuple_args(1, 2);
13 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
14 // Add a tupled test for each call if they are.
15 //tuple_args((1, 2));
16
17 tuple_args(1, 2);
18 tuple_args(1u32, 2i8);
19
20 splat_non_terminal_arg(1, 2, 3.5);
21 splat_non_terminal_arg(1u32, 2i8, 3.5f64);
22
23 #[expect(unused_variables, reason = "FIXME(splat or lint): this is obviously used")]
24 let fn_ptr = tuple_args;
25 fn_ptr(1, 2);
26 fn_ptr(1u32, 2i8);
27
28 #[expect(unused_variables, reason = "FIXME(splat or lint): this is obviously used")]
29 let fn_ptr = splat_non_terminal_arg;
30 fn_ptr(1, 2, 3.5);
31 fn_ptr(1u32, 2i8, 3.5f64);
32}
tests/ui/splat/splat-generics-complex-types.rs created+26
......@@ -0,0 +1,26 @@
1//@ run-pass
2//! Test using `#[splat]` on tuples with complex generic types inside the splatted tuple.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7// Vec<T> and Option<U> inside splatted tuple
8fn nested_generic<T, U>(#[splat] _: (Vec<T>, Option<U>)) {}
9
10// Box<T> inside splatted tuple
11fn box_generic<T>(#[splat] _: (Box<T>, u32)) {}
12
13// Multiple complex generics
14fn multi_generic<T, U, V>(#[splat] _: (Vec<T>, Option<U>, Box<V>)) {}
15
16fn main() {
17 nested_generic(vec![1u32, 2u32], Some(2i8));
18 nested_generic(vec![1, 2, 3], None::<i8>);
19 nested_generic::<u32, &str>(vec![], Some("hello"));
20
21 box_generic(Box::new(1u32), 42u32);
22 box_generic(Box::new("hello"), 1u32);
23
24 multi_generic(vec![1u32], Some(2i8), Box::new(3.0f64));
25 multi_generic::<u32, i8, &str>(vec![], None::<i8>, Box::new("hello"));
26}
tests/ui/splat/splat-generics-everywhere.rs created+64
......@@ -0,0 +1,64 @@
1//@ run-pass
2//! Test using `#[splat]` on tuples with generics in various positions.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7struct Foo<T>(T);
8
9// FIXME(splat): also add assoc/method with splatted generic tuple traits
10// also add generics inside the splatted tuple
11impl<T> Foo<T> {
12 fn new(t: T) -> Self {
13 Self(t)
14 }
15
16 fn assoc<U>(_u: U, #[splat] _s: ()) {}
17
18 fn method<V>(&self, _v: V, #[splat] _s: (u32, f64)) {}
19
20 fn lifetime<'a>(&self, #[splat] _s: (u32, f64, &'a str)) {}
21
22 fn const_generic<const N: usize>(&self, #[splat] _s: (u32, f64, [u8; N])) {}
23}
24
25// FIXME(splat): also add generics to the trait
26// also add assoc/method with splatted generic tuple traits
27// also add generics inside the splatted tuple
28trait BarTrait {
29 fn trait_assoc<W>(w: W, #[splat] _s: ());
30
31 fn trait_method<X>(&self, x: X, #[splat] _s: (u32, f64));
32
33 fn trait_lifetime<'a>(&self, #[splat] _s: (u32, f64, &'a str)) {}
34
35 fn trait_const_generic<const N: usize>(&self, #[splat] _s: (u32, f64, [u8; N])) {}
36}
37
38impl<T> BarTrait for Foo<T> {
39 fn trait_assoc<W>(_w: W, #[splat] _s: ()) {}
40
41 fn trait_method<X>(&self, _x: X, #[splat] _s: (u32, f64)) {}
42
43 fn trait_lifetime<'a>(&self, #[splat] _s: (u32, f64, &'a str)) {}
44
45 fn trait_const_generic<const N: usize>(&self, #[splat] _s: (u32, f64, [u8; N])) {}
46}
47
48fn main() {
49 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
50 // Add a tupled test for each call if they are.
51 //Foo::<i64>::assoc(("u",));
52
53 Foo::<f32>::assoc("u");
54 Foo::<f32>::trait_assoc("w");
55
56 let foo = Foo::new("t");
57 foo.method("v", 1u32, 2.3);
58 foo.lifetime(1u32, 2.3, "asdf");
59 foo.const_generic(1u32, 2.3, [1, 2, 3]);
60
61 foo.trait_method("x", 42u32, 9.8);
62 foo.trait_lifetime(1u32, 2.3, "asdf");
63 foo.trait_const_generic(1u32, 2.3, [1, 2, 3]);
64}
tests/ui/splat/splat-generics-inside-tuple.rs created+29
......@@ -0,0 +1,29 @@
1//@ run-pass
2//! Test using `#[splat]` on tuples with generics inside the splatted tuple.
3#![allow(incomplete_features)]
4#![feature(splat)]
5
6fn generic_second<T>(#[splat] _s: (u32, T)) {}
7
8fn generic_first<T>(#[splat] _s: (T, u32)) {}
9
10fn generic_both<T, U>(#[splat] _s: (T, U)) {}
11
12fn generic_triple<T, U, V>(#[splat] _s: (T, U, V)) {}
13
14fn main() {
15 generic_second(1u32, 2i8);
16 generic_second(1u32, 2.0f64);
17 generic_second(1u32, "hello");
18
19 generic_first(1i8, 2u32);
20 generic_first(2.0f64, 2u32);
21 generic_first("hello", 2u32);
22
23 generic_both(1u32, 2i8);
24 generic_both("hello", 2.0f64);
25 generic_both(true, "world");
26
27 generic_triple(1u32, 2.0f64, "hello");
28 generic_triple(true, 42i32, 3.14f32);
29}
tests/ui/splat/splat-invalid-trait-impl.rs created+27
......@@ -0,0 +1,27 @@
1//! Test that `#[splat]` trait impls with mismatched tuple element types are rejected.
2#![allow(incomplete_features)]
3#![feature(splat)]
4
5trait FooTrait {
6 fn method(#[splat] _: (u32, i8));
7}
8
9struct Foo;
10struct Foo1;
11struct Foo2;
12
13impl FooTrait for Foo {
14 fn method(#[splat] _: (u32, f32)) {}
15 //~^ ERROR method `method` has an incompatible type for trait
16}
17
18impl FooTrait for Foo1 {
19 fn method(#[splat] _: (f32, i8)) {}
20 //~^ ERROR method `method` has an incompatible type for trait
21}
22
23impl FooTrait for Foo2 {
24 fn method(#[splat] _: (f32, f64)) {}
25 //~^ ERROR method `method` has an incompatible type for trait
26}
27fn main() {}
tests/ui/splat/splat-invalid-trait-impl.stderr created+60
......@@ -0,0 +1,60 @@
1error[E0053]: method `method` has an incompatible type for trait
2 --> $DIR/splat-invalid-trait-impl.rs:14:27
3 |
4LL | fn method(#[splat] _: (u32, f32)) {}
5 | ^^^^^^^^^^ expected `i8`, found `f32`
6 |
7note: type in trait
8 --> $DIR/splat-invalid-trait-impl.rs:6:27
9 |
10LL | fn method(#[splat] _: (u32, i8));
11 | ^^^^^^^^^
12 = note: expected signature `fn(#[splat] (_, i8))`
13 found signature `fn(#[splat] (_, f32))`
14help: change the parameter type to match the trait
15 |
16LL - fn method(#[splat] _: (u32, f32)) {}
17LL + fn method(#[splat] _: (u32, i8)) {}
18 |
19
20error[E0053]: method `method` has an incompatible type for trait
21 --> $DIR/splat-invalid-trait-impl.rs:19:27
22 |
23LL | fn method(#[splat] _: (f32, i8)) {}
24 | ^^^^^^^^^ expected `u32`, found `f32`
25 |
26note: type in trait
27 --> $DIR/splat-invalid-trait-impl.rs:6:27
28 |
29LL | fn method(#[splat] _: (u32, i8));
30 | ^^^^^^^^^
31 = note: expected signature `fn(#[splat] (u32, _))`
32 found signature `fn(#[splat] (f32, _))`
33help: change the parameter type to match the trait
34 |
35LL - fn method(#[splat] _: (f32, i8)) {}
36LL + fn method(#[splat] _: (u32, i8)) {}
37 |
38
39error[E0053]: method `method` has an incompatible type for trait
40 --> $DIR/splat-invalid-trait-impl.rs:24:27
41 |
42LL | fn method(#[splat] _: (f32, f64)) {}
43 | ^^^^^^^^^^ expected `u32`, found `f32`
44 |
45note: type in trait
46 --> $DIR/splat-invalid-trait-impl.rs:6:27
47 |
48LL | fn method(#[splat] _: (u32, i8));
49 | ^^^^^^^^^
50 = note: expected signature `fn(#[splat] (u32, i8))`
51 found signature `fn(#[splat] (f32, f64))`
52help: change the parameter type to match the trait
53 |
54LL - fn method(#[splat] _: (f32, f64)) {}
55LL + fn method(#[splat] _: (u32, i8)) {}
56 |
57
58error: aborting due to 3 previous errors
59
60For more information about this error, try `rustc --explain E0053`.
tests/ui/splat/splat-invalid.rs+14
......@@ -30,4 +30,18 @@ extern "C" {
3030 fn bar_2(#[splat] _: (u32, i8));
3131}
3232
33trait FooTrait {
34 fn has_splat(#[splat] _: ());
35
36 fn no_splat(_: (u32, f64));
37}
38
39struct Foo;
40
41impl FooTrait for Foo {
42 fn has_splat(_: ()) {} //~ ERROR method `has_splat` has an incompatible type for trait
43
44 fn no_splat(#[splat] _: (u32, f64)) {} //~ ERROR method `no_splat` has an incompatible type for trait
45}
46
3347fn main() {}
tests/ui/splat/splat-invalid.stderr+30-1
......@@ -73,5 +73,34 @@ LL | fn splat_variadic4(..., #[splat] (_a, _b): (u32, i8)) {}
7373 |
7474 = help: remove `#[splat]` or remove `...`
7575
76error: aborting due to 9 previous errors
76error[E0053]: method `has_splat` has an incompatible type for trait
77 --> $DIR/splat-invalid.rs:42:5
78 |
79LL | fn has_splat(_: ()) {}
80 | ^^^^^^^^^^^^^^^^^^^ expected fn with arg 0 splatted, found fn with no splatted arg
81 |
82note: type in trait
83 --> $DIR/splat-invalid.rs:34:5
84 |
85LL | fn has_splat(#[splat] _: ());
86 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
87 = note: expected signature `fn(#[splat] ())`
88 found signature `fn(())`
89
90error[E0053]: method `no_splat` has an incompatible type for trait
91 --> $DIR/splat-invalid.rs:44:5
92 |
93LL | fn no_splat(#[splat] _: (u32, f64)) {}
94 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn with no splatted arg, found fn with arg 0 splatted
95 |
96note: type in trait
97 --> $DIR/splat-invalid.rs:36:5
98 |
99LL | fn no_splat(_: (u32, f64));
100 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
101 = note: expected signature `fn((_, _))`
102 found signature `fn(#[splat] (_, _))`
103
104error: aborting due to 11 previous errors
77105
106For more information about this error, try `rustc --explain E0053`.
tests/ui/splat/splat-maybe-tuple.rs created+22
......@@ -0,0 +1,22 @@
1//! Test that using `#[splat]` on maybe-tuple generic function arguments is an error,
2//! but only when the generics aren't tuples.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6#![expect(unused)]
7
8fn unbound_generic_arg<T>(#[splat] t: T) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32
9
10fn main() {
11 unbound_generic_arg();
12 unbound_generic_arg::<()>();
13
14 unbound_generic_arg(1);
15 unbound_generic_arg::<(u32,)>(1);
16
17 unbound_generic_arg(1, 2.0);
18 unbound_generic_arg::<(u32, f32)>(1, 2.0);
19
20 // The error comes from this call
21 unbound_generic_arg::<u32>(1);
22}
tests/ui/splat/splat-maybe-tuple.stderr created+12
......@@ -0,0 +1,12 @@
1error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32 (u32)
2 --> $DIR/splat-maybe-tuple.rs:8:39
3 |
4LL | fn unbound_generic_arg<T>(#[splat] t: T) {}
5 | ^
6...
7LL | unbound_generic_arg::<u32>(1);
8 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9
10error: aborting due to 1 previous error
11
12For more information about this error, try `rustc --explain E0277`.
tests/ui/splat/splat-method-tuple-simple.rs created+40
......@@ -0,0 +1,40 @@
1//@ run-pass
2//! Test using `#[splat]` on method tuple arguments (with receivers).
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7struct Foo;
8
9impl Foo {
10 fn tuple_2(&self, #[splat] (a, _b): (u32, i8)) -> u32 {
11 a
12 }
13
14 fn tuple_4(&self, #[splat] (a, _b, _c, _d): (u32, i8, (), f32)) -> u32 {
15 a
16 }
17}
18
19#[expect(dead_code)]
20struct TupleStruct(u32, i8);
21
22impl TupleStruct {
23 fn tuple_2(&self, #[splat] (a, _b): (u32, i8)) -> u32 {
24 a
25 }
26}
27
28fn main() {
29 let foo = Foo;
30
31 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
32 // Add a tupled test for each call if they are.
33 //foo.tuple_2((1, 2));
34
35 foo.tuple_2(1u32, 2i8);
36 foo.tuple_4(1u32, 2i8, (), 3f32);
37
38 let tuple_struct = TupleStruct(1u32, 2i8);
39 tuple_struct.tuple_2(1u32, 2i8);
40}
tests/ui/splat/splat-non-tuple.rs created+90
......@@ -0,0 +1,90 @@
1//! Test that using `#[splat]` on non-tuple function arguments is an error.
2
3#![allow(incomplete_features)]
4#![feature(splat)]
5#![expect(unused)]
6
7fn primitive_arg(#[splat] x: u32) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32
8
9enum NotATuple {
10 A(u32),
11 B(i8),
12}
13
14fn enum_arg(#[splat] y: NotATuple) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a NotATuple
15
16trait FooTrait {
17 fn tuple_1(#[splat] _: (u32,)); //~ NOTE type in trait
18
19 // Ambiguous case, self could be a tuple or a non-tuple
20 fn tuple_4(#[splat] self, _: (u32, i8, (), f32));
21}
22
23struct Foo;
24
25fn struct_arg(#[splat] z: Foo) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a Foo
26
27impl Foo {
28 fn tuple_2_self(
29 // FIXME(splat): ERROR cannot use splat attribute; the splatted argument type must be a...
30 #[splat] self,
31 (a, b): (u32, i8),
32 ) -> u32 {
33 a
34 }
35}
36
37impl FooTrait for Foo {
38 fn tuple_1(_: (u32,)) {}
39 //~^ ERROR method `tuple_1` has an incompatible type for trait
40 //~| NOTE expected fn with arg 0 splatted, found fn with no splatted arg
41 //~| NOTE expected signature `fn(#[splat] (_,))`
42 //~| NOTE found signature `fn((_,))`
43
44 fn tuple_4(
45 // FIXME(splat): ERROR cannot use splat attribute; the splatted argument type must be a...
46 #[splat] self,
47 _: (u32, i8, (), f32),
48 ) {
49 }
50}
51
52struct TupleStruct(u32, i8);
53
54fn tuple_struct_arg(#[splat] z: TupleStruct) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a TupleStruct
55
56impl TupleStruct {
57 fn tuple_2(
58 #[splat] self, // FIXME(splat): ERROR `#[splat]` attribute must be used on a tuple
59 (a, b): (f32, f64),
60 ) -> f32 {
61 a
62 }
63}
64
65impl FooTrait for TupleStruct {
66 fn tuple_1(#[splat] _: (u32,)) {}
67
68 fn tuple_4(
69 #[splat] self, // FIXME(splat): ERROR `#[splat]` attribute must be used on a tuple
70 _: (u32, i8, (), f32),
71 ) {
72 }
73}
74
75fn main() {
76 // FIXME(splat): is it enough for just the definitions/callees to error,
77 // or should the callers also error?
78 primitive_arg(1u32);
79 enum_arg(NotATuple::A(1u32));
80
81 let foo = Foo;
82 struct_arg(foo);
83 foo.tuple_2_self((1u32, 2i8));
84
85 let tuple_struct = TupleStruct(1u32, 2i8);
86 tuple_struct_arg(tuple_struct);
87 tuple_struct.tuple_2((1f32, 2f64));
88 TupleStruct::tuple_1(1u32);
89 tuple_struct.tuple_4((1u32, 2i8, (), 3f32));
90}
tests/ui/splat/splat-non-tuple.stderr created+54
......@@ -0,0 +1,54 @@
1error[E0053]: method `tuple_1` has an incompatible type for trait
2 --> $DIR/splat-non-tuple.rs:38:5
3 |
4LL | fn tuple_1(_: (u32,)) {}
5 | ^^^^^^^^^^^^^^^^^^^^^ expected fn with arg 0 splatted, found fn with no splatted arg
6 |
7note: type in trait
8 --> $DIR/splat-non-tuple.rs:17:5
9 |
10LL | fn tuple_1(#[splat] _: (u32,));
11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12 = note: expected signature `fn(#[splat] (_,))`
13 found signature `fn((_,))`
14
15error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32 (u32)
16 --> $DIR/splat-non-tuple.rs:7:30
17 |
18LL | fn primitive_arg(#[splat] x: u32) {}
19 | ^^^
20...
21LL | primitive_arg(1u32);
22 | ^^^^^^^^^^^^^^^^^^^
23
24error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a NotATuple (NotATuple)
25 --> $DIR/splat-non-tuple.rs:14:25
26 |
27LL | fn enum_arg(#[splat] y: NotATuple) {}
28 | ^^^^^^^^^
29...
30LL | enum_arg(NotATuple::A(1u32));
31 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32
33error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a Foo (Foo)
34 --> $DIR/splat-non-tuple.rs:25:27
35 |
36LL | fn struct_arg(#[splat] z: Foo) {}
37 | ^^^
38...
39LL | struct_arg(foo);
40 | ^^^^^^^^^^^^^^^
41
42error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a TupleStruct (TupleStruct)
43 --> $DIR/splat-non-tuple.rs:54:33
44 |
45LL | fn tuple_struct_arg(#[splat] z: TupleStruct) {}
46 | ^^^^^^^^^^^
47...
48LL | tuple_struct_arg(tuple_struct);
49 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50
51error: aborting due to 5 previous errors
52
53Some errors have detailed explanations: E0053, E0277.
54For more information about an error, try `rustc --explain E0053`.
tests/ui/splat/splat-overload-at-home-fail.rs created+41
......@@ -0,0 +1,41 @@
1//! Test error cases for `#[splat]` "overloading at home" example code.
2//! Splatted calls that don't match any registered MethodArgs impl should fail.
3#![allow(incomplete_features)]
4#![feature(splat)]
5#![feature(tuple_trait)]
6
7struct Foo;
8
9trait MethodArgs: std::marker::Tuple {
10 fn call_method(self, _this: &Foo);
11}
12
13impl MethodArgs for () {
14 fn call_method(self, _this: &Foo) {}
15}
16
17impl MethodArgs for (i32,) {
18 fn call_method(self, _this: &Foo) {}
19}
20
21impl MethodArgs for (i32, String) {
22 fn call_method(self, _this: &Foo) {}
23}
24
25impl Foo {
26 fn method<T: MethodArgs>(&self, #[splat] args: T) {
27 args.call_method(self)
28 }
29}
30
31fn main() {
32 let foo = Foo;
33
34 // No impl for (f32,) — wrong type
35 foo.method(42f32);
36 //~^ ERROR mismatched types
37
38 // No impl for (i32,i32) - wrong type
39 foo.method(42i32, 42i32);
40 //~^ ERROR mismatched types
41}
tests/ui/splat/splat-overload-at-home-fail.stderr created+40
......@@ -0,0 +1,40 @@
1error[E0308]: mismatched types
2 --> $DIR/splat-overload-at-home-fail.rs:35:16
3 |
4LL | foo.method(42f32);
5 | ------ ^^^^^ expected `i32`, found `f32`
6 | |
7 | arguments to this method are incorrect
8 |
9note: method defined here
10 --> $DIR/splat-overload-at-home-fail.rs:26:8
11 |
12LL | fn method<T: MethodArgs>(&self, #[splat] args: T) {
13 | ^^^^^^ ----------------
14help: change the type of the numeric literal from `f32` to `i32`
15 |
16LL - foo.method(42f32);
17LL + foo.method(42i32);
18 |
19
20error[E0308]: mismatched types
21 --> $DIR/splat-overload-at-home-fail.rs:39:23
22 |
23LL | foo.method(42i32, 42i32);
24 | ------ ^^^^^ expected `String`, found `i32`
25 | |
26 | arguments to this method are incorrect
27 |
28note: method defined here
29 --> $DIR/splat-overload-at-home-fail.rs:26:8
30 |
31LL | fn method<T: MethodArgs>(&self, #[splat] args: T) {
32 | ^^^^^^
33help: try using a conversion method
34 |
35LL | foo.method(42i32, 42i32.to_string());
36 | ++++++++++++
37
38error: aborting due to 2 previous errors
39
40For more information about this error, try `rustc --explain E0308`.
tests/ui/splat/splat-overload-at-home.rs created+52
......@@ -0,0 +1,52 @@
1//@ run-pass
2// ignore-tidy-linelength
3//! Test using `#[splat]` on some "overloading at home" example code.
4//! <https://internals.rust-lang.org/t/pre-pre-rfc-splatting-for-named-arguments-and-function-overloading/24012>
5
6#![allow(incomplete_features)]
7#![feature(splat)]
8#![feature(tuple_trait)]
9
10struct Foo;
11
12trait MethodArgs: std::marker::Tuple {
13 fn call_method(self, _this: &Foo);
14}
15impl MethodArgs for () {
16 fn call_method(self, _this: &Foo) {}
17}
18impl MethodArgs for (i32,) {
19 fn call_method(self, _this: &Foo) {}
20}
21impl MethodArgs for (i32, String) {
22 fn call_method(self, _this: &Foo) {}
23}
24
25impl Foo {
26 fn method<T: MethodArgs>(&self, #[splat] args: T) {
27 args.call_method(self)
28 }
29}
30
31fn main() {
32 let foo = Foo;
33
34 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
35 // Add a tupled test for each call if they are.
36 //foo.method(());
37 //foo.method((42i32,));
38
39 // Generic tuple trait implementers work without explicit tuple type parameters.
40 foo.method::<()>();
41 foo.method();
42
43 foo.method::<(i32,)>(42i32);
44 foo.method::<(i32,)>(42);
45 foo.method(42i32);
46 foo.method(42);
47
48 foo.method::<(i32, String)>(42i32, "asdf".to_owned());
49 foo.method::<(i32, String)>(42, "asdf".to_owned());
50 foo.method(42i32, "asdf".to_owned());
51 foo.method(42, "asdf".to_owned());
52}
tests/ui/splat/splat-trait-tuple.rs created+45
......@@ -0,0 +1,45 @@
1//@ run-pass
2//! Test using `#[splat]` on trait assoc function/method tuple arguments.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7trait FooTrait {
8 fn tuple_1_trait(#[splat] _: (u32,));
9
10 fn tuple_2_trait(&self, #[splat] _: (u32, f32));
11}
12
13struct Foo;
14
15impl FooTrait for Foo {
16 // Currently, splat attributes on impls must match traits. This provides better UX.
17 fn tuple_1_trait(#[splat] _: (u32,)) {}
18
19 fn tuple_2_trait(&self, #[splat] _: (u32, f32)) {}
20}
21
22#[expect(dead_code)]
23struct TupleStruct(u32, i8);
24
25impl FooTrait for TupleStruct {
26 fn tuple_1_trait(#[splat] _: (u32,)) {}
27
28 fn tuple_2_trait(&self, #[splat] _: (u32, f32)) {}
29}
30
31fn main() {
32 let foo = Foo;
33
34 // FIXME(splat): should splatted functions be callable with tupled and un-tupled arguments?
35 // Add a tupled test for each call if they are.
36 //Foo::tuple_1_trait((1u32,));
37 //foo.tuple_2_trait((1, 3.5));
38
39 Foo::tuple_1_trait(1u32);
40 foo.tuple_2_trait(1, 3.5);
41
42 let tuple_struct = TupleStruct(1u32, 2i8);
43 TupleStruct::tuple_1_trait(1u32);
44 tuple_struct.tuple_2_trait(1, 3.5)
45}
tests/ui/splat/splat-unsafe-fn-tuple-fail.rs created+16
......@@ -0,0 +1,16 @@
1//! Test that using `#[splat]` incorrectly on unsafe functions gives errors.
2
3#![allow(incomplete_features)]
4#![feature(splat)]
5
6unsafe fn unsafe_wrong_type(#[splat] _x: u32) {}
7//~^ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32
8
9unsafe fn unsafe_multi_splat(#[splat] (_a, _b): (u32, i8), #[splat] (_c, _d): (u32, i8)) {}
10//~^ ERROR multiple `#[splat]`s are not allowed in the same function
11
12fn main() {
13 unsafe {
14 unsafe_wrong_type(1u32);
15 }
16}
tests/ui/splat/splat-unsafe-fn-tuple-fail.stderr created+20
......@@ -0,0 +1,20 @@
1error: multiple `#[splat]`s are not allowed in the same function
2 --> $DIR/splat-unsafe-fn-tuple-fail.rs:9:30
3 |
4LL | unsafe fn unsafe_multi_splat(#[splat] (_a, _b): (u32, i8), #[splat] (_c, _d): (u32, i8)) {}
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 |
7 = help: remove `#[splat]` from all but one argument
8
9error[E0277]: cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32 (u32)
10 --> $DIR/splat-unsafe-fn-tuple-fail.rs:6:42
11 |
12LL | unsafe fn unsafe_wrong_type(#[splat] _x: u32) {}
13 | ^^^
14...
15LL | unsafe_wrong_type(1u32);
16 | ^^^^^^^^^^^^^^^^^^^^^^^
17
18error: aborting due to 2 previous errors
19
20For more information about this error, try `rustc --explain E0277`.
tests/ui/splat/splat-unsafe-fn-tuple.rs created+19
......@@ -0,0 +1,19 @@
1//@ run-pass
2//! Test using `#[splat]` on tuple arguments of unsafe functions.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6
7unsafe fn unsafe_tuple_args(#[splat] (_a, _b): (u32, i8)) {}
8
9unsafe fn unsafe_splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {}
10
11fn main() {
12 unsafe {
13 unsafe_tuple_args(1u32, 2i8);
14 unsafe_tuple_args(1, 2);
15
16 unsafe_splat_non_terminal_arg(1u32, 2i8, 3.5f64);
17 unsafe_splat_non_terminal_arg(1, 2, 3.5);
18 }
19}
tests/ui/splat/splat-where-clause.rs created+44
......@@ -0,0 +1,44 @@
1//@ run-pass
2//! Test using `#[splat]` on tuple arguments with where clause bounds.
3
4#![allow(incomplete_features)]
5#![feature(splat)]
6#![feature(tuple_trait)]
7
8fn where_splat<T>(#[splat] _t: T) where T: std::marker::Tuple {}
9
10fn where_splat_with_extra<T>(#[splat] _t: T, _extra: u32) where T: std::marker::Tuple {}
11
12fn impl_tuple_splat(#[splat] _t: impl std::marker::Tuple) {}
13
14fn impl_tuple_splat_with_extra(#[splat] _t: impl std::marker::Tuple, _extra: u32) {}
15
16fn main() {
17 // empty tuple
18 where_splat();
19
20 // single element
21 where_splat(1u32);
22 where_splat(1);
23
24 // two elements
25 where_splat(1u32, 2i8);
26 where_splat(1, 2);
27
28 // three elements
29 where_splat(1u32, 2i8, 3.0f64);
30 where_splat(1, 2, 3.0);
31
32 // with extra non-splatted arg
33 where_splat_with_extra(1u32, 2i8, 42u32);
34 where_splat_with_extra(1, 2, 42);
35
36 // impl Trait syntax variants
37 impl_tuple_splat();
38 impl_tuple_splat(1u32);
39 impl_tuple_splat(1u32, 2i8);
40 impl_tuple_splat(1, 2, 3.0);
41
42 impl_tuple_splat_with_extra(1u32, 2i8, 42u32);
43 impl_tuple_splat_with_extra(1, 2, 42);
44}
tests/ui/symbol-names/basic.legacy.stderr+2-2
......@@ -1,10 +1,10 @@
1error: symbol-name(_ZN5basic4main17h27f62b2d0b2beac6E)
1error: symbol-name(_ZN5basic4main17h33f35fba43592008E)
22 --> $DIR/basic.rs:8:1
33 |
44LL | #[rustc_dump_symbol_name]
55 | ^^^^^^^^^^^^^^^^^^^^^^^^^
66
7error: demangling(basic::main::h27f62b2d0b2beac6)
7error: demangling(basic::main::h33f35fba43592008)
88 --> $DIR/basic.rs:8:1
99 |
1010LL | #[rustc_dump_symbol_name]
tests/ui/symbol-names/issue-60925.legacy.stderr+2-2
......@@ -1,10 +1,10 @@
1error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h1eb769490ff06e77E)
1error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hc741419c44ba4d79E)
22 --> $DIR/issue-60925.rs:21:9
33 |
44LL | #[rustc_dump_symbol_name]
55 | ^^^^^^^^^^^^^^^^^^^^^^^^^
66
7error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h1eb769490ff06e77)
7error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hc741419c44ba4d79)
88 --> $DIR/issue-60925.rs:21:9
99 |
1010LL | #[rustc_dump_symbol_name]