| author | bors <bors@rust-lang.org> 2026-06-27 01:14:21 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-27 01:14:21 UTC |
| log | 16761606d606b6ec4d0c88fc9251670742ad9fd2 |
| tree | 3c0a01736c840678fcbddb7d07bd4da8a023afdc |
| parent | ce9954c0cfc4bf26b82aef16e6fd8b020c237992 |
| parent | 2ea8268f763c4c540786d16a1db8301a091d34e9 |
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 { |
| 3059 | 3059 | } |
| 3060 | 3060 | |
| 3061 | 3061 | /// The marker index for "no splatted arguments". |
| 3062 | /// Higher values are also not supported, for performance reasons. | |
| 3063 | /// | |
| 3062 | 3064 | /// 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; | |
| 3064 | 3066 | |
| 3065 | 3067 | /// Returns a splatted argument index, if any are present. |
| 3066 | pub fn splatted(&self) -> Option<u16> { | |
| 3068 | pub fn splatted(&self) -> Option<u8> { | |
| 3067 | 3069 | 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) { | |
| 3069 | 3071 | // AST validation has already checked the splatted argument index is valid, so just |
| 3070 | 3072 | // ignore invalid indexes here. |
| 3071 | 3073 | None |
| ... | ... | @@ -3073,7 +3075,7 @@ impl FnDecl { |
| 3073 | 3075 | arg.attrs |
| 3074 | 3076 | .iter() |
| 3075 | 3077 | .any(|attr| attr.has_name(sym::splat)) |
| 3076 | .then_some(u16::try_from(index).unwrap()) | |
| 3078 | .then_some(u8::try_from(index).unwrap()) | |
| 3077 | 3079 | } |
| 3078 | 3080 | }) |
| 3079 | 3081 | } |
compiler/rustc_ast_lowering/src/delegation.rs+2-3| ... | ... | @@ -93,7 +93,7 @@ struct ParamInfo { |
| 93 | 93 | pub c_variadic: bool, |
| 94 | 94 | |
| 95 | 95 | /// The index of the splatted parameter, if any. |
| 96 | pub splatted: Option<u16>, | |
| 96 | pub splatted: Option<u8>, | |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; |
| ... | ... | @@ -364,11 +364,10 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 364 | 364 | fn param_info(&self, def_id: DefId) -> ParamInfo { |
| 365 | 365 | let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder(); |
| 366 | 366 | |
| 367 | // FIXME(splat): use `sig.splatted()` once FnSig has it | |
| 368 | 367 | ParamInfo { |
| 369 | 368 | param_count: sig.inputs().len() + usize::from(sig.c_variadic()), |
| 370 | 369 | c_variadic: sig.c_variadic(), |
| 371 | splatted: None, | |
| 370 | splatted: sig.splatted(), | |
| 372 | 371 | } |
| 373 | 372 | } |
| 374 | 373 |
compiler/rustc_ast_passes/src/ast_validation.rs+3-3| ... | ... | @@ -412,11 +412,11 @@ impl<'a> AstValidator<'a> { |
| 412 | 412 | }) |
| 413 | 413 | .unzip(); |
| 414 | 414 | |
| 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. | |
| 417 | 417 | if let (Some(&splatted_arg_index), Some(&splatted_span)) = |
| 418 | 418 | (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) | |
| 420 | 420 | { |
| 421 | 421 | self.dcx().emit_err(diagnostics::InvalidSplattedArg { |
| 422 | 422 | splatted_arg_index, |
compiler/rustc_attr_parsing/src/attributes/link_attrs.rs+12-5| ... | ... | @@ -14,11 +14,11 @@ use super::util::parse_single_integer; |
| 14 | 14 | use crate::attributes::AttributeSafety; |
| 15 | 15 | use crate::attributes::cfg::parse_cfg_entry; |
| 16 | 16 | use 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, | |
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | 24 | pub(crate) struct LinkNameParser; |
| ... | ... | @@ -575,6 +575,13 @@ impl NoArgsAttributeParser for FfiPureParser { |
| 575 | 575 | AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); |
| 576 | 576 | const STABILITY: AttributeStability = unstable!(ffi_pure); |
| 577 | 577 | 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 | } | |
| 578 | 585 | } |
| 579 | 586 | |
| 580 | 587 | pub(crate) struct RustcStdInternalSymbolParser; |
compiler/rustc_attr_parsing/src/attributes/mod.rs+24-2| ... | ... | @@ -147,6 +147,14 @@ pub(crate) trait SingleAttributeParser: 'static { |
| 147 | 147 | |
| 148 | 148 | /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] |
| 149 | 149 | 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<'_, '_>) {} | |
| 150 | 158 | } |
| 151 | 159 | |
| 152 | 160 | /// Use in combination with [`SingleAttributeParser`]. |
| ... | ... | @@ -177,8 +185,10 @@ impl<T: SingleAttributeParser> AttributeParser for Single<T> { |
| 177 | 185 | const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS; |
| 178 | 186 | const SAFETY: AttributeSafety = T::SAFETY; |
| 179 | 187 | |
| 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) | |
| 182 | 192 | } |
| 183 | 193 | } |
| 184 | 194 | |
| ... | ... | @@ -258,6 +268,14 @@ pub(crate) trait NoArgsAttributeParser: 'static { |
| 258 | 268 | |
| 259 | 269 | /// Create the [`AttributeKind`] given attribute's [`Span`]. |
| 260 | 270 | 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<'_, '_>) {} | |
| 261 | 279 | } |
| 262 | 280 | |
| 263 | 281 | pub(crate) struct WithoutArgs<T: NoArgsAttributeParser>(PhantomData<T>); |
| ... | ... | @@ -280,6 +298,10 @@ impl<T: NoArgsAttributeParser> SingleAttributeParser for WithoutArgs<T> { |
| 280 | 298 | let _ = cx.expect_no_args(args); |
| 281 | 299 | Some(T::CREATE(cx.attr_span)) |
| 282 | 300 | } |
| 301 | ||
| 302 | fn finalize_check(attr_span: Span, cx: &FinalizeContext<'_, '_>) { | |
| 303 | T::finalize_check(attr_span, cx) | |
| 304 | } | |
| 283 | 305 | } |
| 284 | 306 | |
| 285 | 307 | type 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; |
| 13 | 13 | use crate::AttributeTemplate; |
| 14 | 14 | use crate::context::Suggestion; |
| 15 | 15 | |
| 16 | #[derive(Diagnostic)] | |
| 17 | #[diag("`#[ffi_const]` function cannot be `#[ffi_pure]`", code = E0757)] | |
| 18 | pub(crate) struct BothFfiConstAndPure { | |
| 19 | #[primary_span] | |
| 20 | pub attr_span: Span, | |
| 21 | } | |
| 22 | ||
| 16 | 23 | #[derive(Diagnostic)] |
| 17 | 24 | #[diag("{$attr_str} attribute cannot have empty value")] |
| 18 | 25 | pub(crate) struct DocAliasEmpty<'a> { |
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs+13-9| ... | ... | @@ -1461,15 +1461,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 1461 | 1461 | let cause = ObligationCause::misc(expr.span, self.mir_def_id()); |
| 1462 | 1462 | ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait); |
| 1463 | 1463 | 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 | { | |
| 1473 | 1477 | let mut type_spans = vec![]; |
| 1474 | 1478 | let mut types = FxIndexSet::default(); |
| 1475 | 1479 | for clause in errors |
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs+1-1| ... | ... | @@ -706,7 +706,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { |
| 706 | 706 | Some(Cause::LiveVar(..) | Cause::DropVar(..)) | None => { |
| 707 | 707 | // Here, under NLL: no cause was found. Under polonius: no cause was found, or a |
| 708 | 708 | // 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) { | |
| 710 | 710 | let (category, from_closure, span, region_name, path) = |
| 711 | 711 | self.free_region_constraint_info(borrow_region_vid, region); |
| 712 | 712 | 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> { |
| 116 | 116 | pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) { |
| 117 | 117 | self.buffered_diags.push(BufferedDiag::NonError(diag)); |
| 118 | 118 | } |
| 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 | } | |
| 119 | 150 | } |
| 120 | 151 | |
| 121 | 152 | impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 122 | 153 | 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); | |
| 124 | 155 | } |
| 125 | 156 | |
| 126 | 157 | pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) { |
| ... | ... | @@ -152,34 +183,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 152 | 183 | self.diags_buffer.buffered_mut_errors.insert(span, (diag, count)); |
| 153 | 184 | } |
| 154 | 185 | |
| 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 | ||
| 183 | 186 | pub(crate) fn has_buffered_diags(&self) -> bool { |
| 184 | 187 | self.diags_buffer.buffered_diags.is_empty() |
| 185 | 188 | } |
compiler/rustc_borrowck/src/diagnostics/opaque_types.rs+2-6| ... | ... | @@ -28,11 +28,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | let infcx = self.infcx; |
| 31 | let mut guar = None; | |
| 32 | 31 | let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> = |
| 33 | 32 | None; |
| 34 | 33 | for error in errors { |
| 35 | guar = Some(match error { | |
| 34 | match error { | |
| 36 | 35 | DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(infcx), |
| 37 | 36 | DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => { |
| 38 | 37 | infcx.dcx().emit_err(err) |
| ... | ... | @@ -82,11 +81,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 82 | 81 | ) |
| 83 | 82 | ), |
| 84 | 83 | ), |
| 85 | }); | |
| 84 | }; | |
| 86 | 85 | } |
| 87 | let guar = guar.unwrap(); | |
| 88 | self.root_cx.set_tainted_by_errors(guar); | |
| 89 | self.infcx.set_tainted_by_errors(guar); | |
| 90 | 86 | } |
| 91 | 87 | |
| 92 | 88 | /// 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}; |
| 28 | 28 | use tracing::{debug, instrument, trace}; |
| 29 | 29 | |
| 30 | 30 | use super::{LIMITATION_NOTE, OutlivesSuggestionBuilder, RegionName, RegionNameSource}; |
| 31 | use crate::consumers::RegionInferenceContext; | |
| 31 | 32 | use crate::nll::ConstraintDescription; |
| 32 | 33 | use crate::region_infer::{BlameConstraint, TypeTest}; |
| 33 | 34 | use crate::session_diagnostics::{ |
| ... | ... | @@ -134,7 +135,7 @@ pub(crate) struct ErrorConstraintInfo<'tcx> { |
| 134 | 135 | pub(super) span: Span, |
| 135 | 136 | } |
| 136 | 137 | |
| 137 | impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { | |
| 138 | impl<'tcx> RegionInferenceContext<'tcx> { | |
| 138 | 139 | /// Converts a region inference variable into a `ty::Region` that |
| 139 | 140 | /// we can use for error reporting. If `r` is universally bound, |
| 140 | 141 | /// 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> { |
| 142 | 143 | /// to find a good name from that. Returns `None` if we can't find |
| 143 | 144 | /// one (e.g., this is just some random part of the CFG). |
| 144 | 145 | 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) | |
| 146 | 147 | } |
| 147 | 148 | |
| 148 | 149 | /// Returns the `RegionVid` corresponding to the region returned by |
| 149 | 150 | /// `to_error_region`. |
| 150 | 151 | 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) { | |
| 152 | 153 | Some(r) |
| 153 | 154 | } else { |
| 154 | 155 | // We just want something nameable, even if it's not |
| 155 | 156 | // 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); | |
| 157 | 158 | |
| 158 | if self.regioncx.upper_bound_in_region_scc(r, upper_bound) { | |
| 159 | if self.upper_bound_in_region_scc(r, upper_bound) { | |
| 159 | 160 | self.to_error_region_vid(upper_bound) |
| 160 | 161 | } else { |
| 161 | 162 | None |
| ... | ... | @@ -179,14 +180,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 179 | 180 | if let Some(r) = self.to_error_region(fr) |
| 180 | 181 | && let ty::ReLateParam(late_param) = r.kind() |
| 181 | 182 | && 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 | |
| 183 | 184 | { |
| 184 | 185 | return args.as_closure().kind() == ty::ClosureKind::FnMut; |
| 185 | 186 | } |
| 186 | 187 | |
| 187 | 188 | false |
| 188 | 189 | } |
| 190 | } | |
| 189 | 191 | |
| 192 | impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { | |
| 190 | 193 | // For generic associated types (GATs) which implied 'static requirement |
| 191 | 194 | // from higher-ranked trait bounds (HRTB). Try to locate span of the trait |
| 192 | 195 | // and the span which bounded to the trait for adding 'static lifetime suggestion |
| ... | ... | @@ -309,12 +312,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 309 | 312 | RegionErrorKind::TypeTestError { type_test } => { |
| 310 | 313 | // Try to convert the lower-bound region into something named we can print for |
| 311 | 314 | // 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); | |
| 313 | 316 | |
| 314 | 317 | let type_test_span = type_test.span; |
| 315 | 318 | |
| 316 | 319 | if let Some(lower_bound_region) = lower_bound_region { |
| 317 | let generic_ty = self.name_regions( | |
| 320 | let generic_ty = self.regioncx.name_regions( | |
| 318 | 321 | self.infcx.tcx, |
| 319 | 322 | type_test.generic_kind.to_ty(self.infcx.tcx), |
| 320 | 323 | ); |
| ... | ... | @@ -324,7 +327,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 324 | 327 | self.body.source.def_id().expect_local(), |
| 325 | 328 | type_test_span, |
| 326 | 329 | 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), | |
| 328 | 331 | lower_bound_region, |
| 329 | 332 | )); |
| 330 | 333 | } else { |
| ... | ... | @@ -450,7 +453,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 450 | 453 | debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); |
| 451 | 454 | |
| 452 | 455 | // 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 | { | |
| 454 | 459 | let infer_err = self.infcx.err_ctxt(); |
| 455 | 460 | let nice = |
| 456 | 461 | NiceRegionError::new_from_span(&infer_err, self.mir_def_id(), cause.span, o, f); |
| ... | ... | @@ -481,7 +486,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 481 | 486 | d.note("meoow :c"); |
| 482 | 487 | d |
| 483 | 488 | } |
| 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 | { | |
| 485 | 492 | self.report_fnmut_error(&errci, kind) |
| 486 | 493 | } |
| 487 | 494 | (ConstraintCategory::Assignment, true, false) |
| ... | ... | @@ -736,7 +743,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 736 | 743 | // Only show an extra note if we can find an 'error region' for both of the region |
| 737 | 744 | // variables. This avoids showing a noisy note that just mentions 'synthetic' regions |
| 738 | 745 | // 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 | ) { | |
| 740 | 750 | (Some(f), Some(o)) => { |
| 741 | 751 | self.maybe_suggest_constrain_dyn_trait_impl(&mut diag, f, o, category); |
| 742 | 752 | |
| ... | ... | @@ -842,7 +852,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 842 | 852 | outlived_fr: RegionVid, |
| 843 | 853 | ) { |
| 844 | 854 | 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)) | |
| 846 | 856 | { |
| 847 | 857 | if outlived_f.kind() != ty::ReStatic { |
| 848 | 858 | return; |
| ... | ... | @@ -1013,7 +1023,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 1013 | 1023 | } |
| 1014 | 1024 | |
| 1015 | 1025 | 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 { | |
| 1017 | 1029 | return; |
| 1018 | 1030 | }; |
| 1019 | 1031 |
compiler/rustc_borrowck/src/diagnostics/region_name.rs+3-3| ... | ... | @@ -283,7 +283,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { |
| 283 | 283 | /// named variants. |
| 284 | 284 | #[instrument(level = "trace", skip(self))] |
| 285 | 285 | 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)?; | |
| 287 | 287 | |
| 288 | 288 | let tcx = self.infcx.tcx; |
| 289 | 289 | |
| ... | ... | @@ -1015,7 +1015,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { |
| 1015 | 1015 | &self, |
| 1016 | 1016 | fr: RegionVid, |
| 1017 | 1017 | ) -> 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 { | |
| 1019 | 1019 | return None; |
| 1020 | 1020 | }; |
| 1021 | 1021 | if region.is_named() { |
| ... | ... | @@ -1050,7 +1050,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { |
| 1050 | 1050 | &self, |
| 1051 | 1051 | fr: RegionVid, |
| 1052 | 1052 | ) -> 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 { | |
| 1054 | 1054 | return None; |
| 1055 | 1055 | }; |
| 1056 | 1056 | if region.is_named() { |
compiler/rustc_borrowck/src/lib.rs+14-5| ... | ... | @@ -48,6 +48,7 @@ use rustc_mir_dataflow::points::DenseLocationMap; |
| 48 | 48 | use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; |
| 49 | 49 | use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; |
| 50 | 50 | use rustc_span::{ErrorGuaranteed, Span, Symbol}; |
| 51 | use rustc_trait_selection::traits::query::type_op::{QueryTypeOp, TypeOp, TypeOpOutput}; | |
| 51 | 52 | use smallvec::SmallVec; |
| 52 | 53 | use tracing::{debug, instrument}; |
| 53 | 54 | |
| ... | ... | @@ -323,7 +324,6 @@ fn borrowck_collect_region_constraints<'tcx>( |
| 323 | 324 | let input_promoted: &IndexSlice<_, _> = &promoted.borrow(); |
| 324 | 325 | if let Some(e) = input_body.tainted_by_errors { |
| 325 | 326 | infcx.set_tainted_by_errors(e); |
| 326 | root_cx.set_tainted_by_errors(e); | |
| 327 | 327 | } |
| 328 | 328 | |
| 329 | 329 | // Replace all regions with fresh inference variables. This |
| ... | ... | @@ -571,15 +571,16 @@ fn borrowck_check_region_constraints<'tcx>( |
| 571 | 571 | |
| 572 | 572 | debug!("mbcx.used_mut: {:?}", mbcx.used_mut); |
| 573 | 573 | mbcx.lint_unused_mut(); |
| 574 | if let Some(guar) = mbcx.emit_errors() { | |
| 575 | mbcx.root_cx.set_tainted_by_errors(guar); | |
| 576 | } | |
| 577 | 574 | |
| 578 | 575 | let result = PropagatedBorrowCheckResults { |
| 579 | 576 | closure_requirements: opt_closure_req, |
| 580 | 577 | used_mut_upvars: mbcx.used_mut_upvars, |
| 581 | 578 | }; |
| 582 | 579 | |
| 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 | ||
| 583 | 584 | if let Some(consumer) = &mut root_cx.consumer { |
| 584 | 585 | consumer.insert_body( |
| 585 | 586 | def, |
| ... | ... | @@ -707,6 +708,14 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { |
| 707 | 708 | |
| 708 | 709 | next_region |
| 709 | 710 | } |
| 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 | } | |
| 710 | 719 | } |
| 711 | 720 | |
| 712 | 721 | impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { |
| ... | ... | @@ -718,7 +727,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { |
| 718 | 727 | } |
| 719 | 728 | |
| 720 | 729 | pub(crate) struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { |
| 721 | root_cx: &'a mut BorrowCheckRootCtxt<'tcx>, | |
| 730 | root_cx: &'a BorrowCheckRootCtxt<'tcx>, | |
| 722 | 731 | infcx: &'infcx BorrowckInferCtxt<'tcx>, |
| 723 | 732 | body: &'a Body<'tcx>, |
| 724 | 733 | 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>( |
| 111 | 111 | /// |
| 112 | 112 | /// This may result in errors being reported. |
| 113 | 113 | pub(crate) fn compute_regions<'tcx>( |
| 114 | root_cx: &mut BorrowCheckRootCtxt<'tcx>, | |
| 114 | root_cx: &BorrowCheckRootCtxt<'tcx>, | |
| 115 | 115 | infcx: &BorrowckInferCtxt<'tcx>, |
| 116 | 116 | body: &Body<'tcx>, |
| 117 | 117 | location_table: &PoloniusLocationTable, |
compiler/rustc_borrowck/src/root_cx.rs+1-1| ... | ... | @@ -72,7 +72,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | pub(super) fn used_mut_upvars( |
| 75 | &mut self, | |
| 75 | &self, | |
| 76 | 76 | nested_body_def_id: LocalDefId, |
| 77 | 77 | ) -> &SmallVec<[FieldIdx; 8]> { |
| 78 | 78 | &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::{ |
| 11 | 11 | self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions, |
| 12 | 12 | }; |
| 13 | 13 | use rustc_span::Span; |
| 14 | use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; | |
| 14 | use rustc_trait_selection::traits::query::type_op::TypeOpOutput; | |
| 15 | 15 | use tracing::{debug, instrument}; |
| 16 | 16 | |
| 17 | 17 | use crate::constraints::OutlivesConstraint; |
| ... | ... | @@ -287,11 +287,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { |
| 287 | 287 | ConstraintCategory<'tcx>, |
| 288 | 288 | )>, |
| 289 | 289 | ) -> 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) { | |
| 295 | 291 | Ok(TypeOpOutput { output: ty, constraints, .. }) => { |
| 296 | 292 | // FIXME(higher_ranked_auto): What should we do with the assumptions here? |
| 297 | 293 | 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; |
| 10 | 10 | use rustc_middle::traits::query::OutlivesBound; |
| 11 | 11 | use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; |
| 12 | 12 | use rustc_span::{ErrorGuaranteed, Span}; |
| 13 | use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; | |
| 13 | use rustc_trait_selection::traits::query::type_op; | |
| 14 | 14 | use tracing::{debug, instrument}; |
| 15 | 15 | use type_op::TypeOpOutput; |
| 16 | 16 | |
| ... | ... | @@ -242,15 +242,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { |
| 242 | 242 | if let Some(c) = constraints_unnorm { |
| 243 | 243 | constraints.push(c) |
| 244 | 244 | } |
| 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 | }); | |
| 254 | 253 | if let Some(c) = constraints_normalize { |
| 255 | 254 | constraints.push(c) |
| 256 | 255 | } |
| ... | ... | @@ -299,9 +298,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { |
| 299 | 298 | if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst { .. }) |
| 300 | 299 | { |
| 301 | 300 | 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); | |
| 305 | 303 | let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else { |
| 306 | 304 | continue; |
| 307 | 305 | }; |
| ... | ... | @@ -354,11 +352,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { |
| 354 | 352 | output: normalized_outlives, |
| 355 | 353 | constraints: constraints_normalize, |
| 356 | 354 | 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) | |
| 362 | 356 | else { |
| 363 | 357 | self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}")); |
| 364 | 358 | return; |
| ... | ... | @@ -381,9 +375,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { |
| 381 | 375 | ) -> Option<&'tcx QueryRegionConstraints<'tcx>> { |
| 382 | 376 | let TypeOpOutput { output: bounds, constraints, .. } = self |
| 383 | 377 | .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) | |
| 387 | 379 | .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty)) |
| 388 | 380 | .ok()?; |
| 389 | 381 | 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}; |
| 15 | 15 | use rustc_trait_selection::error_reporting::InferCtxtErrorExt; |
| 16 | 16 | use rustc_trait_selection::traits::ObligationCtxt; |
| 17 | 17 | use rustc_trait_selection::traits::query::dropck_outlives; |
| 18 | use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, TypeOpOutput}; | |
| 18 | use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOpOutput}; | |
| 19 | 19 | use tracing::debug; |
| 20 | 20 | |
| 21 | 21 | use crate::polonius; |
| ... | ... | @@ -638,9 +638,9 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> { |
| 638 | 638 | ) -> DropData<'tcx> { |
| 639 | 639 | debug!("compute_drop_data(dropped_ty={:?})", dropped_ty); |
| 640 | 640 | |
| 641 | let op = typeck.infcx.param_env.and(DropckOutlives { dropped_ty }); | |
| 641 | let goal = DropckOutlives { dropped_ty }; | |
| 642 | 642 | |
| 643 | match op.fully_perform(typeck.infcx, typeck.root_cx.root_def_id(), DUMMY_SP) { | |
| 643 | match typeck.infcx.fully_perform(goal, DUMMY_SP) { | |
| 644 | 644 | Ok(TypeOpOutput { output, constraints, .. }) => { |
| 645 | 645 | DropData { dropck_result: output, region_constraint_data: constraints } |
| 646 | 646 | } |
| ... | ... | @@ -655,7 +655,9 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> { |
| 655 | 655 | typeck.infcx.probe(|_| { |
| 656 | 656 | let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx); |
| 657 | 657 | 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, | |
| 659 | 661 | ) { |
| 660 | 662 | Ok(_) => ocx.evaluate_obligations_error_on_ambiguity(), |
| 661 | 663 | Err(e) => e, |
compiler/rustc_borrowck/src/type_check/mod.rs+2-3| ... | ... | @@ -95,7 +95,7 @@ mod relate_tys; |
| 95 | 95 | /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis |
| 96 | 96 | /// - `location_map` -- map between MIR `Location` and `PointIndex` |
| 97 | 97 | pub(crate) fn type_check<'tcx>( |
| 98 | root_cx: &mut BorrowCheckRootCtxt<'tcx>, | |
| 98 | root_cx: &BorrowCheckRootCtxt<'tcx>, | |
| 99 | 99 | infcx: &BorrowckInferCtxt<'tcx>, |
| 100 | 100 | body: &Body<'tcx>, |
| 101 | 101 | promoted: &IndexSlice<Promoted, Body<'tcx>>, |
| ... | ... | @@ -198,7 +198,6 @@ pub(crate) fn type_check<'tcx>( |
| 198 | 198 | debug!("encountered an error region; removing constraints!"); |
| 199 | 199 | constraints.outlives_constraints = Default::default(); |
| 200 | 200 | constraints.type_tests = Default::default(); |
| 201 | root_cx.set_tainted_by_errors(guar); | |
| 202 | 201 | infcx.set_tainted_by_errors(guar); |
| 203 | 202 | } |
| 204 | 203 | |
| ... | ... | @@ -229,7 +228,7 @@ enum FieldAccessError { |
| 229 | 228 | /// way, it accrues region constraints -- these can later be used by |
| 230 | 229 | /// NLL region checking. |
| 231 | 230 | struct TypeChecker<'a, 'tcx> { |
| 232 | root_cx: &'a mut BorrowCheckRootCtxt<'tcx>, | |
| 231 | root_cx: &'a BorrowCheckRootCtxt<'tcx>, | |
| 233 | 232 | infcx: &'a BorrowckInferCtxt<'tcx>, |
| 234 | 233 | last_span: Span, |
| 235 | 234 | 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_ |
| 271 | 271 | .map(|local| { |
| 272 | 272 | let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty); |
| 273 | 273 | |
| 274 | // FIXME(splat): un-tuple splatted arguments in codegen, for performance | |
| 274 | 275 | // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482 |
| 275 | 276 | if Some(local) == fx.mir.spread_arg { |
| 276 | 277 | // 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> { |
| 993 | 993 | loaded_value.to_rvalue() |
| 994 | 994 | } |
| 995 | 995 | |
| 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. | |
| 997 | 998 | let ptr = self.context.new_cast(self.location, ptr, ty.make_volatile().make_pointer()); |
| 998 | 999 | // (FractalFir): We insert a local here, to ensure this volatile load can't move across |
| 999 | 1000 | // blocks. |
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs+4-3| ... | ... | @@ -5,7 +5,7 @@ mod simd; |
| 5 | 5 | use std::iter; |
| 6 | 6 | |
| 7 | 7 | use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp}; |
| 8 | use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange}; | |
| 8 | use rustc_abi::{Align, BackendRepr, HasDataLayout, WrappingRange}; | |
| 9 | 9 | use rustc_codegen_ssa::base::wants_msvc_seh; |
| 10 | 10 | use rustc_codegen_ssa::common::IntPredicate; |
| 11 | 11 | use rustc_codegen_ssa::errors::InvalidMonomorphization; |
| ... | ... | @@ -368,8 +368,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc |
| 368 | 368 | |
| 369 | 369 | sym::volatile_load | sym::unaligned_volatile_load => { |
| 370 | 370 | 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); | |
| 373 | 374 | if let BackendRepr::Scalar(scalar) = result.layout.backend_repr { |
| 374 | 375 | self.to_immediate_scalar(load, scalar) |
| 375 | 376 | } 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> { |
| 682 | 682 | } |
| 683 | 683 | } |
| 684 | 684 | |
| 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 { | |
| 686 | 686 | unsafe { |
| 687 | let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); | |
| 687 | let load = self.load(ty, ptr, align); | |
| 688 | 688 | llvm::LLVMSetVolatile(load, llvm::TRUE); |
| 689 | 689 | load |
| 690 | 690 | } |
compiler/rustc_codegen_llvm/src/context.rs+1-1| ... | ... | @@ -978,7 +978,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { |
| 978 | 978 | } |
| 979 | 979 | |
| 980 | 980 | 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) | |
| 982 | 982 | } |
| 983 | 983 | } |
| 984 | 984 |
compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs+2-4| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | // .debug_gdb_scripts binary section. |
| 2 | 2 | |
| 3 | use rustc_abi::Align; | |
| 3 | 4 | use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; |
| 4 | 5 | use rustc_codegen_ssa::traits::*; |
| 5 | 6 | use rustc_hir::attrs::DebuggerVisualizerType; |
| ... | ... | @@ -18,10 +19,7 @@ pub(crate) fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Buil |
| 18 | 19 | let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx); |
| 19 | 20 | // Load just the first byte as that's all that's necessary to force |
| 20 | 21 | // 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); | |
| 25 | 23 | } |
| 26 | 24 | } |
| 27 | 25 |
compiler/rustc_codegen_llvm/src/intrinsic.rs+30-16| ... | ... | @@ -354,25 +354,39 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { |
| 354 | 354 | } |
| 355 | 355 | |
| 356 | 356 | 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. | |
| 362 | 361 | 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) | |
| 366 | 369 | } 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 | }; | |
| 374 | 389 | } |
| 375 | return IntrinsicResult::WroteIntoPlace; | |
| 376 | 390 | } |
| 377 | 391 | sym::volatile_store => { |
| 378 | 392 | 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>( |
| 375 | 375 | output.push_str("fn("); |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | // FIXME(splat): should debuginfo be de-tupled in the callee (and caller)? | |
| 378 | 379 | if !sig.inputs().is_empty() { |
| 379 | 380 | for &parameter_type in sig.inputs() { |
| 380 | 381 | 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> { |
| 1202 | 1202 | }; |
| 1203 | 1203 | |
| 1204 | 1204 | // Split the rust-call tupled arguments off. |
| 1205 | // FIXME(splat): un-tuple splatted arguments in codegen, for performance | |
| 1205 | 1206 | let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall |
| 1206 | 1207 | && let Some((tup, args)) = args.split_last() |
| 1207 | 1208 | { |
compiler/rustc_codegen_ssa/src/mir/mod.rs+1| ... | ... | @@ -433,6 +433,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( |
| 433 | 433 | let arg_decl = &mir.local_decls[local]; |
| 434 | 434 | let arg_ty = fx.monomorphize(arg_decl.ty); |
| 435 | 435 | |
| 436 | // FIXME(splat): re-tuple splatted arguments that were un-tupled in the ABI | |
| 436 | 437 | if Some(local) == mir.spread_arg { |
| 437 | 438 | // This argument (e.g., the last argument in the "rust-call" ABI) |
| 438 | 439 | // 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>: |
| 242 | 242 | fn alloca_with_ty(&mut self, layout: TyAndLayout<'tcx>) -> Self::Value; |
| 243 | 243 | |
| 244 | 244 | 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; | |
| 246 | 246 | fn atomic_load( |
| 247 | 247 | &mut self, |
| 248 | 248 | ty: Self::Type, |
compiler/rustc_const_eval/src/const_eval/type_info.rs+17-1| ... | ... | @@ -7,7 +7,7 @@ use rustc_ast::Mutability; |
| 7 | 7 | use rustc_hir::LangItem; |
| 8 | 8 | use rustc_middle::span_bug; |
| 9 | 9 | use rustc_middle::ty::layout::TyAndLayout; |
| 10 | use rustc_middle::ty::{self, Const, FnHeader, FnSigTys, ScalarInt, Ty, TyCtxt}; | |
| 10 | use rustc_middle::ty::{self, Const, FnHeader, FnSigKind, FnSigTys, ScalarInt, Ty, TyCtxt}; | |
| 11 | 11 | use rustc_span::{Symbol, sym}; |
| 12 | 12 | |
| 13 | 13 | use crate::const_eval::CompileTimeMachine; |
| ... | ... | @@ -436,6 +436,22 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { |
| 436 | 436 | sym::variadic => { |
| 437 | 437 | self.write_scalar(Scalar::from_bool(fn_sig_kind.c_variadic()), &field_place)?; |
| 438 | 438 | } |
| 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 | } | |
| 439 | 455 | other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), |
| 440 | 456 | } |
| 441 | 457 | } |
compiler/rustc_const_eval/src/interpret/call.rs+1| ... | ... | @@ -681,6 +681,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |
| 681 | 681 | }; |
| 682 | 682 | |
| 683 | 683 | // Special handling for the closure ABI: untuple the last argument. |
| 684 | // FIXME(splat): un-tuple splatted arguments that were tupled in typecheck | |
| 684 | 685 | let args: Cow<'_, [FnArg<'tcx, M::Provenance>]> = |
| 685 | 686 | if caller_abi == ExternAbi::RustCall && !args.is_empty() { |
| 686 | 687 | // Untuple |
compiler/rustc_hir/src/hir.rs+21-20| ... | ... | @@ -4045,12 +4045,12 @@ pub struct Param<'hir> { |
| 4045 | 4045 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 4046 | 4046 | pub enum SplattedArgIndexError { |
| 4047 | 4047 | /// 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 }, | |
| 4051 | 4051 | |
| 4052 | 4052 | /// 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 }, | |
| 4054 | 4054 | } |
| 4055 | 4055 | |
| 4056 | 4056 | /// Contains the packed non-type fields of a function declaration. |
| ... | ... | @@ -4061,9 +4061,9 @@ pub struct FnDeclFlags { |
| 4061 | 4061 | flags: u8, |
| 4062 | 4062 | |
| 4063 | 4063 | /// 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 | |
| 4065 | 4065 | /// details. |
| 4066 | splatted: u16, | |
| 4066 | splatted: u8, | |
| 4067 | 4067 | } |
| 4068 | 4068 | |
| 4069 | 4069 | impl fmt::Debug for FnDeclFlags { |
| ... | ... | @@ -4101,13 +4101,13 @@ impl FnDeclFlags { |
| 4101 | 4101 | |
| 4102 | 4102 | /// Marker index for "no splatted argument". |
| 4103 | 4103 | /// 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; | |
| 4105 | 4105 | |
| 4106 | 4106 | /// Create a new FnDeclKind with no implicit self, no lifetime elision, no C-style variadic |
| 4107 | 4107 | /// argument, and no splatting. |
| 4108 | 4108 | /// To modify these flags, use the `set_*` methods, for readability. |
| 4109 | 4109 | // FIXME: use Default instead when that trait is const stable. |
| 4110 | pub const fn default() -> Self { | |
| 4110 | pub fn default() -> Self { | |
| 4111 | 4111 | Self { flags: 0, splatted: 0 } |
| 4112 | 4112 | .set_implicit_self(ImplicitSelfKind::None) |
| 4113 | 4113 | .set_lifetime_elision_allowed(false) |
| ... | ... | @@ -4117,7 +4117,7 @@ impl FnDeclFlags { |
| 4117 | 4117 | |
| 4118 | 4118 | /// Set the implicit self kind. |
| 4119 | 4119 | #[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 { | |
| 4121 | 4121 | self.flags &= !Self::IMPLICIT_SELF_MASK; |
| 4122 | 4122 | |
| 4123 | 4123 | match implicit_self { |
| ... | ... | @@ -4133,7 +4133,7 @@ impl FnDeclFlags { |
| 4133 | 4133 | |
| 4134 | 4134 | /// Set the C-style variadic argument flag. |
| 4135 | 4135 | #[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 { | |
| 4137 | 4137 | if c_variadic { |
| 4138 | 4138 | self.flags |= Self::C_VARIADIC_FLAG; |
| 4139 | 4139 | } else { |
| ... | ... | @@ -4145,7 +4145,7 @@ impl FnDeclFlags { |
| 4145 | 4145 | |
| 4146 | 4146 | /// Set the lifetime elision allowed flag. |
| 4147 | 4147 | #[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 { | |
| 4149 | 4149 | if allowed { |
| 4150 | 4150 | self.flags |= Self::LIFETIME_ELISION_ALLOWED_FLAG; |
| 4151 | 4151 | } else { |
| ... | ... | @@ -4158,16 +4158,17 @@ impl FnDeclFlags { |
| 4158 | 4158 | /// Set the splatted argument index. |
| 4159 | 4159 | /// The number of function arguments is used for error checking. |
| 4160 | 4160 | #[must_use = "this method does not modify the receiver"] |
| 4161 | pub const fn set_splatted( | |
| 4161 | pub fn set_splatted( | |
| 4162 | 4162 | mut self, |
| 4163 | splatted: Option<u16>, | |
| 4163 | splatted: Option<u8>, | |
| 4164 | 4164 | args_len: usize, |
| 4165 | 4165 | ) -> Result<Self, SplattedArgIndexError> { |
| 4166 | 4166 | if let Some(splatted_arg_index) = splatted { |
| 4167 | 4167 | if splatted_arg_index == Self::NO_SPLATTED_ARG_INDEX { |
| 4168 | 4168 | // 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. | |
| 4169 | 4170 | 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 { | |
| 4171 | 4172 | return Err(SplattedArgIndexError::OutOfBounds { |
| 4172 | 4173 | splatted_arg_index, |
| 4173 | 4174 | args_len: args_len as u16, |
| ... | ... | @@ -4184,14 +4185,14 @@ impl FnDeclFlags { |
| 4184 | 4185 | |
| 4185 | 4186 | /// Set "no splatted arguments" for the function declaration. |
| 4186 | 4187 | #[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 { | |
| 4188 | 4189 | self.splatted = Self::NO_SPLATTED_ARG_INDEX; |
| 4189 | 4190 | |
| 4190 | 4191 | self |
| 4191 | 4192 | } |
| 4192 | 4193 | |
| 4193 | 4194 | /// Get the implicit self kind. |
| 4194 | pub const fn implicit_self(self) -> ImplicitSelfKind { | |
| 4195 | pub fn implicit_self(self) -> ImplicitSelfKind { | |
| 4195 | 4196 | match self.flags & Self::IMPLICIT_SELF_MASK { |
| 4196 | 4197 | 0 => ImplicitSelfKind::None, |
| 4197 | 4198 | 1 => ImplicitSelfKind::Imm, |
| ... | ... | @@ -4203,17 +4204,17 @@ impl FnDeclFlags { |
| 4203 | 4204 | } |
| 4204 | 4205 | |
| 4205 | 4206 | /// 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 { | |
| 4207 | 4208 | self.flags & Self::C_VARIADIC_FLAG != 0 |
| 4208 | 4209 | } |
| 4209 | 4210 | |
| 4210 | 4211 | /// Is lifetime elision allowed? |
| 4211 | pub const fn lifetime_elision_allowed(self) -> bool { | |
| 4212 | pub fn lifetime_elision_allowed(self) -> bool { | |
| 4212 | 4213 | self.flags & Self::LIFETIME_ELISION_ALLOWED_FLAG != 0 |
| 4213 | 4214 | } |
| 4214 | 4215 | |
| 4215 | 4216 | /// Get the splatted argument index, if any. |
| 4216 | pub const fn splatted(self) -> Option<u16> { | |
| 4217 | pub fn splatted(self) -> Option<u8> { | |
| 4217 | 4218 | if self.splatted == Self::NO_SPLATTED_ARG_INDEX { None } else { Some(self.splatted) } |
| 4218 | 4219 | } |
| 4219 | 4220 | } |
| ... | ... | @@ -4263,7 +4264,7 @@ impl<'hir> FnDecl<'hir> { |
| 4263 | 4264 | self.fn_decl_kind.lifetime_elision_allowed() |
| 4264 | 4265 | } |
| 4265 | 4266 | |
| 4266 | pub fn splatted(&self) -> Option<u16> { | |
| 4267 | pub fn splatted(&self) -> Option<u8> { | |
| 4267 | 4268 | self.fn_decl_kind.splatted() |
| 4268 | 4269 | } |
| 4269 | 4270 |
compiler/rustc_hir_analysis/src/check/mod.rs+3-1| ... | ... | @@ -444,11 +444,13 @@ fn fn_sig_suggestion<'tcx>( |
| 444 | 444 | predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, |
| 445 | 445 | assoc: ty::AssocItem, |
| 446 | 446 | ) -> String { |
| 447 | let splatted_arg_index = sig.splatted().map(usize::from); | |
| 447 | 448 | let args = sig |
| 448 | 449 | .inputs() |
| 449 | 450 | .iter() |
| 450 | 451 | .enumerate() |
| 451 | 452 | .map(|(i, ty)| { |
| 453 | let splat = if splatted_arg_index == Some(i) { "#[splat] " } else { "" }; | |
| 452 | 454 | let arg_ty = match ty.kind() { |
| 453 | 455 | ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(), |
| 454 | 456 | ty::Ref(reg, ref_ty, mutability) if i == 0 => { |
| ... | ... | @@ -477,7 +479,7 @@ fn fn_sig_suggestion<'tcx>( |
| 477 | 479 | } |
| 478 | 480 | } |
| 479 | 481 | }; |
| 480 | Some(format!("{arg_ty}")) | |
| 482 | Some(format!("{splat}{arg_ty}")) | |
| 481 | 483 | }) |
| 482 | 484 | .chain(std::iter::once(if sig.c_variadic() { Some("...".to_string()) } else { None })) |
| 483 | 485 | .flatten() |
compiler/rustc_hir_analysis/src/check/wfcheck.rs+10-1| ... | ... | @@ -1714,7 +1714,16 @@ fn check_fn_or_method<'tcx>( |
| 1714 | 1714 | let span = tcx.def_span(def_id); |
| 1715 | 1715 | let has_implicit_self = hir_decl.implicit_self().has_implicit_self(); |
| 1716 | 1716 | 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 | } | |
| 1718 | 1727 | // Check that the argument is a tuple and is sized |
| 1719 | 1728 | if let Some(ty) = inputs.next() { |
| 1720 | 1729 | wfcx.register_bound( |
compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs+3-2| ... | ... | @@ -3582,11 +3582,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 3582 | 3582 | debug!(?output_ty); |
| 3583 | 3583 | |
| 3584 | 3584 | debug!(?abi, ?safety, ?decl.fn_decl_kind, input_tys_len = ?input_tys.len()); |
| 3585 | // FIXME(splat): use `set_splatted()` once FnSig has it | |
| 3586 | 3585 | let fn_sig_kind = FnSigKind::default() |
| 3587 | 3586 | .set_abi(abi) |
| 3588 | 3587 | .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(); | |
| 3590 | 3591 | let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, fn_sig_kind); |
| 3591 | 3592 | let fn_ptr_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); |
| 3592 | 3593 |
compiler/rustc_hir_typeck/src/callee.rs+35-10| ... | ... | @@ -58,9 +58,13 @@ pub(crate) fn check_legal_trait_for_method_call( |
| 58 | 58 | tcx.ensure_result().coherent_trait(trait_id) |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | /// State machine for typechecking a call, based on the callee type. | |
| 61 | 62 | #[derive(Debug)] |
| 62 | 63 | enum CallStep<'tcx> { |
| 64 | /// Typecheck a call to a function definition or pointer. | |
| 65 | /// Includes functions with splatted arguments. | |
| 63 | 66 | Builtin(Ty<'tcx>), |
| 67 | /// Deferred closure Fn* trait typechecking, when the callee is a closure. | |
| 64 | 68 | DeferredClosure(LocalDefId, ty::FnSig<'tcx>), |
| 65 | 69 | /// Call overloading when callee implements one of the Fn* traits. |
| 66 | 70 | Overloaded(MethodCallee<'tcx>), |
| ... | ... | @@ -544,7 +548,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 544 | 548 | arg_exprs: &'tcx [hir::Expr<'tcx>], |
| 545 | 549 | expected: Expectation<'tcx>, |
| 546 | 550 | ) -> 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() { | |
| 548 | 552 | ty::FnDef(def_id, args) => { |
| 549 | 553 | self.enforce_context_effects(Some(call_expr.hir_id), call_expr.span, def_id, args); |
| 550 | 554 | 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> { |
| 573 | 577 | .emit(); |
| 574 | 578 | } |
| 575 | 579 | } |
| 576 | (fn_sig, Some(def_id)) | |
| 580 | (fn_sig, Some(def_id), Some(args)) | |
| 577 | 581 | } |
| 578 | 582 | |
| 579 | 583 | // 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), | |
| 581 | 585 | |
| 582 | 586 | _ => unreachable!(), |
| 583 | 587 | }; |
| ... | ... | @@ -595,12 +599,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 595 | 599 | let fn_sig = self.normalize(call_expr.span, Unnormalized::new_wip(fn_sig)); |
| 596 | 600 | |
| 597 | 601 | 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, | |
| 599 | 609 | ); |
| 600 | 610 | |
| 611 | // Splatting is currently incompatible with RustCall. | |
| 601 | 612 | if fn_sig.abi() == rustc_abi::ExternAbi::RustCall { |
| 602 | 613 | 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 | { | |
| 604 | 617 | self.register_bound( |
| 605 | 618 | ty, |
| 606 | 619 | self.tcx.require_lang_item(hir::LangItem::Tuple, sp), |
| ... | ... | @@ -627,7 +640,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 627 | 640 | call_expr: &'tcx hir::Expr<'tcx>, |
| 628 | 641 | arg_exprs: &'tcx [hir::Expr<'tcx>], |
| 629 | 642 | expected: Expectation<'tcx>, |
| 643 | tuple_arguments_flag: TupleArgumentsFlag, | |
| 630 | 644 | def_id: Option<DefId>, |
| 645 | callee_generic_args: Option<GenericArgsRef<'tcx>>, | |
| 631 | 646 | ) { |
| 632 | 647 | let do_check = || { |
| 633 | 648 | self.check_argument_types( |
| ... | ... | @@ -638,8 +653,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 638 | 653 | expected, |
| 639 | 654 | arg_exprs, |
| 640 | 655 | fn_sig.c_variadic(), |
| 641 | TupleArgumentsFlag::DontTupleArguments, | |
| 656 | tuple_arguments_flag, | |
| 642 | 657 | def_id, |
| 658 | callee_generic_args, | |
| 643 | 659 | ); |
| 644 | 660 | }; |
| 645 | 661 | |
| ... | ... | @@ -1009,9 +1025,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1009 | 1025 | fn_sig.output(), |
| 1010 | 1026 | expected, |
| 1011 | 1027 | arg_exprs, |
| 1012 | fn_sig.c_variadic(), | |
| 1013 | TupleArgumentsFlag::TupleArguments, | |
| 1028 | fn_sig.fn_sig_kind.c_variadic(), | |
| 1029 | TupleArgumentsFlag::rust_fn_trait_call(), | |
| 1014 | 1030 | Some(closure_def_id.to_def_id()), |
| 1031 | None, | |
| 1015 | 1032 | ); |
| 1016 | 1033 | |
| 1017 | 1034 | fn_sig.output() |
| ... | ... | @@ -1092,6 +1109,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1092 | 1109 | expected: Expectation<'tcx>, |
| 1093 | 1110 | method: MethodCallee<'tcx>, |
| 1094 | 1111 | ) -> 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 | ); | |
| 1095 | 1119 | self.check_argument_types( |
| 1096 | 1120 | call_expr.span, |
| 1097 | 1121 | call_expr, |
| ... | ... | @@ -1099,9 +1123,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1099 | 1123 | method.sig.output(), |
| 1100 | 1124 | expected, |
| 1101 | 1125 | arg_exprs, |
| 1102 | method.sig.c_variadic(), | |
| 1103 | TupleArgumentsFlag::TupleArguments, | |
| 1126 | method.sig.fn_sig_kind.c_variadic(), | |
| 1127 | TupleArgumentsFlag::rust_fn_trait_call(), | |
| 1104 | 1128 | Some(method.def_id), |
| 1129 | None, | |
| 1105 | 1130 | ); |
| 1106 | 1131 | |
| 1107 | 1132 | 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> { |
| 720 | 720 | // in this binder we are creating. |
| 721 | 721 | assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST)); |
| 722 | 722 | let bound_sig = expected_sig.sig.map_bound(|sig| { |
| 723 | // Ignore splatting, it is unsupported on closures. | |
| 723 | 724 | let fn_sig_kind = FnSigKind::default() |
| 724 | 725 | .set_abi(ExternAbi::RustCall) |
| 725 | 726 | .set_safety(hir::Safety::Safe) |
compiler/rustc_hir_typeck/src/demand.rs+15-2| ... | ... | @@ -3,11 +3,11 @@ use rustc_hir::def::Res; |
| 3 | 3 | use rustc_hir::intravisit::Visitor; |
| 4 | 4 | use rustc_hir::{self as hir, find_attr}; |
| 5 | 5 | use rustc_infer::infer::DefineOpaqueTypes; |
| 6 | use rustc_middle::bug; | |
| 7 | 6 | use rustc_middle::ty::adjustment::AllowTwoPhase; |
| 8 | 7 | use rustc_middle::ty::error::{ExpectedFound, TypeError}; |
| 9 | 8 | use rustc_middle::ty::print::with_no_trimmed_paths; |
| 10 | 9 | use rustc_middle::ty::{self, AssocItem, BottomUpFolder, Ty, TypeFoldable, TypeVisitableExt}; |
| 10 | use rustc_middle::{bug, span_bug}; | |
| 11 | 11 | use rustc_span::{DUMMY_SP, Ident, Span, sym}; |
| 12 | 12 | use rustc_trait_selection::infer::InferCtxtExt; |
| 13 | 13 | use rustc_trait_selection::traits::ObligationCause; |
| ... | ... | @@ -402,9 +402,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 402 | 402 | // Unify the method signature with our incompatible arg, to |
| 403 | 403 | // do inference in the *opposite* direction and to find out |
| 404 | 404 | // 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 | }; | |
| 405 | 418 | let _ = self |
| 406 | 419 | .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) | |
| 408 | 421 | .ok()?; |
| 409 | 422 | self.select_obligations_where_possible(|errs| { |
| 410 | 423 | // Yeet the errors, we're already reporting errors. |
compiler/rustc_hir_typeck/src/diagnostics.rs+1| ... | ... | @@ -100,6 +100,7 @@ impl IntoDiagArg for ReturnLikeStatementKind { |
| 100 | 100 | } |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | // FIXME(splat): add "non-splatted" to all 4 instances of this error message | |
| 103 | 104 | #[derive(Diagnostic)] |
| 104 | 105 | #[diag("functions with the \"rust-call\" ABI must take a single non-self tuple argument")] |
| 105 | 106 | pub(crate) struct RustCallIncorrectArgs { |
compiler/rustc_hir_typeck/src/expr.rs+11-3| ... | ... | @@ -1463,16 +1463,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1463 | 1463 | Ok(method) => { |
| 1464 | 1464 | self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); |
| 1465 | 1465 | |
| 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 | ||
| 1466 | 1472 | self.check_argument_types( |
| 1467 | 1473 | segment.ident.span, |
| 1468 | 1474 | expr, |
| 1469 | &method.sig.inputs()[1..], | |
| 1475 | method_inputs, | |
| 1470 | 1476 | method.sig.output(), |
| 1471 | 1477 | expected, |
| 1472 | 1478 | args, |
| 1473 | method.sig.c_variadic(), | |
| 1474 | TupleArgumentsFlag::DontTupleArguments, | |
| 1479 | method.sig.fn_sig_kind.c_variadic(), | |
| 1480 | method_tuple_args_flag, | |
| 1475 | 1481 | Some(method.def_id), |
| 1482 | Some(method.args), | |
| 1476 | 1483 | ); |
| 1477 | 1484 | |
| 1478 | 1485 | self.check_call_abi(method.sig.abi(), expr.span); |
| ... | ... | @@ -1495,6 +1502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1495 | 1502 | false, |
| 1496 | 1503 | TupleArgumentsFlag::DontTupleArguments, |
| 1497 | 1504 | None, |
| 1505 | Some(GenericArgsRef::default()), | |
| 1498 | 1506 | ); |
| 1499 | 1507 | |
| 1500 | 1508 | err_output |
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs+38-3| ... | ... | @@ -27,8 +27,8 @@ use rustc_middle::ty::adjustment::{ |
| 27 | 27 | }; |
| 28 | 28 | use rustc_middle::ty::{ |
| 29 | 29 | 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, | |
| 32 | 32 | }; |
| 33 | 33 | use rustc_middle::{bug, span_bug}; |
| 34 | 34 | use rustc_session::lint; |
| ... | ... | @@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 143 | 143 | /// also select obligations if it seems useful, in an effort |
| 144 | 144 | /// to get more type information. |
| 145 | 145 | // 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. | |
| 147 | 147 | #[instrument(skip(self), level = "debug", ret)] |
| 148 | 148 | pub(crate) fn resolve_vars_with_obligations<T: TypeFoldable<TyCtxt<'tcx>>>( |
| 149 | 149 | &self, |
| ... | ... | @@ -236,6 +236,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 236 | 236 | self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); |
| 237 | 237 | } |
| 238 | 238 | |
| 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 | ||
| 239 | 248 | #[instrument(level = "debug", skip(self))] |
| 240 | 249 | pub(crate) fn write_method_call_and_enforce_effects( |
| 241 | 250 | &self, |
| ... | ... | @@ -248,6 +257,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 248 | 257 | self.write_args(hir_id, method.args); |
| 249 | 258 | } |
| 250 | 259 | |
| 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 | ||
| 251 | 286 | fn write_args(&self, node_id: HirId, args: GenericArgsRef<'tcx>) { |
| 252 | 287 | if !args.is_empty() { |
| 253 | 288 | 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! { |
| 50 | 50 | pub(crate) struct GenericIdx {} |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | /// Outcome of checking arguments that are tupled by "rust-call" or `#[splat]`. | |
| 54 | #[derive(Debug, Clone, Eq, PartialEq)] | |
| 55 | struct 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 | ||
| 53 | 66 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 54 | 67 | pub(in super::super) fn check_casts(&mut self) { |
| 55 | 68 | let mut deferred_cast_checks = self.root_ctxt.deferred_cast_checks.borrow_mut(); |
| ... | ... | @@ -185,13 +198,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 185 | 198 | expectation: Expectation<'tcx>, |
| 186 | 199 | // The expressions for each provided argument |
| 187 | 200 | 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) | |
| 190 | 202 | 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 | |
| 192 | 204 | tuple_arguments: TupleArgumentsFlag, |
| 193 | 205 | // The DefId for the function being called, for better error messages |
| 194 | 206 | 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>>, | |
| 195 | 209 | ) { |
| 196 | 210 | let tcx = self.tcx; |
| 197 | 211 | |
| ... | ... | @@ -220,11 +234,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 220 | 234 | } |
| 221 | 235 | |
| 222 | 236 | // 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 | |
| 224 | 238 | // any remaining type variables are assigned to new, unrelated variables. This |
| 225 | 239 | // is because the inference guidance here is only speculative. |
| 240 | // FIXME(splat): do we need to splat arguments before this type inference? | |
| 226 | 241 | 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 | |
| 228 | 243 | .only_has_type(self) |
| 229 | 244 | .and_then(|expected_output| { |
| 230 | 245 | // FIXME(#149379): This operation results in expected input |
| ... | ... | @@ -272,45 +287,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 272 | 287 | |
| 273 | 288 | let mut err_code = E0061; |
| 274 | 289 | |
| 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; | |
| 310 | 314 | } |
| 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 | } | |
| 314 | 318 | |
| 315 | 319 | // If there are no external expectations at the call site, just use the types from the function defn |
| 316 | 320 | let expected_input_tys = if let Some(expected_input_tys) = expected_input_tys { |
| ... | ... | @@ -556,6 +560,257 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 556 | 560 | } |
| 557 | 561 | } |
| 558 | 562 | |
| 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 | ||
| 559 | 814 | /// If `unsized_fn_params` is active, check that unsized values are place expressions. Since |
| 560 | 815 | /// the removal of `unsized_locals` in <https://github.com/rust-lang/rust/pull/142911> we can't |
| 561 | 816 | /// store them in MIR locals as temporaries. |
| ... | ... | @@ -581,6 +836,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 581 | 836 | fn_def_id: Option<DefId>, |
| 582 | 837 | call_span: Span, |
| 583 | 838 | call_expr: &'tcx hir::Expr<'tcx>, |
| 839 | // FIXME(splat): when the feature design is settled, improve the errors here | |
| 584 | 840 | tuple_arguments: TupleArgumentsFlag, |
| 585 | 841 | ) -> ErrorGuaranteed { |
| 586 | 842 | // Next, let's construct the error |
| ... | ... | @@ -1354,8 +1610,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1354 | 1610 | // If we're calling a method of a Fn/FnMut/FnOnce trait object implicitly |
| 1355 | 1611 | // (eg invoking a closure) we want to point at the underlying callable, |
| 1356 | 1612 | // 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 | |
| 1359 | 1616 | && let Some(assoc_item) = self.tcx.opt_associated_item(def_id) |
| 1360 | 1617 | // Since this is an associated item, it might point at either an impl or a trait item. |
| 1361 | 1618 | // We want it to always point to the trait item. |
| ... | ... | @@ -1442,25 +1699,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1442 | 1699 | deps: SmallVec<[ExpectedIdx; 4]>, |
| 1443 | 1700 | } |
| 1444 | 1701 | |
| 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 | } | |
| 1446 | 1706 | // Gather all mismatched parameters with generics. |
| 1447 | 1707 | let mut mismatched_params = Vec::<MismatchedParam<'_>>::new(); |
| 1708 | let mut use_splat_fallback = false; | |
| 1448 | 1709 | if let Some(expected_idx) = expected_idx { |
| 1449 | 1710 | 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 { | |
| 1464 | 1740 | mismatched_params.extend( |
| 1465 | 1741 | params_with_generics.iter_enumerated().zip(matched_inputs).filter_map( |
| 1466 | 1742 | |((idx, &(generic, ref param)), matched_idx)| { |
| ... | ... | @@ -1671,15 +1947,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1671 | 1947 | provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>, |
| 1672 | 1948 | formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, |
| 1673 | 1949 | is_method: bool, |
| 1950 | is_splat: bool, | |
| 1674 | 1951 | ) { |
| 1675 | 1952 | let Some(def_id) = callable_def_id else { |
| 1676 | 1953 | return; |
| 1677 | 1954 | }; |
| 1678 | 1955 | |
| 1679 | 1956 | 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 | } | |
| 1681 | 1961 | 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() { | |
| 1683 | 1963 | continue; |
| 1684 | 1964 | } |
| 1685 | 1965 | |
| ... | ... | @@ -1701,7 +1981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1701 | 1981 | let Some(other_generic_param) = other_generic_param else { |
| 1702 | 1982 | return false; |
| 1703 | 1983 | }; |
| 1704 | if matched_inputs[other_idx].is_some() { | |
| 1984 | if matched_inputs.get(other_idx).flatten_ref().is_some() { | |
| 1705 | 1985 | return false; |
| 1706 | 1986 | } |
| 1707 | 1987 | other_generic_param == generic_param |
| ... | ... | @@ -2004,7 +2284,11 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> { |
| 2004 | 2284 | self.arg_matching_ctxt.args_ctxt.call_metadata.full_call_span, |
| 2005 | 2285 | format!( |
| 2006 | 2286 | "{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 | }, | |
| 2008 | 2292 | potentially_plural_count( |
| 2009 | 2293 | self.formal_and_expected_inputs.len(), |
| 2010 | 2294 | "argument" |
| ... | ... | @@ -2147,14 +2431,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> { |
| 2147 | 2431 | format!("arguments to this {call_name} are incorrect"), |
| 2148 | 2432 | ); |
| 2149 | 2433 | |
| 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); | |
| 2158 | 2435 | |
| 2159 | 2436 | if let hir::ExprKind::MethodCall(_, rcvr, _, _) = |
| 2160 | 2437 | self.arg_matching_ctxt.args_ctxt.call_ctxt.call_expr.kind |
| ... | ... | @@ -2237,7 +2514,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> { |
| 2237 | 2514 | format!( |
| 2238 | 2515 | "this {} takes {}{} but {} {} supplied", |
| 2239 | 2516 | 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 { "" }, | |
| 2241 | 2518 | potentially_plural_count(self.formal_and_expected_inputs.len(), "argument"), |
| 2242 | 2519 | potentially_plural_count(self.provided_args.len(), "argument"), |
| 2243 | 2520 | pluralize!("was", self.provided_args.len()) |
| ... | ... | @@ -2614,6 +2891,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> { |
| 2614 | 2891 | &self.provided_arg_tys, |
| 2615 | 2892 | &self.formal_and_expected_inputs, |
| 2616 | 2893 | self.call_metadata.is_method, |
| 2894 | self.arg_matching_ctxt.tuple_arguments.is_splatted(), | |
| 2617 | 2895 | ); |
| 2618 | 2896 | } |
| 2619 | 2897 |
compiler/rustc_hir_typeck/src/lib.rs+69-8| ... | ... | @@ -3,6 +3,7 @@ |
| 3 | 3 | #![feature(iter_intersperse)] |
| 4 | 4 | #![feature(iter_order_by)] |
| 5 | 5 | #![feature(never_type)] |
| 6 | #![feature(option_reference_flattening)] | |
| 6 | 7 | #![feature(trim_prefix_suffix)] |
| 7 | 8 | // tidy-alphabetical-end |
| 8 | 9 | |
| ... | ... | @@ -50,7 +51,7 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; |
| 50 | 51 | use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; |
| 51 | 52 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
| 52 | 53 | use rustc_middle::query::Providers; |
| 53 | use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized}; | |
| 54 | use rustc_middle::ty::{self, FnSigKind, Ty, TyCtxt, Unnormalized}; | |
| 54 | 55 | use rustc_middle::{bug, span_bug}; |
| 55 | 56 | use rustc_session::config; |
| 56 | 57 | use rustc_span::Span; |
| ... | ... | @@ -589,12 +590,10 @@ fn report_unexpected_variant_res( |
| 589 | 590 | .emit() |
| 590 | 591 | } |
| 591 | 592 | |
| 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. | |
| 594 | 594 | /// |
| 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: | |
| 598 | 597 | /// ``` |
| 599 | 598 | /// fn f(x: (isize, isize)) {} |
| 600 | 599 | /// ``` |
| ... | ... | @@ -608,10 +607,72 @@ fn report_unexpected_variant_res( |
| 608 | 607 | /// # fn f(x: (isize, isize)) {} |
| 609 | 608 | /// f((1, 2)); |
| 610 | 609 | /// ``` |
| 611 | #[derive(Copy, Clone, Eq, PartialEq)] | |
| 610 | /// | |
| 611 | /// Note: splatted arguments are handled separately. | |
| 612 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | |
| 612 | 613 | enum TupleArgumentsFlag { |
| 614 | /// Arguments are typechecked unchanged. | |
| 613 | 615 | 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 | ||
| 625 | impl 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 | } | |
| 615 | 676 | } |
| 616 | 677 | |
| 617 | 678 | fn 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> { |
| 663 | 663 | self.typeck_results.type_dependent_defs_mut().insert(hir_id, def); |
| 664 | 664 | } |
| 665 | 665 | |
| 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 | ||
| 666 | 671 | // Resolve any borrowings for the node with id `node_id` |
| 667 | 672 | self.visit_adjustments(span, hir_id); |
| 668 | 673 |
compiler/rustc_interface/src/passes.rs+2-2| ... | ... | @@ -803,8 +803,8 @@ fn resolver_for_lowering_raw<'tcx>( |
| 803 | 803 | ); |
| 804 | 804 | let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver); |
| 805 | 805 | |
| 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(); | |
| 808 | 808 | |
| 809 | 809 | let ResolverOutputs { |
| 810 | 810 | global_ctxt: untracked_resolutions, |
compiler/rustc_lint/src/foreign_modules.rs+8| ... | ... | @@ -329,6 +329,14 @@ fn structurally_same_type_impl<'tcx>( |
| 329 | 329 | let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig); |
| 330 | 330 | let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig); |
| 331 | 331 | |
| 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 | ||
| 332 | 340 | (a_sig.abi(), a_sig.safety(), a_sig.c_variadic()) |
| 333 | 341 | == (b_sig.abi(), b_sig.safety(), b_sig.c_variadic()) |
| 334 | 342 | && 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) { |
| 556 | 556 | ) |
| 557 | 557 | }, |
| 558 | 558 | 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(); | |
| 562 | 562 | tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum)) |
| 563 | 563 | }, |
| 564 | 564 | 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(); | |
| 568 | 568 | tcx.arena.alloc_from_iter( |
| 569 | 569 | CStore::from_tcx(tcx) |
| 570 | 570 | .iter_crate_data() |
compiler/rustc_middle/src/ty/context.rs+2| ... | ... | @@ -2085,6 +2085,8 @@ impl<'tcx> TyCtxt<'tcx> { |
| 2085 | 2085 | ty::Tuple(params) => *params, |
| 2086 | 2086 | _ => bug!(), |
| 2087 | 2087 | }; |
| 2088 | // Ignore splatting, it is unsupported on closures. | |
| 2089 | assert!(s.splatted().is_none()); | |
| 2088 | 2090 | self.mk_fn_sig( |
| 2089 | 2091 | params, |
| 2090 | 2092 | s.output(), |
compiler/rustc_middle/src/ty/error.rs+14| ... | ... | @@ -96,6 +96,20 @@ impl<'tcx> TypeError<'tcx> { |
| 96 | 96 | if values.found { "variadic" } else { "non-variadic" } |
| 97 | 97 | ) |
| 98 | 98 | .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(), | |
| 99 | 113 | TypeError::ProjectionMismatched(ref values) => format!( |
| 100 | 114 | "expected `{}`, found `{}`", |
| 101 | 115 | 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::{ |
| 113 | 113 | pub use self::trait_def::TraitDef; |
| 114 | 114 | pub use self::typeck_results::{ |
| 115 | 115 | CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity, |
| 116 | Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, | |
| 116 | Rust2024IncompatiblePatInfo, SplattedDef, TypeckResults, UserType, UserTypeAnnotationIndex, | |
| 117 | UserTypeKind, | |
| 117 | 118 | }; |
| 118 | 119 | use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; |
| 119 | 120 | use 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 { |
| 1435 | 1435 | p.pretty_print_fn_sig( |
| 1436 | 1436 | tys, |
| 1437 | 1437 | false, |
| 1438 | // FIXME(splat): support splatted arguments here? | |
| 1439 | None, | |
| 1438 | 1440 | proj.skip_binder().term.as_type().expect("Return type was a const"), |
| 1439 | 1441 | )?; |
| 1440 | 1442 | resugared = true; |
| ... | ... | @@ -1538,10 +1540,19 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { |
| 1538 | 1540 | &mut self, |
| 1539 | 1541 | inputs: &[Ty<'tcx>], |
| 1540 | 1542 | c_variadic: bool, |
| 1543 | splatted: Option<u8>, | |
| 1541 | 1544 | output: Ty<'tcx>, |
| 1542 | 1545 | ) -> Result<(), PrintError> { |
| 1543 | 1546 | 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 | } | |
| 1545 | 1556 | if c_variadic { |
| 1546 | 1557 | if !inputs.is_empty() { |
| 1547 | 1558 | write!(self, ", ")?; |
| ... | ... | @@ -3150,7 +3161,7 @@ define_print! { |
| 3150 | 3161 | } |
| 3151 | 3162 | |
| 3152 | 3163 | 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())?; | |
| 3154 | 3165 | } |
| 3155 | 3166 | |
| 3156 | 3167 | ty::TraitRef<'tcx> { |
compiler/rustc_middle/src/ty/typeck_results.rs+35| ... | ... | @@ -36,6 +36,9 @@ pub struct TypeckResults<'tcx> { |
| 36 | 36 | /// method calls, including those of overloaded operators. |
| 37 | 37 | type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>, |
| 38 | 38 | |
| 39 | /// Resolved definitions for splatted function calls. | |
| 40 | splatted_defs: ItemLocalMap<Result<SplattedDef, ErrorGuaranteed>>, | |
| 41 | ||
| 39 | 42 | /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`) |
| 40 | 43 | /// or patterns (`S { field }`). The index is often useful by itself, but to learn more |
| 41 | 44 | /// about the field you also need definition of the variant to which the field |
| ... | ... | @@ -229,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> { |
| 229 | 232 | TypeckResults { |
| 230 | 233 | hir_owner, |
| 231 | 234 | type_dependent_defs: Default::default(), |
| 235 | splatted_defs: Default::default(), | |
| 232 | 236 | field_indices: Default::default(), |
| 233 | 237 | user_provided_types: Default::default(), |
| 234 | 238 | user_provided_sigs: Default::default(), |
| ... | ... | @@ -287,6 +291,21 @@ impl<'tcx> TypeckResults<'tcx> { |
| 287 | 291 | LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs } |
| 288 | 292 | } |
| 289 | 293 | |
| 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 | ||
| 290 | 309 | pub fn field_indices(&self) -> LocalTableInContext<'_, FieldIdx> { |
| 291 | 310 | LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices } |
| 292 | 311 | } |
| ... | ... | @@ -407,6 +426,10 @@ impl<'tcx> TypeckResults<'tcx> { |
| 407 | 426 | matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _)))) |
| 408 | 427 | } |
| 409 | 428 | |
| 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 | ||
| 410 | 433 | /// Returns the computed binding mode for a `PatKind::Binding` pattern |
| 411 | 434 | /// (after match ergonomics adjustments). |
| 412 | 435 | pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> BindingMode { |
| ... | ... | @@ -569,6 +592,18 @@ impl<'tcx> TypeckResults<'tcx> { |
| 569 | 592 | } |
| 570 | 593 | } |
| 571 | 594 | |
| 595 | /// A resolved splatted function call. | |
| 596 | #[derive(Debug, Copy, Clone, PartialEq, Eq, StableHash, TyEncodable, TyDecodable)] | |
| 597 | pub 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 | ||
| 572 | 607 | /// Validate that the given HirId (respectively its `local_id` part) can be |
| 573 | 608 | /// safely used as a key in the maps of a TypeckResults. For that to be |
| 574 | 609 | /// 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>( |
| 547 | 547 | |
| 548 | 548 | body.spread_arg = if abi == ExternAbi::RustCall { |
| 549 | 549 | // RustCall pseudo-ABI untuples the last argument. |
| 550 | // FIXME(splat): splat can untuple any argument, set spread_arg here | |
| 550 | 551 | Some(Local::new(arguments.len())) |
| 551 | 552 | } else { |
| 552 | 553 | None |
compiler/rustc_mir_build/src/thir/cx/expr.rs+136-15| ... | ... | @@ -18,8 +18,8 @@ use rustc_middle::ty::adjustment::{ |
| 18 | 18 | Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, DerefAdjustKind, PointerCoercion, |
| 19 | 19 | }; |
| 20 | 20 | use 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, | |
| 23 | 23 | }; |
| 24 | 24 | use rustc_middle::{bug, span_bug}; |
| 25 | 25 | use rustc_span::{DesugaringKind, Span}; |
| ... | ... | @@ -369,19 +369,26 @@ impl<'tcx> ThirBuildCx<'tcx> { |
| 369 | 369 | let kind = match expr.kind { |
| 370 | 370 | // Here comes the interesting stuff: |
| 371 | 371 | 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 | } | |
| 385 | 392 | } |
| 386 | 393 | } |
| 387 | 394 | |
| ... | ... | @@ -412,6 +419,10 @@ impl<'tcx> ThirBuildCx<'tcx> { |
| 412 | 419 | from_hir_call: true, |
| 413 | 420 | fn_span: expr.span, |
| 414 | 421 | } |
| 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) | |
| 415 | 426 | } else { |
| 416 | 427 | // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. |
| 417 | 428 | let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind |
| ... | ... | @@ -1205,6 +1216,116 @@ impl<'tcx> ThirBuildCx<'tcx> { |
| 1205 | 1216 | } |
| 1206 | 1217 | } |
| 1207 | 1218 | |
| 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 | ||
| 1208 | 1329 | fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { |
| 1209 | 1330 | let arm = Arm { |
| 1210 | 1331 | 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 |
| 462 | 462 | Ok(i) => Ok(i), |
| 463 | 463 | Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution), |
| 464 | 464 | 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. | |
| 466 | 466 | assert!(opaque_accesses.should_bail().is_err()); |
| 467 | 467 | Err(NoSolution) |
| 468 | 468 | } |
| ... | ... | @@ -1442,7 +1442,7 @@ where |
| 1442 | 1442 | uv: ty::UnevaluatedConst<I>, |
| 1443 | 1443 | ) -> Result<Option<I::Const>, RerunNonErased> { |
| 1444 | 1444 | 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)? {} | |
| 1446 | 1446 | } |
| 1447 | 1447 | |
| 1448 | 1448 | Ok(self.delegate.evaluate_const(param_env, uv)) |
| ... | ... | @@ -1515,7 +1515,7 @@ where |
| 1515 | 1515 | symbol: I::Symbol, |
| 1516 | 1516 | ) -> Result<bool, RerunNonErased> { |
| 1517 | 1517 | 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)? {} | |
| 1519 | 1519 | } |
| 1520 | 1520 | |
| 1521 | 1521 | 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 |
| 98 | 98 | |
| 99 | 99 | outer.opaque_accesses.update(nested.opaque_accesses)?; |
| 100 | 100 | |
| 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(); | |
| 105 | 103 | |
| 106 | 104 | if !nested.inspect.is_noop() { |
| 107 | 105 | let probe_kind = probe_kind(&r); |
compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs+18-32| ... | ... | @@ -81,15 +81,10 @@ where |
| 81 | 81 | None |
| 82 | 82 | }, |
| 83 | 83 | |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 | }) | |
| 93 | 88 | }, |
| 94 | 89 | ) |
| 95 | 90 | } |
| ... | ... | @@ -351,11 +346,9 @@ where |
| 351 | 346 | GoalSource::Misc, |
| 352 | 347 | goal.with(cx, PredicateKind::Ambiguous), |
| 353 | 348 | )?; |
| 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 | ); | |
| 359 | 352 | } |
| 360 | 353 | // Outside of coherence, we treat the associated item as rigid instead. |
| 361 | 354 | ty::TypingMode::Typeck { .. } |
| ... | ... | @@ -367,11 +360,9 @@ where |
| 367 | 360 | goal, |
| 368 | 361 | goal.predicate.alias, |
| 369 | 362 | ); |
| 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 | ); | |
| 375 | 366 | } |
| 376 | 367 | }; |
| 377 | 368 | } |
| ... | ... | @@ -401,10 +392,10 @@ where |
| 401 | 392 | // This is not the case here and we only prefer adding an ambiguous |
| 402 | 393 | // nested goal for consistency. |
| 403 | 394 | 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); | |
| 405 | 396 | } else { |
| 406 | 397 | 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); | |
| 408 | 399 | } |
| 409 | 400 | } else { |
| 410 | 401 | return error_response(ecx, cx.delay_bug("missing item")); |
| ... | ... | @@ -472,7 +463,7 @@ where |
| 472 | 463 | }; |
| 473 | 464 | |
| 474 | 465 | 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) | |
| 476 | 467 | }) |
| 477 | 468 | } |
| 478 | 469 | |
| ... | ... | @@ -572,7 +563,6 @@ where |
| 572 | 563 | pred, |
| 573 | 564 | [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))], |
| 574 | 565 | ) |
| 575 | .map_err(Into::into) | |
| 576 | 566 | } |
| 577 | 567 | |
| 578 | 568 | fn consider_builtin_async_fn_trait_candidates( |
| ... | ... | @@ -759,8 +749,9 @@ where |
| 759 | 749 | // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. |
| 760 | 750 | // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't |
| 761 | 751 | // 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| { | |
| 764 | 755 | let sized_predicate = ty::TraitRef::new( |
| 765 | 756 | cx, |
| 766 | 757 | cx.require_trait_lang_item(SolverTraitLangItem::Sized), |
| ... | ... | @@ -769,12 +760,8 @@ where |
| 769 | 760 | ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate))?; |
| 770 | 761 | ecx.instantiate_normalizes_to_term(goal, Ty::new_unit(cx).into())?; |
| 771 | 762 | 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()?; | |
| 778 | 765 | |
| 779 | 766 | // In case the dummy alias-bound candidate does not apply, we instead treat this projection |
| 780 | 767 | // as rigid. |
| ... | ... | @@ -900,7 +887,6 @@ where |
| 900 | 887 | // but that's already proven by the generator being WF. |
| 901 | 888 | [], |
| 902 | 889 | ) |
| 903 | .map_err(Into::into) | |
| 904 | 890 | } |
| 905 | 891 | |
| 906 | 892 | 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; |
| 4 | 4 | use rustc_type_ir::data_structures::ensure_sufficient_stack; |
| 5 | 5 | use rustc_type_ir::search_graph::{self, PathKind}; |
| 6 | 6 | use rustc_type_ir::solve::{ |
| 7 | AccessedOpaques, CanonicalInput, Certainty, NoSolution, NoSolutionOrRerunNonErased, QueryResult, | |
| 7 | AccessedOpaques, CanonicalInput, Certainty, NoSolution, QueryResult, RerunResultExt, | |
| 8 | 8 | }; |
| 9 | 9 | use rustc_type_ir::{Interner, MayBeErased, TypingMode}; |
| 10 | 10 | |
| ... | ... | @@ -141,17 +141,8 @@ where |
| 141 | 141 | ) -> (QueryResult<I>, AccessedOpaques<I>) { |
| 142 | 142 | ensure_sufficient_stack(|| { |
| 143 | 143 | 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()?; | |
| 155 | 146 | |
| 156 | 147 | ecx.inspect.query_result(result); |
| 157 | 148 | result.map_err(Into::into) |
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+6-11| ... | ... | @@ -119,7 +119,7 @@ where |
| 119 | 119 | .map(|pred| goal.with(cx, pred)), |
| 120 | 120 | )?; |
| 121 | 121 | |
| 122 | then(ecx, maximal_certainty).map_err(Into::into) | |
| 122 | then(ecx, maximal_certainty) | |
| 123 | 123 | }) |
| 124 | 124 | } |
| 125 | 125 | |
| ... | ... | @@ -399,7 +399,6 @@ where |
| 399 | 399 | pred, |
| 400 | 400 | [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))], |
| 401 | 401 | ) |
| 402 | .map_err(Into::into) | |
| 403 | 402 | } |
| 404 | 403 | |
| 405 | 404 | fn consider_builtin_async_fn_trait_candidates( |
| ... | ... | @@ -450,7 +449,6 @@ where |
| 450 | 449 | .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred))) |
| 451 | 450 | .map(|goal| (GoalSource::ImplWhereBound, goal)), |
| 452 | 451 | ) |
| 453 | .map_err(Into::into) | |
| 454 | 452 | } |
| 455 | 453 | |
| 456 | 454 | fn consider_builtin_async_fn_kind_helper_candidate( |
| ... | ... | @@ -696,7 +694,7 @@ where |
| 696 | 694 | goal.predicate.trait_ref.args.type_at(1), |
| 697 | 695 | assume, |
| 698 | 696 | )?; |
| 699 | ecx.evaluate_added_goals_and_make_canonical_response(certainty).map_err(Into::into) | |
| 697 | ecx.evaluate_added_goals_and_make_canonical_response(certainty) | |
| 700 | 698 | }, |
| 701 | 699 | ) |
| 702 | 700 | } |
| ... | ... | @@ -1085,7 +1083,6 @@ where |
| 1085 | 1083 | ecx.try_evaluate_added_goals() |
| 1086 | 1084 | }, |
| 1087 | 1085 | ) |
| 1088 | .map_err(Into::into) | |
| 1089 | 1086 | }) |
| 1090 | 1087 | .is_ok() |
| 1091 | 1088 | }; |
| ... | ... | @@ -1124,11 +1121,9 @@ where |
| 1124 | 1121 | return Err(NoSolution.into()); |
| 1125 | 1122 | }; |
| 1126 | 1123 | 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 | ); | |
| 1132 | 1127 | } |
| 1133 | 1128 | ecx.enter_forall_with_assumptions( |
| 1134 | 1129 | target_projection, |
| ... | ... | @@ -1156,7 +1151,7 @@ where |
| 1156 | 1151 | Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)), |
| 1157 | 1152 | )?; |
| 1158 | 1153 | |
| 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) | |
| 1160 | 1155 | }) |
| 1161 | 1156 | } |
| 1162 | 1157 |
compiler/rustc_parse/src/parser/diagnostics.rs+3-1| ... | ... | @@ -602,7 +602,9 @@ impl<'a> Parser<'a> { |
| 602 | 602 | // Look for usages of '=>' where '>=' was probably intended |
| 603 | 603 | if self.token == token::FatArrow |
| 604 | 604 | && 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)) | |
| 606 | 608 | { |
| 607 | 609 | err.span_suggestion( |
| 608 | 610 | self.token.span, |
compiler/rustc_passes/src/check_attr.rs+1-8| ... | ... | @@ -220,7 +220,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { |
| 220 | 220 | AttributeKind::NonExhaustive(attr_span) => { |
| 221 | 221 | self.check_non_exhaustive(*attr_span, span, target, item) |
| 222 | 222 | } |
| 223 | &AttributeKind::FfiPure(attr_span) => self.check_ffi_pure(attr_span, attrs), | |
| 224 | 223 | AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), |
| 225 | 224 | AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target), |
| 226 | 225 | AttributeKind::MacroExport { span, .. } => { |
| ... | ... | @@ -272,6 +271,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { |
| 272 | 271 | AttributeKind::ExportStable => (), |
| 273 | 272 | AttributeKind::Feature(..) => (), |
| 274 | 273 | AttributeKind::FfiConst => (), |
| 274 | AttributeKind::FfiPure(..) => (), | |
| 275 | 275 | AttributeKind::Fundamental => (), |
| 276 | 276 | AttributeKind::Ignore { .. } => (), |
| 277 | 277 | AttributeKind::InstructionSet(..) => (), |
| ... | ... | @@ -1113,13 +1113,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { |
| 1113 | 1113 | } |
| 1114 | 1114 | } |
| 1115 | 1115 | |
| 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 | ||
| 1123 | 1116 | /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. |
| 1124 | 1117 | fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) { |
| 1125 | 1118 | let hir::Node::GenericParam( |
compiler/rustc_passes/src/diagnostics.rs-7| ... | ... | @@ -152,13 +152,6 @@ pub(crate) struct DocMaskedNotExternCrateSelf { |
| 152 | 152 | pub item_span: Span, |
| 153 | 153 | } |
| 154 | 154 | |
| 155 | #[derive(Diagnostic)] | |
| 156 | #[diag("`#[ffi_const]` function cannot be `#[ffi_pure]`", code = E0757)] | |
| 157 | pub(crate) struct BothFfiConstAndPure { | |
| 158 | #[primary_span] | |
| 159 | pub attr_span: Span, | |
| 160 | } | |
| 161 | ||
| 162 | 155 | #[derive(Diagnostic)] |
| 163 | 156 | #[diag("`#[optimize(none)]` cannot be used with `#[inline]` attributes")] |
| 164 | 157 | pub(crate) struct BothOptimizeNoneAndInline { |
compiler/rustc_public/src/unstable/convert/internal.rs+1| ... | ... | @@ -312,6 +312,7 @@ impl RustcInternal for FnSig { |
| 312 | 312 | tables: &mut Tables<'_, BridgeTys>, |
| 313 | 313 | tcx: impl InternalCx<'tcx>, |
| 314 | 314 | ) -> Self::T<'tcx> { |
| 315 | // FIXME(splat): When `#[splat]` is complete (or stable), add splatted to the public FnSig | |
| 315 | 316 | let fn_sig_kind = rustc_ty::FnSigKind::default() |
| 316 | 317 | .set_abi(self.abi.internal(tables, tcx)) |
| 317 | 318 | .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> { |
| 2091 | 2091 | .time("resolve_postprocess", || self.cstore_mut().postprocess(self.tcx, krate)); |
| 2092 | 2092 | }); |
| 2093 | 2093 | |
| 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(); | |
| 2096 | 2096 | } |
| 2097 | 2097 | |
| 2098 | 2098 | fn traits_in_scope( |
compiler/rustc_session/src/cstore.rs+10| ... | ... | @@ -224,3 +224,13 @@ pub struct Untracked { |
| 224 | 224 | /// The interned [StableCrateId]s. |
| 225 | 225 | pub stable_crate_ids: FreezeLock<StableCrateIdMap>, |
| 226 | 226 | } |
| 227 | ||
| 228 | impl 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! { |
| 1142 | 1142 | irrefutable_let_patterns, |
| 1143 | 1143 | is, |
| 1144 | 1144 | is_auto, |
| 1145 | is_splatted, | |
| 1145 | 1146 | is_val_statically_known, |
| 1146 | 1147 | isa_attribute, |
| 1147 | 1148 | isize, |
| ... | ... | @@ -2001,6 +2002,7 @@ symbols! { |
| 2001 | 2002 | speed, |
| 2002 | 2003 | spirv, |
| 2003 | 2004 | splat, |
| 2005 | splatted_index, | |
| 2004 | 2006 | spotlight, |
| 2005 | 2007 | sqrtf16, |
| 2006 | 2008 | sqrtf32, |
compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs+10| ... | ... | @@ -823,9 +823,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 823 | 823 | // ^^^^^ |
| 824 | 824 | let len1 = sig1.inputs().len(); |
| 825 | 825 | 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); | |
| 826 | 828 | if len1 == len2 { |
| 827 | 829 | for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() { |
| 828 | 830 | 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 | } | |
| 829 | 839 | let (x1, x2) = self.cmp(*l, *r); |
| 830 | 840 | (values.0).0.extend(x1.0); |
| 831 | 841 | (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> { |
| 4962 | 4962 | && let fn_sig @ ty::FnSig { |
| 4963 | 4963 | .. |
| 4964 | 4964 | } = fn_ty.fn_sig(tcx).skip_binder() |
| 4965 | // FIXME(splat): this might need to change if the Fn* traits start using/supporting splat | |
| 4965 | 4966 | && fn_sig.abi() == ExternAbi::Rust |
| 4966 | 4967 | && !fn_sig.c_variadic() |
| 4967 | 4968 | && 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>( |
| 317 | 317 | tcx: TyCtxt<'tcx>, |
| 318 | 318 | item: LocalDefId, |
| 319 | 319 | ) -> &'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 | } | |
| 320 | 323 | let kind = tcx.def_kind(item); |
| 321 | 324 | trace!(?kind); |
| 322 | 325 | let mut collector = OpaqueTypeCollector::new(tcx, item); |
| ... | ... | @@ -332,13 +335,6 @@ fn opaque_types_defined_by<'tcx>( |
| 332 | 335 | | DefKind::AnonConst => { |
| 333 | 336 | collector.collect_taits_declared_in_body(); |
| 334 | 337 | } |
| 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 | } | |
| 342 | 338 | DefKind::AssocTy | DefKind::TyAlias | DefKind::GlobalAsm => {} |
| 343 | 339 | DefKind::OpaqueTy |
| 344 | 340 | | DefKind::Mod |
| ... | ... | @@ -349,6 +345,15 @@ fn opaque_types_defined_by<'tcx>( |
| 349 | 345 | | DefKind::Trait |
| 350 | 346 | | DefKind::ForeignTy |
| 351 | 347 | | 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 | ||
| 352 | 357 | | DefKind::TyParam |
| 353 | 358 | | DefKind::ConstParam |
| 354 | 359 | | DefKind::Ctor(_, _) |
compiler/rustc_ty_utils/src/ty.rs+3| ... | ... | @@ -149,6 +149,9 @@ fn adt_sizedness_constraint<'tcx>( |
| 149 | 149 | |
| 150 | 150 | /// See `ParamEnv` struct definition for details. |
| 151 | 151 | fn 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 | } | |
| 152 | 155 | // Compute the bounds on Self and the type parameters. |
| 153 | 156 | let ty::InstantiatedPredicates { predicates, .. } = |
| 154 | 157 | 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> { |
| 41 | 41 | ArgumentSorts(ExpectedFound<I::Ty>, usize), |
| 42 | 42 | Traits(ExpectedFound<I::TraitId>), |
| 43 | 43 | VariadicMismatch(ExpectedFound<bool>), |
| 44 | SplatMismatch(ExpectedFound<Option<u8>>), | |
| 44 | 45 | |
| 45 | 46 | /// Instantiating a type variable with the given type would have |
| 46 | 47 | /// created a cycle (because it appears somewhere within that |
| ... | ... | @@ -76,7 +77,7 @@ impl<I: Interner> TypeError<I> { |
| 76 | 77 | match self { |
| 77 | 78 | CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch |
| 78 | 79 | | AbiMismatch(_) | ArraySize(_) | ArgumentSorts(..) | Sorts(_) |
| 79 | | VariadicMismatch(_) | TargetFeatureCast(_) => false, | |
| 80 | | VariadicMismatch(_) | SplatMismatch(_) | TargetFeatureCast(_) => false, | |
| 80 | 81 | |
| 81 | 82 | Mutability |
| 82 | 83 | | 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_ |
| 256 | 256 | match rhs.kind() { |
| 257 | 257 | // Start by checking whether the `rhs` type may unify with |
| 258 | 258 | // pretty much everything. Just return `true` in that case. |
| 259 | ty::Param(_) => { | |
| 259 | ty::Param(_) | ty::Alias(ty::IsRigid::Yes, _) => { | |
| 260 | 260 | if INSTANTIATE_RHS_WITH_INFER { |
| 261 | 261 | return true; |
| 262 | 262 | } |
| 263 | 263 | } |
| 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, | |
| 266 | 265 | ty::Infer(var) => return self.var_and_ty_may_unify(var, lhs), |
| 267 | 266 | |
| 268 | 267 | // 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_ |
| 339 | 338 | |
| 340 | 339 | ty::Infer(var) => self.var_and_ty_may_unify(var, rhs), |
| 341 | 340 | |
| 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 | } | |
| 342 | 353 | // As we're walking the whole type, it may encounter projections |
| 343 | 354 | // 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, | |
| 348 | 357 | |
| 349 | 358 | ty::Int(_) |
| 350 | 359 | | ty::Uint(_) |
compiler/rustc_type_ir/src/macros.rs+1| ... | ... | @@ -45,6 +45,7 @@ TrivialTypeTraversalImpls! { |
| 45 | 45 | (), |
| 46 | 46 | bool, |
| 47 | 47 | usize, |
| 48 | u8, | |
| 48 | 49 | u16, |
| 49 | 50 | u32, |
| 50 | 51 | u64, |
compiler/rustc_type_ir/src/relate.rs+4| ... | ... | @@ -169,6 +169,10 @@ impl<I: Interner> Relate<I> for ty::FnSig<I> { |
| 169 | 169 | return Err(TypeError::AbiMismatch(ExpectedFound::new(a.abi(), b.abi()))); |
| 170 | 170 | }; |
| 171 | 171 | |
| 172 | if a.splatted() != b.splatted() { | |
| 173 | return Err(TypeError::SplatMismatch(ExpectedFound::new(a.splatted(), b.splatted()))); | |
| 174 | } | |
| 175 | ||
| 172 | 176 | let a_inputs = a.inputs(); |
| 173 | 177 | let b_inputs = b.inputs(); |
| 174 | 178 | 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> { |
| 888 | 888 | |
| 889 | 889 | impl<I: Interner> Eq for TypeAndMut<I> {} |
| 890 | 890 | |
| 891 | /// Error type for splatted argument index errors. | |
| 892 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | |
| 893 | pub 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 | ||
| 891 | 903 | /// Contains the packed non-type fields of a function signature. |
| 892 | // FIXME(splat): add the splatted argument index as a u16 | |
| 893 | 904 | #[derive_where(Copy, Clone, PartialEq, Eq, Hash; I: Interner)] |
| 894 | 905 | #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] |
| 895 | 906 | #[cfg_attr( |
| ... | ... | @@ -903,6 +914,15 @@ pub struct FnSigKind<I: Interner> { |
| 903 | 914 | #[type_visitable(ignore)] |
| 904 | 915 | #[type_foldable(identity)] |
| 905 | 916 | 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 | ||
| 906 | 926 | #[type_visitable(ignore)] |
| 907 | 927 | #[type_foldable(identity)] |
| 908 | 928 | _marker: PhantomData<fn() -> I>, |
| ... | ... | @@ -922,12 +942,28 @@ impl<I: Interner> fmt::Debug for FnSigKind<I> { |
| 922 | 942 | |
| 923 | 943 | if self.c_variadic() { |
| 924 | 944 | f.field(&"CVariadic"); |
| 925 | }; | |
| 945 | } | |
| 946 | ||
| 947 | if let Some(index) = self.splatted() { | |
| 948 | f.field(&format!("Splatted({})", index)); | |
| 949 | } | |
| 926 | 950 | |
| 927 | 951 | f.finish() |
| 928 | 952 | } |
| 929 | 953 | } |
| 930 | 954 | |
| 955 | impl<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 | ||
| 931 | 967 | impl<I: Interner> FnSigKind<I> { |
| 932 | 968 | /// Mask for the `ExternAbi` variant, including the unwind flag. |
| 933 | 969 | const EXTERN_ABI_MASK: u8 = 0b111111; |
| ... | ... | @@ -938,19 +974,34 @@ impl<I: Interner> FnSigKind<I> { |
| 938 | 974 | /// Bitflag for a trailing C-style variadic argument. |
| 939 | 975 | const C_VARIADIC_FLAG: u8 = 1 << 7; |
| 940 | 976 | |
| 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; | |
| 950 | 985 | |
| 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()) | |
| 954 | 1005 | } |
| 955 | 1006 | |
| 956 | 1007 | /// Set the ABI, including the unwind flag. |
| ... | ... | @@ -989,6 +1040,41 @@ impl<I: Interner> FnSigKind<I> { |
| 989 | 1040 | self |
| 990 | 1041 | } |
| 991 | 1042 | |
| 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 | ||
| 992 | 1078 | /// Get the ABI, including the unwind flag. |
| 993 | 1079 | pub fn abi(self) -> ExternAbi { |
| 994 | 1080 | let abi_index = self.flags & Self::EXTERN_ABI_MASK; |
| ... | ... | @@ -1009,6 +1095,11 @@ impl<I: Interner> FnSigKind<I> { |
| 1009 | 1095 | pub fn c_variadic(self) -> bool { |
| 1010 | 1096 | self.flags & Self::C_VARIADIC_FLAG != 0 |
| 1011 | 1097 | } |
| 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 | } | |
| 1012 | 1103 | } |
| 1013 | 1104 | |
| 1014 | 1105 | #[derive_where(Clone, Copy, PartialEq, Hash; I: Interner)] |
| ... | ... | @@ -1039,8 +1130,21 @@ impl<I: Interner> FnSig<I> { |
| 1039 | 1130 | !self.c_variadic() && self.safety().is_safe() && self.abi() == ExternAbi::Rust |
| 1040 | 1131 | } |
| 1041 | 1132 | |
| 1133 | /// Set the safety flag. | |
| 1134 | #[must_use = "this method does not modify the receiver"] | |
| 1042 | 1135 | 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 }) | |
| 1044 | 1148 | } |
| 1045 | 1149 | |
| 1046 | 1150 | pub fn safety(self) -> I::Safety { |
| ... | ... | @@ -1055,11 +1159,14 @@ impl<I: Interner> FnSig<I> { |
| 1055 | 1159 | self.fn_sig_kind.c_variadic() |
| 1056 | 1160 | } |
| 1057 | 1161 | |
| 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. | |
| 1058 | 1168 | 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() } | |
| 1063 | 1170 | } |
| 1064 | 1171 | } |
| 1065 | 1172 | |
| ... | ... | @@ -1092,6 +1199,10 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> { |
| 1092 | 1199 | self.skip_binder().c_variadic() |
| 1093 | 1200 | } |
| 1094 | 1201 | |
| 1202 | pub fn splatted(self) -> Option<u8> { | |
| 1203 | self.skip_binder().splatted() | |
| 1204 | } | |
| 1205 | ||
| 1095 | 1206 | pub fn safety(self) -> I::Safety { |
| 1096 | 1207 | self.skip_binder().safety() |
| 1097 | 1208 | } |
| ... | ... | @@ -1127,6 +1238,9 @@ impl<I: Interner> fmt::Debug for FnSig<I> { |
| 1127 | 1238 | if i > 0 { |
| 1128 | 1239 | write!(f, ", ")?; |
| 1129 | 1240 | } |
| 1241 | if Some(i) == fn_sig_kind.splatted().map(usize::from) { | |
| 1242 | write!(f, "#[splat] ")?; | |
| 1243 | } | |
| 1130 | 1244 | write!(f, "{ty:?}")?; |
| 1131 | 1245 | } |
| 1132 | 1246 | if fn_sig_kind.c_variadic() { |
| ... | ... | @@ -1288,8 +1402,9 @@ impl<I: Interner> FnHeader<I> { |
| 1288 | 1402 | self.fn_sig_kind.abi() |
| 1289 | 1403 | } |
| 1290 | 1404 | |
| 1405 | /// Create a new safe FnHeader with the `extern "Rust"` ABI, that isn't C-style variadic or splatted. | |
| 1291 | 1406 | pub fn dummy() -> Self { |
| 1292 | Self { fn_sig_kind: FnSigKind::new(ExternAbi::Rust, I::Safety::safe(), false) } | |
| 1407 | Self { fn_sig_kind: FnSigKind::dummy() } | |
| 1293 | 1408 | } |
| 1294 | 1409 | } |
| 1295 | 1410 |
compiler/rustc_type_ir/src/ty_kind/closure.rs+1-1| ... | ... | @@ -364,7 +364,7 @@ pub struct CoroutineClosureSignature<I: Interner> { |
| 364 | 364 | // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types |
| 365 | 365 | // never actually differ. But we save them rather than recreating them |
| 366 | 366 | // from scratch just for good measure. |
| 367 | /// Always safe, RustCall, non-c-variadic | |
| 367 | /// Always safe, RustCall, non-c-variadic, non-splatted | |
| 368 | 368 | #[type_visitable(ignore)] |
| 369 | 369 | #[type_foldable(identity)] |
| 370 | 370 | 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> { |
| 1760 | 1760 | #[must_use] |
| 1761 | 1761 | pub fn into_array<const N: usize>(self) -> Result<Box<[T; N], A>, Self> { |
| 1762 | 1762 | 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() }) | |
| 1764 | 1768 | } else { |
| 1765 | 1769 | Err(self) |
| 1766 | 1770 | } |
library/core/src/fmt/num.rs+1-1| ... | ... | @@ -361,7 +361,7 @@ macro_rules! impl_Display { |
| 361 | 361 | |
| 362 | 362 | #[cfg(feature = "optimize_for_size")] |
| 363 | 363 | 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; | |
| 365 | 365 | let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N]; |
| 366 | 366 | |
| 367 | 367 | 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 { |
| 17 | 17 | #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] |
| 18 | 18 | impl NumBufferTrait for $signed { |
| 19 | 19 | // `+ 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]; | |
| 22 | 22 | } |
| 23 | 23 | #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] |
| 24 | 24 | 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]; | |
| 27 | 27 | } |
| 28 | 28 | )* |
| 29 | 29 | } |
| ... | ... | @@ -74,7 +74,6 @@ impl<T: NumBufferTrait> NumBuffer<T> { |
| 74 | 74 | #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] |
| 75 | 75 | #[rustc_const_stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] |
| 76 | 76 | pub const fn new() -> Self { |
| 77 | // FIXME: Once const generics feature is working, use `T::BUF_SIZE` instead of 40. | |
| 78 | 77 | NumBuffer { buf: T::DEFAULT, phantom: core::marker::PhantomData } |
| 79 | 78 | } |
| 80 | 79 | } |
library/core/src/mem/type_info.rs+17-1| ... | ... | @@ -215,7 +215,7 @@ pub struct Variant { |
| 215 | 215 | pub name: &'static str, |
| 216 | 216 | /// All fields of the variant. |
| 217 | 217 | pub fields: &'static [Field], |
| 218 | /// Whether the enum variant fields is non-exhaustive. | |
| 218 | /// Whether the enum variant fields are non-exhaustive. | |
| 219 | 219 | pub non_exhaustive: bool, |
| 220 | 220 | } |
| 221 | 221 | |
| ... | ... | @@ -342,6 +342,22 @@ pub struct FnPtr { |
| 342 | 342 | |
| 343 | 343 | /// Vardiadic function, e.g. extern "C" fn add(n: usize, mut args: ...); |
| 344 | 344 | 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 | ||
| 356 | impl 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 | } | |
| 345 | 361 | } |
| 346 | 362 | |
| 347 | 363 | #[derive(Debug, Default)] |
library/core/src/slice/index.rs+4| ... | ... | @@ -139,6 +139,8 @@ pub impl(crate) const unsafe trait SliceIndex<T: ?Sized> { |
| 139 | 139 | /// Returns a pointer to the output at this location, without |
| 140 | 140 | /// performing any bounds checking. |
| 141 | 141 | /// |
| 142 | /// # Safety | |
| 143 | /// | |
| 142 | 144 | /// Calling this method with an out-of-bounds index or a dangling `slice` pointer |
| 143 | 145 | /// is *[undefined behavior]* even if the resulting pointer is not used. |
| 144 | 146 | /// |
| ... | ... | @@ -149,6 +151,8 @@ pub impl(crate) const unsafe trait SliceIndex<T: ?Sized> { |
| 149 | 151 | /// Returns a mutable pointer to the output at this location, without |
| 150 | 152 | /// performing any bounds checking. |
| 151 | 153 | /// |
| 154 | /// # Safety | |
| 155 | /// | |
| 152 | 156 | /// Calling this method with an out-of-bounds index or a dangling `slice` pointer |
| 153 | 157 | /// is *[undefined behavior]* even if the resulting pointer is not used. |
| 154 | 158 | /// |
library/coretests/tests/mem/fn_ptr.rs+66| ... | ... | @@ -5,6 +5,7 @@ const STRING_TY: TypeId = const { TypeId::of::<String>() }; |
| 5 | 5 | const U8_TY: TypeId = const { TypeId::of::<u8>() }; |
| 6 | 6 | const _U8_REF_TY: TypeId = const { TypeId::of::<&u8>() }; |
| 7 | 7 | const UNIT_TY: TypeId = const { TypeId::of::<()>() }; |
| 8 | const TUPLE_STRING_U8_TY: TypeId = const { TypeId::of::<(String, u8)>() }; | |
| 8 | 9 | |
| 9 | 10 | #[test] |
| 10 | 11 | fn test_fn_ptrs() { |
| ... | ... | @@ -14,6 +15,8 @@ fn test_fn_ptrs() { |
| 14 | 15 | inputs: &[], |
| 15 | 16 | output, |
| 16 | 17 | variadic: false, |
| 18 | is_splatted: false, | |
| 19 | splatted_index: _, | |
| 17 | 20 | }) = (const { Type::of::<fn()>().kind }) |
| 18 | 21 | else { |
| 19 | 22 | panic!(); |
| ... | ... | @@ -31,6 +34,8 @@ fn test_ref() { |
| 31 | 34 | inputs: &[ty1, ty2], |
| 32 | 35 | output, |
| 33 | 36 | variadic: false, |
| 37 | is_splatted: false, | |
| 38 | splatted_index: _, | |
| 34 | 39 | }) = (const { Type::of::<fn(&u8, &u8)>().kind }) |
| 35 | 40 | else { |
| 36 | 41 | panic!(); |
| ... | ... | @@ -61,6 +66,8 @@ fn test_unsafe() { |
| 61 | 66 | inputs: &[], |
| 62 | 67 | output, |
| 63 | 68 | variadic: false, |
| 69 | is_splatted: false, | |
| 70 | splatted_index: _, | |
| 64 | 71 | }) = (const { Type::of::<unsafe fn()>().kind }) |
| 65 | 72 | else { |
| 66 | 73 | panic!(); |
| ... | ... | @@ -75,6 +82,8 @@ fn test_abi() { |
| 75 | 82 | inputs: &[], |
| 76 | 83 | output, |
| 77 | 84 | variadic: false, |
| 85 | is_splatted: false, | |
| 86 | splatted_index: _, | |
| 78 | 87 | }) = (const { Type::of::<extern "Rust" fn()>().kind }) |
| 79 | 88 | else { |
| 80 | 89 | panic!(); |
| ... | ... | @@ -87,6 +96,8 @@ fn test_abi() { |
| 87 | 96 | inputs: &[], |
| 88 | 97 | output, |
| 89 | 98 | variadic: false, |
| 99 | is_splatted: false, | |
| 100 | splatted_index: _, | |
| 90 | 101 | }) = (const { Type::of::<extern "C" fn()>().kind }) |
| 91 | 102 | else { |
| 92 | 103 | panic!(); |
| ... | ... | @@ -99,6 +110,8 @@ fn test_abi() { |
| 99 | 110 | inputs: &[], |
| 100 | 111 | output, |
| 101 | 112 | variadic: false, |
| 113 | is_splatted: false, | |
| 114 | splatted_index: _, | |
| 102 | 115 | }) = (const { Type::of::<unsafe extern "system" fn()>().kind }) |
| 103 | 116 | else { |
| 104 | 117 | panic!(); |
| ... | ... | @@ -114,6 +127,8 @@ fn test_inputs() { |
| 114 | 127 | inputs: &[ty1, ty2], |
| 115 | 128 | output, |
| 116 | 129 | variadic: false, |
| 130 | is_splatted: false, | |
| 131 | splatted_index: _, | |
| 117 | 132 | }) = (const { Type::of::<fn(String, u8)>().kind }) |
| 118 | 133 | else { |
| 119 | 134 | panic!(); |
| ... | ... | @@ -128,6 +143,8 @@ fn test_inputs() { |
| 128 | 143 | inputs: &[ty1, ty2], |
| 129 | 144 | output, |
| 130 | 145 | variadic: false, |
| 146 | is_splatted: false, | |
| 147 | splatted_index: _, | |
| 131 | 148 | }) = (const { Type::of::<fn(val: String, p2: u8)>().kind }) |
| 132 | 149 | else { |
| 133 | 150 | panic!(); |
| ... | ... | @@ -145,6 +162,8 @@ fn test_output() { |
| 145 | 162 | inputs: &[], |
| 146 | 163 | output, |
| 147 | 164 | variadic: false, |
| 165 | is_splatted: false, | |
| 166 | splatted_index: _, | |
| 148 | 167 | }) = (const { Type::of::<fn() -> u8>().kind }) |
| 149 | 168 | else { |
| 150 | 169 | panic!(); |
| ... | ... | @@ -160,6 +179,8 @@ fn test_variadic() { |
| 160 | 179 | inputs: [ty1], |
| 161 | 180 | output, |
| 162 | 181 | variadic: true, |
| 182 | is_splatted: false, | |
| 183 | splatted_index: _, | |
| 163 | 184 | }) = &(const { Type::of::<extern "C" fn(u8, ...)>().kind }) |
| 164 | 185 | else { |
| 165 | 186 | panic!(); |
| ... | ... | @@ -167,3 +188,48 @@ fn test_variadic() { |
| 167 | 188 | assert_eq!(output, &UNIT_TY); |
| 168 | 189 | assert_eq!(*ty1, U8_TY); |
| 169 | 190 | } |
| 191 | ||
| 192 | #[test] | |
| 193 | fn 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] | |
| 216 | fn 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 @@ |
| 85 | 85 | /// [`unused_must_use`]: ../rustc/lints/listing/warn-by-default.html#unused-must-use |
| 86 | 86 | /// [the `must_use` attribute]: ../reference/attributes/diagnostics.html#the-must_use-attribute |
| 87 | 87 | mod 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 | |
| 146 | mod 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 | |
| 192 | mod 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 | |
| 236 | mod 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 | |
| 270 | mod 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 | |
| 295 | mod 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 | |
| 337 | mod warn_attribute {} |
library/std/src/sys/thread/unix.rs+6| ... | ... | @@ -392,6 +392,7 @@ pub fn current_os_id() -> Option<u64> { |
| 392 | 392 | target_os = "vxworks", |
| 393 | 393 | target_os = "cygwin", |
| 394 | 394 | target_vendor = "apple", |
| 395 | target_os = "netbsd", | |
| 395 | 396 | ))] |
| 396 | 397 | fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { |
| 397 | 398 | let mut result = [0; MAX_WITH_NUL]; |
| ... | ... | @@ -463,7 +464,12 @@ pub fn set_name(name: &CStr) { |
| 463 | 464 | |
| 464 | 465 | #[cfg(target_os = "netbsd")] |
| 465 | 466 | pub 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 | ||
| 466 | 471 | unsafe { |
| 472 | let name = truncate_cstr::<{ PTHREAD_MAX_NAMELEN_NP }>(name); | |
| 467 | 473 | let res = libc::pthread_setname_np( |
| 468 | 474 | libc::pthread_self(), |
| 469 | 475 | c"%s".as_ptr(), |
src/tools/enzyme+1-1| ... | ... | @@ -1 +1 @@ |
| 1 | Subproject commit 7c0141f133a3592daa12cc6cc07f297a5222a42e | |
| 1 | Subproject commit a8668c7ca3579c3304d628bca518bafc0fcc62d1 |
src/tools/miri/src/helpers.rs+2| ... | ... | @@ -406,6 +406,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 406 | 406 | let sig = this.tcx.mk_fn_sig( |
| 407 | 407 | args.iter().map(|a| a.layout.ty), |
| 408 | 408 | dest.layout.ty, |
| 409 | // FIXME(splat): Do we need to set splatted here? | |
| 410 | // (Currently this also ignores c_variadic) | |
| 409 | 411 | FnSigKind::default().set_abi(caller_abi).set_safety(rustc_hir::Safety::Safe), |
| 410 | 412 | ); |
| 411 | 413 | 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> { |
| 274 | 274 | inputs_and_output.push(shim_sig.ret); |
| 275 | 275 | let fn_sig_binder = Binder::dummy(FnSig { |
| 276 | 276 | 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. | |
| 278 | 278 | fn_sig_kind: FnSigKind::default() |
| 279 | 279 | .set_abi(shim_sig.abi) |
| 280 | 280 | .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> { |
| 173 | 173 | // impl forces the closure kind to `FnOnce` i.e. `u8`. |
| 174 | 174 | let kind_ty = autoderef.ctx().table.next_ty_var(call_expr.into()); |
| 175 | 175 | let interner = autoderef.ctx().interner(); |
| 176 | ||
| 177 | // Ignore splatting, it is unsupported on closures. | |
| 176 | 178 | let call_sig = interner.mk_fn_sig( |
| 177 | 179 | [coroutine_closure_sig.tupled_inputs_ty], |
| 178 | 180 | 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>( |
| 464 | 464 | args.tuple_fields(), |
| 465 | 465 | ret, |
| 466 | 466 | false, |
| 467 | // FIXME(splat): handle splatted arguments | |
| 467 | 468 | Safety::Safe, |
| 468 | 469 | ExternAbi::Rust, |
| 469 | 470 | )); |
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs+1| ... | ... | @@ -637,6 +637,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { |
| 637 | 637 | fn_.abi, |
| 638 | 638 | if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, |
| 639 | 639 | fn_.is_varargs, |
| 640 | // FIXME(splat): handle splatted arguments | |
| 640 | 641 | ), |
| 641 | 642 | inputs_and_output: Tys::new_from_slice(&args), |
| 642 | 643 | }), |
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs+1| ... | ... | @@ -2238,6 +2238,7 @@ impl<'db> DbInterner<'db> { |
| 2238 | 2238 | self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate) |
| 2239 | 2239 | } |
| 2240 | 2240 | |
| 2241 | // FIXME: add splat support when the experiment is complete | |
| 2241 | 2242 | pub fn mk_fn_sig<I>( |
| 2242 | 2243 | self, |
| 2243 | 2244 | inputs: I, |
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs+1| ... | ... | @@ -1514,6 +1514,7 @@ impl<'db> DbInterner<'db> { |
| 1514 | 1514 | TyKind::Tuple(params) => params, |
| 1515 | 1515 | _ => panic!(), |
| 1516 | 1516 | }; |
| 1517 | // Ignore splatting, it is unsupported on closures. | |
| 1517 | 1518 | self.mk_fn_sig(params, s.output(), s.c_variadic(), safety, ExternAbi::Rust) |
| 1518 | 1519 | }) |
| 1519 | 1520 | } |
tests/codegen-llvm/i128-x86-align.rs+2-4| ... | ... | @@ -5,8 +5,6 @@ |
| 5 | 5 | // while rustc wants it to have 16 byte alignment. This test checks that we handle this |
| 6 | 6 | // correctly. |
| 7 | 7 | |
| 8 | // CHECK: %ScalarPair = type { i32, [3 x i32], i128 } | |
| 9 | ||
| 10 | 8 | #![feature(core_intrinsics)] |
| 11 | 9 | |
| 12 | 10 | #[repr(C)] |
| ... | ... | @@ -62,8 +60,8 @@ pub fn load_volatile(x: &ScalarPair) -> ScalarPair { |
| 62 | 60 | // CHECK-SAME: dereferenceable(32) %_0, |
| 63 | 61 | // CHECK-SAME: align 16 |
| 64 | 62 | // 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 | |
| 67 | 65 | // CHECK-NEXT: ret void |
| 68 | 66 | unsafe { std::intrinsics::volatile_load(x) } |
| 69 | 67 | } |
tests/codegen-llvm/intrinsics/volatile.rs+117-4| ... | ... | @@ -5,6 +5,11 @@ |
| 5 | 5 | |
| 6 | 6 | use std::intrinsics; |
| 7 | 7 | |
| 8 | #[repr(align(32))] | |
| 9 | pub struct CustomZst; | |
| 10 | ||
| 11 | type UninitFatPointer = std::mem::MaybeUninit<&'static dyn std::fmt::Debug>; | |
| 12 | ||
| 8 | 13 | // CHECK-LABEL: @volatile_copy_memory |
| 9 | 14 | #[no_mangle] |
| 10 | 15 | pub 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) { |
| 28 | 33 | |
| 29 | 34 | // CHECK-LABEL: @volatile_load |
| 30 | 35 | #[no_mangle] |
| 31 | pub unsafe fn volatile_load(a: *const u8) -> u8 { | |
| 32 | // CHECK: load volatile | |
| 36 | pub 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] | |
| 45 | pub 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] | |
| 55 | pub 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] | |
| 64 | pub 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] | |
| 76 | pub 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]] | |
| 33 | 92 | intrinsics::volatile_load(a) |
| 34 | 93 | } |
| 35 | 94 | |
| ... | ... | @@ -42,8 +101,62 @@ pub unsafe fn volatile_store(a: *mut u8, b: u8) { |
| 42 | 101 | |
| 43 | 102 | // CHECK-LABEL: @unaligned_volatile_load |
| 44 | 103 | #[no_mangle] |
| 45 | pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 { | |
| 46 | // CHECK: load volatile | |
| 104 | pub 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] | |
| 113 | pub 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] | |
| 123 | pub 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] | |
| 132 | pub 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] | |
| 144 | pub 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]] | |
| 47 | 160 | intrinsics::unaligned_volatile_load(a) |
| 48 | 161 | } |
| 49 | 162 |
tests/ui/asm/parse-error.stderr+6| ... | ... | @@ -57,6 +57,12 @@ error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` |
| 57 | 57 | | |
| 58 | 58 | LL | asm!("{}", in(reg) foo => bar); |
| 59 | 59 | | ^^ expected one of 7 possible tokens |
| 60 | | | |
| 61 | help: you might have meant to write a "greater than or equal to" comparison | |
| 62 | | | |
| 63 | LL - asm!("{}", in(reg) foo => bar); | |
| 64 | LL + asm!("{}", in(reg) foo >= bar); | |
| 65 | | | |
| 60 | 66 | |
| 61 | 67 | error: expected a path for argument to `sym` |
| 62 | 68 | --> $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) |
| 8 | 8 | //~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` |
| 9 | 9 | //~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` |
| 10 | 10 | where |
| 11 | F:, | |
| 12 | for<'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, | |
| 13 | 13 | { |
| 14 | //~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` | |
| 15 | 14 | let mut i = 41; |
| 16 | 15 | &mut i; |
| 17 | 16 | } |
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` |
| 3 | 3 | | |
| 4 | 4 | LL | / async fn wrapper<F>(f: F) |
| 5 | 5 | ... | |
| 6 | LL | | F:, | |
| 7 | LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, | |
| 8 | | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | |
| 6 | LL | | F:, | |
| 7 | LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, | |
| 8 | | |______________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | |
| 9 | 9 | | |
| 10 | 10 | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` |
| 11 | 11 | |
| ... | ... | @@ -26,18 +26,6 @@ LL | async fn wrapper<F>(f: F) |
| 26 | 26 | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` |
| 27 | 27 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 28 | 28 | |
| 29 | error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` | |
| 30 | --> $DIR/issue-76168-hr-outlives-3.rs:13:1 | |
| 31 | | | |
| 32 | LL | / { | |
| 33 | LL | | | |
| 34 | LL | | let mut i = 41; | |
| 35 | LL | | &mut i; | |
| 36 | LL | | } | |
| 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 | ||
| 41 | error: aborting due to 4 previous errors | |
| 29 | error: aborting due to 3 previous errors | |
| 42 | 30 | |
| 43 | 31 | For 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 | ||
| 3 | struct C; | |
| 4 | ||
| 5 | struct S<T>(T); | |
| 6 | ||
| 7 | trait Tr {} | |
| 8 | ||
| 9 | impl<T> Clone for S<C> | |
| 10 | //~^ ERROR the type parameter `T` is not constrained | |
| 11 | where | |
| 12 | S<T>: Tr, | |
| 13 | { | |
| 14 | fn clone(&self) -> Self { | |
| 15 | *self | |
| 16 | //~^ ERROR cannot move out of `*self` | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | fn main() {} |
tests/ui/moves/unconstrained-impl-param-clone-suggestion.stderr created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | error[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 | | | |
| 4 | LL | impl<T> Clone for S<C> | |
| 5 | | -^- | |
| 6 | | || | |
| 7 | | |unconstrained type parameter | |
| 8 | | help: remove the unused type parameter `T` | |
| 9 | ||
| 10 | error[E0507]: cannot move out of `*self` which is behind a shared reference | |
| 11 | --> $DIR/unconstrained-impl-param-clone-suggestion.rs:15:9 | |
| 12 | | | |
| 13 | LL | *self | |
| 14 | | ^^^^^ move occurs because `*self` has type `S<C>`, which does not implement the `Copy` trait | |
| 15 | ||
| 16 | error: aborting due to 2 previous errors | |
| 17 | ||
| 18 | Some errors have detailed explanations: E0207, E0507. | |
| 19 | For 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() { |
| 43 | 43 | _ => todo!(), |
| 44 | 44 | } |
| 45 | 45 | } |
| 46 | ||
| 47 | fn 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() { |
| 43 | 43 | _ => todo!(), |
| 44 | 44 | } |
| 45 | 45 | } |
| 46 | ||
| 47 | fn 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 { |
| 109 | 109 | LL + match a >= b { |
| 110 | 110 | | |
| 111 | 111 | |
| 112 | error: aborting due to 7 previous errors | |
| 112 | error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` | |
| 113 | --> $DIR/eq-gt-to-gt-eq.rs:50:34 | |
| 114 | | | |
| 115 | LL | let _ = [a].iter().any(|x| x => &b); | |
| 116 | | ^^ expected one of 8 possible tokens | |
| 117 | | | |
| 118 | help: you might have meant to write a "greater than or equal to" comparison | |
| 119 | | | |
| 120 | LL - let _ = [a].iter().any(|x| x => &b); | |
| 121 | LL + let _ = [a].iter().any(|x| x >= &b); | |
| 122 | | | |
| 123 | ||
| 124 | error: aborting due to 8 previous errors | |
| 113 | 125 |
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 | ||
| 9 | type 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] | |
| 14 | type 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] | |
| 34 | fn 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] | |
| 54 | fn 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] | |
| 75 | fn 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] | |
| 96 | fn 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. | |
| 118 | fn more_than_255_splatted_args(#[splat] _t: Tuple256) {} | |
| 119 | ||
| 120 | fn 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 @@ |
| 1 | error: `#[splat]` is not supported on argument index 255 | |
| 2 | --> $DIR/splat-255-limit-fail.rs:50:5 | |
| 3 | | | |
| 4 | LL | #[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 | ||
| 9 | error: `#[splat]` is not supported on argument index 256 | |
| 10 | --> $DIR/splat-255-limit-fail.rs:71:5 | |
| 11 | | | |
| 12 | LL | #[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 | ||
| 17 | error: `#[splat]` is not supported on argument index 255 | |
| 18 | --> $DIR/splat-255-limit-fail.rs:91:5 | |
| 19 | | | |
| 20 | LL | #[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 | ||
| 25 | error: `#[splat]` is not supported on argument index 256 | |
| 26 | --> $DIR/splat-255-limit-fail.rs:113:5 | |
| 27 | | | |
| 28 | LL | #[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 | ||
| 33 | error[E0057]: this splatted function takes 256 arguments, but 255 were provided | |
| 34 | --> $DIR/splat-255-limit-fail.rs:124:5 | |
| 35 | | | |
| 36 | LL | / more_than_255_splatted_args( | |
| 37 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 38 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 39 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 40 | ... | | |
| 41 | LL | | /* missing: a, */ | |
| 42 | LL | | ); | |
| 43 | | |_____^ | |
| 44 | ||
| 45 | error[E0057]: this splatted function takes 256 arguments, but 257 were provided | |
| 46 | --> $DIR/splat-255-limit-fail.rs:144:5 | |
| 47 | | | |
| 48 | LL | / more_than_255_splatted_args( | |
| 49 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 50 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 51 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 52 | ... | | |
| 53 | LL | | a, /* unexpected: */ a, | |
| 54 | LL | | ); | |
| 55 | | |_____^ | |
| 56 | ||
| 57 | error[E0057]: this splatted function takes 256 arguments, but 512 were provided | |
| 58 | --> $DIR/splat-255-limit-fail.rs:164:5 | |
| 59 | | | |
| 60 | LL | / more_than_255_splatted_args( | |
| 61 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 62 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 63 | LL | | a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, | |
| 64 | ... | | |
| 65 | LL | | a, | |
| 66 | LL | | ); | |
| 67 | | |_____^ | |
| 68 | ||
| 69 | error: aborting due to 7 previous errors | |
| 70 | ||
| 71 | For 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 | ||
| 10 | type 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] | |
| 15 | type 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] | |
| 35 | fn 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] | |
| 55 | fn 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] | |
| 75 | fn 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] | |
| 96 | fn 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] | |
| 116 | fn 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] | |
| 136 | fn 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] | |
| 157 | fn 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 | ||
| 177 | fn more_than_255_splatted_args(#[splat] _t: Tuple256) {} | |
| 178 | ||
| 179 | fn 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 | ||
| 7 | struct Foo; | |
| 8 | ||
| 9 | impl Foo { | |
| 10 | fn tuple_1(#[splat] (_a,): (u32,)) {} | |
| 11 | ||
| 12 | fn tuple_3(#[splat] (_a, _b, _c): (u32, i32, i8)) {} | |
| 13 | } | |
| 14 | ||
| 15 | fn 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 | ||
| 7 | async 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 | ||
| 10 | async 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 | ||
| 13 | fn 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 @@ |
| 1 | error: multiple `#[splat]`s are not allowed in the same function | |
| 2 | --> $DIR/splat-async-fn-tuple-fail.rs:10:28 | |
| 3 | | | |
| 4 | LL | 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 | ||
| 9 | error[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 | | | |
| 12 | LL | async fn async_wrong_type(#[splat] _x: u32) {} | |
| 13 | | ^^^ | |
| 14 | ... | |
| 15 | LL | async_wrong_type(1u32); | |
| 16 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 17 | ||
| 18 | error[E0057]: this splatted function takes 3 arguments, but 4 were provided | |
| 19 | --> $DIR/splat-async-fn-tuple-fail.rs:15:5 | |
| 20 | | | |
| 21 | LL | async_multi_splat(1u32, 2i8, 3u32, 4i8); | |
| 22 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 23 | ||
| 24 | error: aborting due to 3 previous errors | |
| 25 | ||
| 26 | Some errors have detailed explanations: E0057, E0277. | |
| 27 | For 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 | ||
| 8 | async fn async_tuple_args(#[splat] (_a, _b): (u32, i8)) {} | |
| 9 | ||
| 10 | async fn async_splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {} | |
| 11 | ||
| 12 | fn 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 | ||
| 8 | fn tuple(#[splat] t: impl Sized) -> impl Sized { | |
| 9 | //~^ ERROR cannot resolve opaque type | |
| 10 | tuple(tuple((t, ()))) | |
| 11 | } | |
| 12 | ||
| 13 | fn 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 | ||
| 18 | trait Trait { | |
| 19 | type MaybeTup; | |
| 20 | type Tup: std::marker::Tuple; | |
| 21 | } | |
| 22 | ||
| 23 | fn 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 | |
| 28 | fn 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 | ||
| 34 | fn 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 @@ |
| 1 | error[E0223]: ambiguous associated type | |
| 2 | --> $DIR/splat-cannot-resolve.rs:23:22 | |
| 3 | | | |
| 4 | LL | fn ambig(#[splat] t: Trait::MaybeTup) {} | |
| 5 | | ^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path | |
| 8 | | | |
| 9 | LL - fn ambig(#[splat] t: Trait::MaybeTup) {} | |
| 10 | LL + fn ambig(#[splat] t: <Example as Trait>::MaybeTup) {} | |
| 11 | | | |
| 12 | ||
| 13 | error[E0223]: ambiguous associated type | |
| 14 | --> $DIR/splat-cannot-resolve.rs:28:26 | |
| 15 | | | |
| 16 | LL | fn ambig_tup(#[splat] t: Trait::Tup) {} | |
| 17 | | ^^^^^^^^^^ | |
| 18 | | | |
| 19 | help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path | |
| 20 | | | |
| 21 | LL - fn ambig_tup(#[splat] t: Trait::Tup) {} | |
| 22 | LL + fn ambig_tup(#[splat] t: <Example as Trait>::Tup) {} | |
| 23 | | | |
| 24 | ||
| 25 | error[E0720]: cannot resolve opaque type | |
| 26 | --> $DIR/splat-cannot-resolve.rs:8:37 | |
| 27 | | | |
| 28 | LL | fn tuple(#[splat] t: impl Sized) -> impl Sized { | |
| 29 | | ^^^^^^^^^^ | |
| 30 | ||
| 31 | error[E0720]: cannot resolve opaque type | |
| 32 | --> $DIR/splat-cannot-resolve.rs:13:56 | |
| 33 | | | |
| 34 | LL | fn tuple_trait(#[splat] t: impl std::marker::Tuple) -> impl std::marker::Tuple { | |
| 35 | | ^^^^^^^^^^^^^^^^^^^^^^^ | |
| 36 | ||
| 37 | error[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 | | | |
| 40 | LL | fn ambig(#[splat] t: Trait::MaybeTup) {} | |
| 41 | | ^^^^^^^^^^^^^^^ | |
| 42 | ... | |
| 43 | LL | ambig(); | |
| 44 | | ^^^^^^^ | |
| 45 | ||
| 46 | error[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 | | | |
| 49 | LL | fn ambig_tup(#[splat] t: Trait::Tup) {} | |
| 50 | | ^^^^^^^^^^ | |
| 51 | ... | |
| 52 | LL | ambig_tup(); | |
| 53 | | ^^^^^^^^^^^ | |
| 54 | ||
| 55 | error[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 | | | |
| 58 | LL | fn ambig(#[splat] t: Trait::MaybeTup) {} | |
| 59 | | ^^^^^^^^^^^^^^^ | |
| 60 | ... | |
| 61 | LL | ambig(1); | |
| 62 | | ^^^^^^^^ | |
| 63 | ||
| 64 | error[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 | | | |
| 67 | LL | fn ambig_tup(#[splat] t: Trait::Tup) {} | |
| 68 | | ^^^^^^^^^^ | |
| 69 | ... | |
| 70 | LL | ambig_tup(1); | |
| 71 | | ^^^^^^^^^^^^ | |
| 72 | ||
| 73 | error[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 | | | |
| 76 | LL | fn ambig(#[splat] t: Trait::MaybeTup) {} | |
| 77 | | ^^^^^^^^^^^^^^^ | |
| 78 | ... | |
| 79 | LL | ambig(1, 2.0); | |
| 80 | | ^^^^^^^^^^^^^ | |
| 81 | ||
| 82 | error[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 | | | |
| 85 | LL | fn ambig_tup(#[splat] t: Trait::Tup) {} | |
| 86 | | ^^^^^^^^^^ | |
| 87 | ... | |
| 88 | LL | ambig_tup(1, 2.0); | |
| 89 | | ^^^^^^^^^^^^^^^^^ | |
| 90 | ||
| 91 | error: aborting due to 10 previous errors | |
| 92 | ||
| 93 | Some errors have detailed explanations: E0223, E0277, E0720. | |
| 94 | For 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 | |
| 8 | const fn const_generic_first<T: Copy>(#[splat] _: (T, u32)) {} | |
| 9 | ||
| 10 | // Generic type in second position | |
| 11 | const fn const_generic_second<T: Copy>(#[splat] _: (u32, T)) {} | |
| 12 | ||
| 13 | // Multiple generic types | |
| 14 | const fn const_generic_both<T: Copy, U: Copy>(#[splat] _: (T, U)) {} | |
| 15 | ||
| 16 | // Generic with extra non-splatted arg | |
| 17 | const fn const_generic_extra<T: Copy>(#[splat] _: (T, u32), _extra: i32) {} | |
| 18 | ||
| 19 | fn 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 | ||
| 7 | const fn sum(#[splat] (a, b): (u32, u32)) -> u32 { | |
| 8 | a + b | |
| 9 | } | |
| 10 | ||
| 11 | const RESULT: u32 = sum(1, 2); | |
| 12 | ||
| 13 | fn 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 | ||
| 7 | fn dyn_asref_splat<T>(#[splat] _t: &dyn AsRef<T>) where T: std::marker::Tuple {} | |
| 8 | //~^ ERROR cannot use splat attribute | |
| 9 | ||
| 10 | fn 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 @@ |
| 1 | error[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 | | | |
| 4 | LL | fn dyn_asref_splat<T>(#[splat] _t: &dyn AsRef<T>) where T: std::marker::Tuple {} | |
| 5 | | ^^^^^^^^^^^^^ | |
| 6 | ... | |
| 7 | LL | dyn_asref_splat::<String>(&s); | |
| 8 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 9 | ||
| 10 | error[E0277]: `String` is not a tuple | |
| 11 | --> $DIR/splat-dyn-asref-tuple-fail.rs:12:23 | |
| 12 | | | |
| 13 | LL | dyn_asref_splat::<String>(&s); | |
| 14 | | ^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `String` | |
| 15 | | | |
| 16 | note: required by a bound in `dyn_asref_splat` | |
| 17 | --> $DIR/splat-dyn-asref-tuple-fail.rs:7:60 | |
| 18 | | | |
| 19 | LL | 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 | ||
| 22 | error: aborting due to 2 previous errors | |
| 23 | ||
| 24 | For 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 | ||
| 19 | fn tuple_args(#[splat] (_a, _b): (u32, i8)) {} | |
| 20 | ||
| 21 | fn splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {} | |
| 22 | ||
| 23 | fn 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 @@ |
| 1 | error: compiler/rustc_mir_build/src/thir/cx/expr.rs:LL:CC: no splatted def for function or method callee | |
| 2 | | | |
| 3 | LL | fn_ptr(1, 2); | |
| 4 | | ^^^^^^^^^^^^ | |
| 5 | ||
| 6 | ||
| 7 | ||
| 8 | Box<dyn Any> | |
| 9 | stack backtrace: | |
| 10 | ||
| 11 | note: 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 | ||
| 13 | note: please make sure that you have updated to the latest nightly | |
| 14 | ||
| 15 | note: rustc {version} running on {platform} | |
| 16 | ||
| 17 | query 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` | |
| 21 | end of query stack | |
| 22 | error: 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 | ||
| 7 | fn splat_generic_tuple<T: std::marker::Tuple>(#[splat] _t: T) {} | |
| 8 | ||
| 9 | fn 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 @@ |
| 1 | error[E0057]: this splatted function takes 2 arguments, but 1 was provided | |
| 2 | --> $DIR/splat-fn-tuple-generic-fail.rs:19:5 | |
| 3 | | | |
| 4 | LL | splat_generic_tuple::<(((u32, i8)))>((1, 2)); | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | ||
| 7 | error[E0057]: this splatted function takes 2 arguments, but 1 was provided | |
| 8 | --> $DIR/splat-fn-tuple-generic-fail.rs:20:5 | |
| 9 | | | |
| 10 | LL | splat_generic_tuple::<(((u32, i8)))>((1u32, 2i8)); | |
| 11 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 12 | ||
| 13 | error[E0057]: this splatted function takes 2 arguments, but 1 was provided | |
| 14 | --> $DIR/splat-fn-tuple-generic-fail.rs:22:5 | |
| 15 | | | |
| 16 | LL | splat_generic_tuple::<((u32, i8))>((1, 2)); | |
| 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 18 | ||
| 19 | error[E0057]: this splatted function takes 2 arguments, but 1 was provided | |
| 20 | --> $DIR/splat-fn-tuple-generic-fail.rs:23:5 | |
| 21 | | | |
| 22 | LL | splat_generic_tuple::<((u32, i8))>((1u32, 2i8)); | |
| 23 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 24 | ||
| 25 | error[E0057]: this splatted function takes 2 arguments, but 1 was provided | |
| 26 | --> $DIR/splat-fn-tuple-generic-fail.rs:25:5 | |
| 27 | | | |
| 28 | LL | splat_generic_tuple::<(u32, i8)>((1, 2)); | |
| 29 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 30 | ||
| 31 | error[E0057]: this splatted function takes 2 arguments, but 1 was provided | |
| 32 | --> $DIR/splat-fn-tuple-generic-fail.rs:26:5 | |
| 33 | | | |
| 34 | LL | splat_generic_tuple::<(u32, i8)>((1u32, 2i8)); | |
| 35 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 36 | ||
| 37 | error: aborting due to 6 previous errors | |
| 38 | ||
| 39 | For 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 | ||
| 8 | fn splat_generic_tuple<T: std::marker::Tuple>(#[splat] _t: T) {} | |
| 9 | ||
| 10 | fn 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 | ||
| 7 | fn tuple_args(#[splat] (_a, _b): (u32, i8)) {} | |
| 8 | ||
| 9 | fn splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {} | |
| 10 | ||
| 11 | fn 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 | |
| 8 | fn nested_generic<T, U>(#[splat] _: (Vec<T>, Option<U>)) {} | |
| 9 | ||
| 10 | // Box<T> inside splatted tuple | |
| 11 | fn box_generic<T>(#[splat] _: (Box<T>, u32)) {} | |
| 12 | ||
| 13 | // Multiple complex generics | |
| 14 | fn multi_generic<T, U, V>(#[splat] _: (Vec<T>, Option<U>, Box<V>)) {} | |
| 15 | ||
| 16 | fn 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 | ||
| 7 | struct Foo<T>(T); | |
| 8 | ||
| 9 | // FIXME(splat): also add assoc/method with splatted generic tuple traits | |
| 10 | // also add generics inside the splatted tuple | |
| 11 | impl<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 | |
| 28 | trait 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 | ||
| 38 | impl<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 | ||
| 48 | fn 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 | ||
| 6 | fn generic_second<T>(#[splat] _s: (u32, T)) {} | |
| 7 | ||
| 8 | fn generic_first<T>(#[splat] _s: (T, u32)) {} | |
| 9 | ||
| 10 | fn generic_both<T, U>(#[splat] _s: (T, U)) {} | |
| 11 | ||
| 12 | fn generic_triple<T, U, V>(#[splat] _s: (T, U, V)) {} | |
| 13 | ||
| 14 | fn 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 | ||
| 5 | trait FooTrait { | |
| 6 | fn method(#[splat] _: (u32, i8)); | |
| 7 | } | |
| 8 | ||
| 9 | struct Foo; | |
| 10 | struct Foo1; | |
| 11 | struct Foo2; | |
| 12 | ||
| 13 | impl FooTrait for Foo { | |
| 14 | fn method(#[splat] _: (u32, f32)) {} | |
| 15 | //~^ ERROR method `method` has an incompatible type for trait | |
| 16 | } | |
| 17 | ||
| 18 | impl FooTrait for Foo1 { | |
| 19 | fn method(#[splat] _: (f32, i8)) {} | |
| 20 | //~^ ERROR method `method` has an incompatible type for trait | |
| 21 | } | |
| 22 | ||
| 23 | impl FooTrait for Foo2 { | |
| 24 | fn method(#[splat] _: (f32, f64)) {} | |
| 25 | //~^ ERROR method `method` has an incompatible type for trait | |
| 26 | } | |
| 27 | fn main() {} |
tests/ui/splat/splat-invalid-trait-impl.stderr created+60| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | error[E0053]: method `method` has an incompatible type for trait | |
| 2 | --> $DIR/splat-invalid-trait-impl.rs:14:27 | |
| 3 | | | |
| 4 | LL | fn method(#[splat] _: (u32, f32)) {} | |
| 5 | | ^^^^^^^^^^ expected `i8`, found `f32` | |
| 6 | | | |
| 7 | note: type in trait | |
| 8 | --> $DIR/splat-invalid-trait-impl.rs:6:27 | |
| 9 | | | |
| 10 | LL | fn method(#[splat] _: (u32, i8)); | |
| 11 | | ^^^^^^^^^ | |
| 12 | = note: expected signature `fn(#[splat] (_, i8))` | |
| 13 | found signature `fn(#[splat] (_, f32))` | |
| 14 | help: change the parameter type to match the trait | |
| 15 | | | |
| 16 | LL - fn method(#[splat] _: (u32, f32)) {} | |
| 17 | LL + fn method(#[splat] _: (u32, i8)) {} | |
| 18 | | | |
| 19 | ||
| 20 | error[E0053]: method `method` has an incompatible type for trait | |
| 21 | --> $DIR/splat-invalid-trait-impl.rs:19:27 | |
| 22 | | | |
| 23 | LL | fn method(#[splat] _: (f32, i8)) {} | |
| 24 | | ^^^^^^^^^ expected `u32`, found `f32` | |
| 25 | | | |
| 26 | note: type in trait | |
| 27 | --> $DIR/splat-invalid-trait-impl.rs:6:27 | |
| 28 | | | |
| 29 | LL | fn method(#[splat] _: (u32, i8)); | |
| 30 | | ^^^^^^^^^ | |
| 31 | = note: expected signature `fn(#[splat] (u32, _))` | |
| 32 | found signature `fn(#[splat] (f32, _))` | |
| 33 | help: change the parameter type to match the trait | |
| 34 | | | |
| 35 | LL - fn method(#[splat] _: (f32, i8)) {} | |
| 36 | LL + fn method(#[splat] _: (u32, i8)) {} | |
| 37 | | | |
| 38 | ||
| 39 | error[E0053]: method `method` has an incompatible type for trait | |
| 40 | --> $DIR/splat-invalid-trait-impl.rs:24:27 | |
| 41 | | | |
| 42 | LL | fn method(#[splat] _: (f32, f64)) {} | |
| 43 | | ^^^^^^^^^^ expected `u32`, found `f32` | |
| 44 | | | |
| 45 | note: type in trait | |
| 46 | --> $DIR/splat-invalid-trait-impl.rs:6:27 | |
| 47 | | | |
| 48 | LL | fn method(#[splat] _: (u32, i8)); | |
| 49 | | ^^^^^^^^^ | |
| 50 | = note: expected signature `fn(#[splat] (u32, i8))` | |
| 51 | found signature `fn(#[splat] (f32, f64))` | |
| 52 | help: change the parameter type to match the trait | |
| 53 | | | |
| 54 | LL - fn method(#[splat] _: (f32, f64)) {} | |
| 55 | LL + fn method(#[splat] _: (u32, i8)) {} | |
| 56 | | | |
| 57 | ||
| 58 | error: aborting due to 3 previous errors | |
| 59 | ||
| 60 | For more information about this error, try `rustc --explain E0053`. |
tests/ui/splat/splat-invalid.rs+14| ... | ... | @@ -30,4 +30,18 @@ extern "C" { |
| 30 | 30 | fn bar_2(#[splat] _: (u32, i8)); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | trait FooTrait { | |
| 34 | fn has_splat(#[splat] _: ()); | |
| 35 | ||
| 36 | fn no_splat(_: (u32, f64)); | |
| 37 | } | |
| 38 | ||
| 39 | struct Foo; | |
| 40 | ||
| 41 | impl 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 | ||
| 33 | 47 | fn main() {} |
tests/ui/splat/splat-invalid.stderr+30-1| ... | ... | @@ -73,5 +73,34 @@ LL | fn splat_variadic4(..., #[splat] (_a, _b): (u32, i8)) {} |
| 73 | 73 | | |
| 74 | 74 | = help: remove `#[splat]` or remove `...` |
| 75 | 75 | |
| 76 | error: aborting due to 9 previous errors | |
| 76 | error[E0053]: method `has_splat` has an incompatible type for trait | |
| 77 | --> $DIR/splat-invalid.rs:42:5 | |
| 78 | | | |
| 79 | LL | fn has_splat(_: ()) {} | |
| 80 | | ^^^^^^^^^^^^^^^^^^^ expected fn with arg 0 splatted, found fn with no splatted arg | |
| 81 | | | |
| 82 | note: type in trait | |
| 83 | --> $DIR/splat-invalid.rs:34:5 | |
| 84 | | | |
| 85 | LL | fn has_splat(#[splat] _: ()); | |
| 86 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 87 | = note: expected signature `fn(#[splat] ())` | |
| 88 | found signature `fn(())` | |
| 89 | ||
| 90 | error[E0053]: method `no_splat` has an incompatible type for trait | |
| 91 | --> $DIR/splat-invalid.rs:44:5 | |
| 92 | | | |
| 93 | LL | fn no_splat(#[splat] _: (u32, f64)) {} | |
| 94 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn with no splatted arg, found fn with arg 0 splatted | |
| 95 | | | |
| 96 | note: type in trait | |
| 97 | --> $DIR/splat-invalid.rs:36:5 | |
| 98 | | | |
| 99 | LL | fn no_splat(_: (u32, f64)); | |
| 100 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 101 | = note: expected signature `fn((_, _))` | |
| 102 | found signature `fn(#[splat] (_, _))` | |
| 103 | ||
| 104 | error: aborting due to 11 previous errors | |
| 77 | 105 | |
| 106 | For 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 | ||
| 8 | fn 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 | ||
| 10 | fn 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 @@ |
| 1 | error[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 | | | |
| 4 | LL | fn unbound_generic_arg<T>(#[splat] t: T) {} | |
| 5 | | ^ | |
| 6 | ... | |
| 7 | LL | unbound_generic_arg::<u32>(1); | |
| 8 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 9 | ||
| 10 | error: aborting due to 1 previous error | |
| 11 | ||
| 12 | For 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 | ||
| 7 | struct Foo; | |
| 8 | ||
| 9 | impl 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)] | |
| 20 | struct TupleStruct(u32, i8); | |
| 21 | ||
| 22 | impl TupleStruct { | |
| 23 | fn tuple_2(&self, #[splat] (a, _b): (u32, i8)) -> u32 { | |
| 24 | a | |
| 25 | } | |
| 26 | } | |
| 27 | ||
| 28 | fn 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 | ||
| 7 | fn primitive_arg(#[splat] x: u32) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a u32 | |
| 8 | ||
| 9 | enum NotATuple { | |
| 10 | A(u32), | |
| 11 | B(i8), | |
| 12 | } | |
| 13 | ||
| 14 | fn enum_arg(#[splat] y: NotATuple) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a NotATuple | |
| 15 | ||
| 16 | trait 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 | ||
| 23 | struct Foo; | |
| 24 | ||
| 25 | fn struct_arg(#[splat] z: Foo) {} //~ ERROR cannot use splat attribute; the splatted argument type must be a tuple or unit, not a Foo | |
| 26 | ||
| 27 | impl 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 | ||
| 37 | impl 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 | ||
| 52 | struct TupleStruct(u32, i8); | |
| 53 | ||
| 54 | fn 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 | ||
| 56 | impl 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 | ||
| 65 | impl 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 | ||
| 75 | fn 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 @@ |
| 1 | error[E0053]: method `tuple_1` has an incompatible type for trait | |
| 2 | --> $DIR/splat-non-tuple.rs:38:5 | |
| 3 | | | |
| 4 | LL | fn tuple_1(_: (u32,)) {} | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^ expected fn with arg 0 splatted, found fn with no splatted arg | |
| 6 | | | |
| 7 | note: type in trait | |
| 8 | --> $DIR/splat-non-tuple.rs:17:5 | |
| 9 | | | |
| 10 | LL | fn tuple_1(#[splat] _: (u32,)); | |
| 11 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 12 | = note: expected signature `fn(#[splat] (_,))` | |
| 13 | found signature `fn((_,))` | |
| 14 | ||
| 15 | error[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 | | | |
| 18 | LL | fn primitive_arg(#[splat] x: u32) {} | |
| 19 | | ^^^ | |
| 20 | ... | |
| 21 | LL | primitive_arg(1u32); | |
| 22 | | ^^^^^^^^^^^^^^^^^^^ | |
| 23 | ||
| 24 | error[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 | | | |
| 27 | LL | fn enum_arg(#[splat] y: NotATuple) {} | |
| 28 | | ^^^^^^^^^ | |
| 29 | ... | |
| 30 | LL | enum_arg(NotATuple::A(1u32)); | |
| 31 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 32 | ||
| 33 | error[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 | | | |
| 36 | LL | fn struct_arg(#[splat] z: Foo) {} | |
| 37 | | ^^^ | |
| 38 | ... | |
| 39 | LL | struct_arg(foo); | |
| 40 | | ^^^^^^^^^^^^^^^ | |
| 41 | ||
| 42 | error[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 | | | |
| 45 | LL | fn tuple_struct_arg(#[splat] z: TupleStruct) {} | |
| 46 | | ^^^^^^^^^^^ | |
| 47 | ... | |
| 48 | LL | tuple_struct_arg(tuple_struct); | |
| 49 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 50 | ||
| 51 | error: aborting due to 5 previous errors | |
| 52 | ||
| 53 | Some errors have detailed explanations: E0053, E0277. | |
| 54 | For 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 | ||
| 7 | struct Foo; | |
| 8 | ||
| 9 | trait MethodArgs: std::marker::Tuple { | |
| 10 | fn call_method(self, _this: &Foo); | |
| 11 | } | |
| 12 | ||
| 13 | impl MethodArgs for () { | |
| 14 | fn call_method(self, _this: &Foo) {} | |
| 15 | } | |
| 16 | ||
| 17 | impl MethodArgs for (i32,) { | |
| 18 | fn call_method(self, _this: &Foo) {} | |
| 19 | } | |
| 20 | ||
| 21 | impl MethodArgs for (i32, String) { | |
| 22 | fn call_method(self, _this: &Foo) {} | |
| 23 | } | |
| 24 | ||
| 25 | impl Foo { | |
| 26 | fn method<T: MethodArgs>(&self, #[splat] args: T) { | |
| 27 | args.call_method(self) | |
| 28 | } | |
| 29 | } | |
| 30 | ||
| 31 | fn 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 @@ |
| 1 | error[E0308]: mismatched types | |
| 2 | --> $DIR/splat-overload-at-home-fail.rs:35:16 | |
| 3 | | | |
| 4 | LL | foo.method(42f32); | |
| 5 | | ------ ^^^^^ expected `i32`, found `f32` | |
| 6 | | | | |
| 7 | | arguments to this method are incorrect | |
| 8 | | | |
| 9 | note: method defined here | |
| 10 | --> $DIR/splat-overload-at-home-fail.rs:26:8 | |
| 11 | | | |
| 12 | LL | fn method<T: MethodArgs>(&self, #[splat] args: T) { | |
| 13 | | ^^^^^^ ---------------- | |
| 14 | help: change the type of the numeric literal from `f32` to `i32` | |
| 15 | | | |
| 16 | LL - foo.method(42f32); | |
| 17 | LL + foo.method(42i32); | |
| 18 | | | |
| 19 | ||
| 20 | error[E0308]: mismatched types | |
| 21 | --> $DIR/splat-overload-at-home-fail.rs:39:23 | |
| 22 | | | |
| 23 | LL | foo.method(42i32, 42i32); | |
| 24 | | ------ ^^^^^ expected `String`, found `i32` | |
| 25 | | | | |
| 26 | | arguments to this method are incorrect | |
| 27 | | | |
| 28 | note: method defined here | |
| 29 | --> $DIR/splat-overload-at-home-fail.rs:26:8 | |
| 30 | | | |
| 31 | LL | fn method<T: MethodArgs>(&self, #[splat] args: T) { | |
| 32 | | ^^^^^^ | |
| 33 | help: try using a conversion method | |
| 34 | | | |
| 35 | LL | foo.method(42i32, 42i32.to_string()); | |
| 36 | | ++++++++++++ | |
| 37 | ||
| 38 | error: aborting due to 2 previous errors | |
| 39 | ||
| 40 | For 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 | ||
| 10 | struct Foo; | |
| 11 | ||
| 12 | trait MethodArgs: std::marker::Tuple { | |
| 13 | fn call_method(self, _this: &Foo); | |
| 14 | } | |
| 15 | impl MethodArgs for () { | |
| 16 | fn call_method(self, _this: &Foo) {} | |
| 17 | } | |
| 18 | impl MethodArgs for (i32,) { | |
| 19 | fn call_method(self, _this: &Foo) {} | |
| 20 | } | |
| 21 | impl MethodArgs for (i32, String) { | |
| 22 | fn call_method(self, _this: &Foo) {} | |
| 23 | } | |
| 24 | ||
| 25 | impl Foo { | |
| 26 | fn method<T: MethodArgs>(&self, #[splat] args: T) { | |
| 27 | args.call_method(self) | |
| 28 | } | |
| 29 | } | |
| 30 | ||
| 31 | fn 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 | ||
| 7 | trait FooTrait { | |
| 8 | fn tuple_1_trait(#[splat] _: (u32,)); | |
| 9 | ||
| 10 | fn tuple_2_trait(&self, #[splat] _: (u32, f32)); | |
| 11 | } | |
| 12 | ||
| 13 | struct Foo; | |
| 14 | ||
| 15 | impl 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)] | |
| 23 | struct TupleStruct(u32, i8); | |
| 24 | ||
| 25 | impl FooTrait for TupleStruct { | |
| 26 | fn tuple_1_trait(#[splat] _: (u32,)) {} | |
| 27 | ||
| 28 | fn tuple_2_trait(&self, #[splat] _: (u32, f32)) {} | |
| 29 | } | |
| 30 | ||
| 31 | fn 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 | ||
| 6 | unsafe 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 | ||
| 9 | unsafe 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 | ||
| 12 | fn 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 @@ |
| 1 | error: multiple `#[splat]`s are not allowed in the same function | |
| 2 | --> $DIR/splat-unsafe-fn-tuple-fail.rs:9:30 | |
| 3 | | | |
| 4 | LL | 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 | ||
| 9 | error[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 | | | |
| 12 | LL | unsafe fn unsafe_wrong_type(#[splat] _x: u32) {} | |
| 13 | | ^^^ | |
| 14 | ... | |
| 15 | LL | unsafe_wrong_type(1u32); | |
| 16 | | ^^^^^^^^^^^^^^^^^^^^^^^ | |
| 17 | ||
| 18 | error: aborting due to 2 previous errors | |
| 19 | ||
| 20 | For 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 | ||
| 7 | unsafe fn unsafe_tuple_args(#[splat] (_a, _b): (u32, i8)) {} | |
| 8 | ||
| 9 | unsafe fn unsafe_splat_non_terminal_arg(#[splat] (_a, _b): (u32, i8), _c: f64) {} | |
| 10 | ||
| 11 | fn 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 | ||
| 8 | fn where_splat<T>(#[splat] _t: T) where T: std::marker::Tuple {} | |
| 9 | ||
| 10 | fn where_splat_with_extra<T>(#[splat] _t: T, _extra: u32) where T: std::marker::Tuple {} | |
| 11 | ||
| 12 | fn impl_tuple_splat(#[splat] _t: impl std::marker::Tuple) {} | |
| 13 | ||
| 14 | fn impl_tuple_splat_with_extra(#[splat] _t: impl std::marker::Tuple, _extra: u32) {} | |
| 15 | ||
| 16 | fn 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 @@ |
| 1 | error: symbol-name(_ZN5basic4main17h27f62b2d0b2beac6E) | |
| 1 | error: symbol-name(_ZN5basic4main17h33f35fba43592008E) | |
| 2 | 2 | --> $DIR/basic.rs:8:1 |
| 3 | 3 | | |
| 4 | 4 | LL | #[rustc_dump_symbol_name] |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 6 | 6 | |
| 7 | error: demangling(basic::main::h27f62b2d0b2beac6) | |
| 7 | error: demangling(basic::main::h33f35fba43592008) | |
| 8 | 8 | --> $DIR/basic.rs:8:1 |
| 9 | 9 | | |
| 10 | 10 | LL | #[rustc_dump_symbol_name] |
tests/ui/symbol-names/issue-60925.legacy.stderr+2-2| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h1eb769490ff06e77E) | |
| 1 | error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hc741419c44ba4d79E) | |
| 2 | 2 | --> $DIR/issue-60925.rs:21:9 |
| 3 | 3 | | |
| 4 | 4 | LL | #[rustc_dump_symbol_name] |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 6 | 6 | |
| 7 | error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h1eb769490ff06e77) | |
| 7 | error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hc741419c44ba4d79) | |
| 8 | 8 | --> $DIR/issue-60925.rs:21:9 |
| 9 | 9 | | |
| 10 | 10 | LL | #[rustc_dump_symbol_name] |