diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index ab2c7ca8a47c8..3ecb0ef6b4d29 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -79,16 +79,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecaa4c3da2d74c1a991b4faff75d49ab1d0522d9a99d8e2614b3b04d226417ce" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406a66fba005f1a02661f2f9443e5693dd3a667b7c58e70aa4ccc4c8b50b4758" dependencies = [ "libc", ] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 100c10ef1d7af..c5aa2eed1e004 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -22,7 +22,7 @@ master = ["gccjit/master"] default = ["master"] [dependencies] -gccjit = { git = "https://github.com/antoyo/gccjit.rs" } +gccjit = "2.0" # Local copy. #gccjit = { path = "../gccjit.rs" } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4c975c7b9e052..36db377f7e0a8 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -567,6 +567,8 @@ declare_features! ( (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. (unstable, raw_ref_op, "1.41.0", Some(64490)), + /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references. + (incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 36af539401565..dbae8bfb54249 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -227,11 +227,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, }); - let closure_kind_ty = self.next_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish closure kind inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }); + + let closure_kind_ty = match expected_kind { + Some(kind) => Ty::from_closure_kind(tcx, kind), + + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + }; + let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, @@ -262,10 +269,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); - let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }); + let coroutine_kind_ty = match expected_kind { + Some(kind) => Ty::from_coroutine_closure_kind(tcx, kind), + + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + }; + let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9d247c46bab4b..bb47f8dfba46c 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -130,7 +130,14 @@ enum AdjustMode { /// Peel off all immediate reference types. Peel, /// Reset binding mode to the initial mode. + /// Used for destructuring assignment, where we don't want any match ergonomics. Reset, + /// Produced by ref patterns. + /// Reset the binding mode to the initial mode, + /// and if the old biding mode was by-reference + /// with mutability matching the pattern, + /// mark the pattern as having consumed this reference. + ResetAndConsumeRef(Mutability), /// Pass on the input binding mode and expected type. Pass, } @@ -174,7 +181,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); - let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); + let (expected, def_bm, ref_pattern_already_consumed) = + self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); let pat_info = PatInfo { binding_mode: def_bm, top_info: ti, @@ -211,7 +219,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info), - PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), + PatKind::Ref(inner, mutbl) => self.check_pat_ref( + pat, + inner, + mutbl, + expected, + pat_info, + ref_pattern_already_consumed, + ), PatKind::Slice(before, slice, after) => { self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) } @@ -264,17 +279,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Compute the new expected type and default binding mode from the old ones /// as well as the pattern form we are currently checking. + /// + /// Last entry is only relevant for ref patterns (`&` and `&mut`); + /// if `true`, then the ref pattern consumed a match ergonomics inserted reference + /// and so does no need to match against a reference in the scrutinee type. fn calc_default_binding_mode( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingAnnotation, adjust_mode: AdjustMode, - ) -> (Ty<'tcx>, BindingAnnotation) { + ) -> (Ty<'tcx>, BindingAnnotation, bool) { match adjust_mode { - AdjustMode::Pass => (expected, def_bm), - AdjustMode::Reset => (expected, INITIAL_BM), - AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm), + AdjustMode::Pass => (expected, def_bm, false), + AdjustMode::Reset => (expected, INITIAL_BM, false), + AdjustMode::ResetAndConsumeRef(mutbl) => { + (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)) + } + AdjustMode::Peel => { + let peeled = self.peel_off_references(pat, expected, def_bm); + (peeled.0, peeled.1, false) + } } } @@ -329,7 +354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` // // See issue #46688. - PatKind::Ref(..) => AdjustMode::Reset, + PatKind::Ref(_, mutbl) => AdjustMode::ResetAndConsumeRef(*mutbl), // A `_` pattern works with any expected type, so there's no need to do anything. PatKind::Wild // A malformed pattern doesn't have an expected type, so let's just accept any type. @@ -840,8 +865,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) && let ty::Dynamic(..) = mt.ty.kind() { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. + // This is "x = dyn SomeTrait" being reduced from + // "let &x = &dyn SomeTrait" or "let box x = Box", an error. let type_str = self.ty_to_string(expected); let mut err = struct_span_code_err!( self.dcx(), @@ -2036,6 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mutbl: Mutability, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, + consumed_inherited_ref: bool, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -2051,26 +2077,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *expected.kind() { ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), _ => { - let inner_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: inner.span, - }); - let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); - debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); - let err = self.demand_eqtype_pat_diag( - pat.span, - expected, - ref_ty, - pat_info.top_info, - ); + if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere { + // We already matched against a match-ergonmics inserted reference, + // so we don't need to match against a reference from the original type. + // Save this infor for use in lowering later + self.typeck_results + .borrow_mut() + .skipped_ref_pats_mut() + .insert(pat.hir_id); + (expected, expected) + } else { + let inner_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: inner.span, + }); + let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); + debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); + let err = self.demand_eqtype_pat_diag( + pat.span, + expected, + ref_ty, + pat_info.top_info, + ); - // Look for a case like `fn foo(&foo: u32)` and suggest - // `fn foo(foo: &u32)` - if let Some(mut err) = err { - self.borrow_pat_suggestion(&mut err, pat); - err.emit(); + // Look for a case like `fn foo(&foo: u32)` and suggest + // `fn foo(foo: &u32)` + if let Some(mut err) = err { + self.borrow_pat_suggestion(&mut err, pat); + err.emit(); + } + (ref_ty, inner_ty) } - (ref_ty, inner_ty) } } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 72e5b1ed95bf0..c987bfb9a0e88 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -166,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, body_id: hir::BodyId, body: &'tcx hir::Body<'tcx>, - capture_clause: hir::CaptureBy, + mut capture_clause: hir::CaptureBy, ) { // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); @@ -259,6 +259,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .consume_body(body); + // If a coroutine is comes from a coroutine-closure that is `move`, but + // the coroutine-closure was inferred to be `FnOnce` during signature + // inference, then it's still possible that we try to borrow upvars from + // the coroutine-closure because they are not used by the coroutine body + // in a way that forces a move. + // + // This would lead to an impossible to satisfy situation, since `AsyncFnOnce` + // coroutine bodies can't borrow from their parent closure. To fix this, + // we force the inner coroutine to also be `move`. This only matters for + // coroutine-closures that are `move` since otherwise they themselves will + // be borrowing from the outer environment, so there's no self-borrows occuring. + if let UpvarArgs::Coroutine(..) = args + && let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) = + self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind") + && let parent_hir_id = + self.tcx.local_def_id_to_hir_id(self.tcx.local_parent(closure_def_id)) + && let parent_ty = self.node_ty(parent_hir_id) + && let Some(ty::ClosureKind::FnOnce) = self.closure_kind(parent_ty) + { + capture_clause = self.tcx.hir_node(parent_hir_id).expect_closure().capture_clause; + } + debug!( "For closure={:?}, capture_information={:#?}", closure_def_id, delegate.capture_information @@ -399,16 +421,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // Additionally, we can now constrain the coroutine's kind type. - let ty::Coroutine(_, coroutine_args) = - *self.typeck_results.borrow().expr_ty(body.value).kind() - else { - bug!(); - }; - self.demand_eqtype( - span, - coroutine_args.as_coroutine().kind_ty(), - Ty::from_coroutine_closure_kind(self.tcx, closure_kind), - ); + // + // We only do this if `infer_kind`, because if we have constrained + // the kind from closure signature inference, the kind inferred + // for the inner coroutine may actually be more restrictive. + if infer_kind { + let ty::Coroutine(_, coroutine_args) = + *self.typeck_results.borrow().expr_ty(body.value).kind() + else { + bug!(); + }; + self.demand_eqtype( + span, + coroutine_args.as_coroutine().kind_ty(), + Ty::from_coroutine_closure_kind(self.tcx, closure_kind), + ); + } } self.log_closure_min_capture_info(closure_def_id, span); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index f4516b684c386..6604bf094c14a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -345,6 +345,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { _ => {} }; + self.visit_skipped_ref_pats(p.hir_id); self.visit_pat_adjustments(p.span, p.hir_id); self.visit_node_id(p.span, p.hir_id); @@ -674,6 +675,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self), level = "debug")] + fn visit_skipped_ref_pats(&mut self, hir_id: hir::HirId) { + if self.fcx.typeck_results.borrow_mut().skipped_ref_pats_mut().remove(hir_id) { + debug!("node is a skipped ref pat"); + self.typeck_results.skipped_ref_pats_mut().insert(hir_id); + } + } + fn visit_liberated_fn_sigs(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 0d74524276fa7..995feeaa1487f 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -96,6 +96,10 @@ pub struct TypeckResults<'tcx> { /// pat_adjustments: ItemLocalMap>>, + /// Set of reference patterns that match against a match-ergonomics inserted reference + /// (as opposed to against a reference in the scrutinee type). + skipped_ref_pats: ItemLocalSet, + /// Records the reasons that we picked the kind of each closure; /// not all closures are present in the map. closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>, @@ -228,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> { adjustments: Default::default(), pat_binding_modes: Default::default(), pat_adjustments: Default::default(), + skipped_ref_pats: Default::default(), closure_kind_origins: Default::default(), liberated_fn_sigs: Default::default(), fru_field_types: Default::default(), @@ -435,6 +440,14 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> { + LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats } + } + + pub fn skipped_ref_pats_mut(&mut self) -> LocalSetInContextMut<'_> { + LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.skipped_ref_pats } + } + /// Does the pattern recursively contain a `ref mut` binding in it? /// /// This is used to determined whether a `deref` pattern should emit a `Deref` @@ -629,6 +642,49 @@ impl<'a, V> LocalTableInContextMut<'a, V> { } } +#[derive(Clone, Copy, Debug)] +pub struct LocalSetInContext<'a> { + hir_owner: OwnerId, + data: &'a ItemLocalSet, +} + +impl<'a> LocalSetInContext<'a> { + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn contains(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.contains(&id.local_id) + } +} + +#[derive(Debug)] +pub struct LocalSetInContextMut<'a> { + hir_owner: OwnerId, + data: &'a mut ItemLocalSet, +} + +impl<'a> LocalSetInContextMut<'a> { + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn contains(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.contains(&id.local_id) + } + pub fn insert(&mut self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.insert(id.local_id) + } + + pub fn remove(&mut self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.remove(&id.local_id) + } +} + rustc_index::newtype_index! { #[derive(HashStable)] #[encodable] diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a4992da679e8a..133cf8e334929 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -65,7 +65,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted // gets the least-dereferenced type). - let unadjusted_pat = self.lower_pattern_unadjusted(pat); + let unadjusted_pat = match pat.kind { + hir::PatKind::Ref(inner, _) + if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) => + { + self.lower_pattern_unadjusted(inner) + } + _ => self.lower_pattern_unadjusted(pat), + }; self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( unadjusted_pat, |pat: Box<_>, ref_ty| { diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 0866205dfd0db..de43f9faff909 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -91,15 +91,17 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { return; } - let ty::Coroutine(_, coroutine_args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; - // We don't need to generate a by-move coroutine if the kind of the coroutine is - // already `FnOnce` -- that means that any upvars that the closure consumes have - // already been taken by-value. - let coroutine_kind = coroutine_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(); - if coroutine_kind == ty::ClosureKind::FnOnce { + // We don't need to generate a by-move coroutine if the coroutine body was + // produced by the `CoroutineKindShim`, since it's already by-move. + if matches!(body.source.instance, ty::InstanceDef::CoroutineKindShim { .. }) { return; } + let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; + let args = args.as_coroutine(); + + let coroutine_kind = args.kind_ty().to_opt_closure_kind().unwrap(); + let parent_def_id = tcx.local_parent(coroutine_def_id); let ty::CoroutineClosure(_, parent_args) = *tcx.type_of(parent_def_id).instantiate_identity().kind() @@ -128,6 +130,12 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { // the outer closure body -- we need to change the coroutine to take the // upvar by value. if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() { + assert_ne!( + coroutine_kind, + ty::ClosureKind::FnOnce, + "`FnOnce` coroutine-closures return coroutines that capture from \ + their body; it will always result in a borrowck error!" + ); by_ref_fields.insert(FieldIdx::from_usize(num_args + idx)); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a13c9c9b2784d..ea0f7adf6f916 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1456,6 +1456,7 @@ symbols! { receiver, recursion_limit, reexport_test_harness_main, + ref_pat_everywhere, ref_unwind_safe_trait, reference, reflect, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index ab8d7d31e438a..46a0a4eb5ef8f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -407,10 +407,6 @@ fn report_conflicting_impls<'tcx>( impl_span: Span, err: &mut Diag<'_, G>, ) { - if (overlap.trait_ref, overlap.self_ty).references_error() { - err.downgrade_to_delayed_bug(); - } - match tcx.span_of_impl(overlap.with_impl) { Ok(span) => { err.span_label(span, "first implementation here"); @@ -463,6 +459,11 @@ fn report_conflicting_impls<'tcx>( ) }); + // Don't report overlap errors if the header references error + if let Err(err) = (overlap.trait_ref, overlap.self_ty).error_reported() { + return Err(err); + } + match used_to_be_allowed { None => { let reported = if overlap.with_impl.is_local() diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 19ca147d3ad63..a44a5ae0e6b42 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -714,8 +714,6 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // perfect and there may be ways to abuse the fact that we // ignore requirements with escaping bound vars. That's a // more general issue however. - // - // FIXME(eddyb) add the type to `walker` instead of recursing. let fn_sig = tcx.fn_sig(did).instantiate(tcx, args); fn_sig.output().skip_binder().visit_with(self); diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 30d728aa23005..39add60e705fe 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1038,6 +1038,7 @@ def check_vendored_status(self): sync_dirs = "--sync ./src/tools/cargo/Cargo.toml " \ "--sync ./src/tools/rust-analyzer/Cargo.toml " \ "--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \ + "--sync ./compiler/rustc_codegen_gcc/Cargo.toml " \ "--sync ./src/bootstrap/Cargo.toml " eprint('ERROR: vendoring required, but vendor directory does not exist.') eprint(' Run `cargo vendor {}` to initialize the ' diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index ecea62140a2e1..b51d3e157887b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1011,6 +1011,8 @@ impl Step for PlainSourceTarball { .arg("--sync") .arg(builder.src.join("./compiler/rustc_codegen_cranelift/Cargo.toml")) .arg("--sync") + .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml")) + .arg("--sync") .arg(builder.src.join("./src/bootstrap/Cargo.toml")) // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index c597514f1707a..9555be481e695 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2102,12 +2102,10 @@ impl<'a> Builder<'a> { rustdocflags.arg("--cfg=parallel_compiler"); } - // set rustc args passed from command line - let rustc_args = - self.config.cmd.rustc_args().iter().map(|s| s.to_string()).collect::>(); - if !rustc_args.is_empty() { - cargo.env("RUSTFLAGS", &rustc_args.join(" ")); - } + // Pass the value of `--rustc-args` from test command. If it's not a test command, this won't set anything. + self.config.cmd.rustc_args().iter().for_each(|v| { + rustflags.arg(v); + }); Cargo { command: cargo, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index bd2f65925bb96..689fdc5dfebc0 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3926,11 +3926,17 @@ impl<'test> TestCx<'test> { cmd.env("IS_MSVC", "1") .env("IS_WINDOWS", "1") .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("CC", format!("'{}' {}", self.config.cc, cflags)) - .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags)); + // Note: we diverge from legacy run_make and don't lump `CC` the compiler and + // default flags together. + .env("CC_DEFAULT_FLAGS", &cflags) + .env("CC", &self.config.cc) + .env("CXX_DEFAULT_FLAGS", &cxxflags) + .env("CXX", &self.config.cxx); } else { - cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags)) + cmd.env("CC_DEFAULT_FLAGS", &self.config.cflags) + .env("CC", &self.config.cc) + .env("CXX_DEFAULT_FLAGS", &self.config.cxxflags) + .env("CXX", &self.config.cxx) .env("AR", &self.config.ar); if self.config.target.contains("windows") { diff --git a/src/tools/miri/tests/pass/async-closure-captures.rs b/src/tools/miri/tests/pass/async-closure-captures.rs index 3e33de32efb04..cac26bfe14621 100644 --- a/src/tools/miri/tests/pass/async-closure-captures.rs +++ b/src/tools/miri/tests/pass/async-closure-captures.rs @@ -88,4 +88,38 @@ async fn async_main() { }; call_once(c).await; } + + fn force_fnonce(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T { + f + } + + // Capture something with `move`, but infer to `AsyncFnOnce` + { + let x = Hello(6); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(7); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + } + + // Capture something by-ref, but infer to `AsyncFnOnce` + { + let x = Hello(8); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(9); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + } } diff --git a/src/tools/miri/tests/pass/async-closure-captures.stdout b/src/tools/miri/tests/pass/async-closure-captures.stdout index a0db6d236fef1..42a7999b2dcdd 100644 --- a/src/tools/miri/tests/pass/async-closure-captures.stdout +++ b/src/tools/miri/tests/pass/async-closure-captures.stdout @@ -8,3 +8,7 @@ Hello(3) Hello(4) Hello(4) Hello(5) +Hello(6) +Hello(7) +Hello(8) +Hello(9) diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs new file mode 100644 index 0000000000000..2c9ad4f17006c --- /dev/null +++ b/src/tools/run-make-support/src/cc.rs @@ -0,0 +1,202 @@ +use std::env; +use std::path::Path; +use std::process::{Command, Output}; + +use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname}; + +/// Construct a new platform-specific C compiler invocation. +/// +/// WARNING: This means that what flags are accepted by the underlying C compiler is +/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`. +pub fn cc() -> Cc { + Cc::new() +} + +/// A platform-specific C compiler invocation builder. The specific C compiler used is +/// passed down from compiletest. +#[derive(Debug)] +pub struct Cc { + cmd: Command, +} + +impl Cc { + /// Construct a new platform-specific C compiler invocation. + /// + /// WARNING: This means that what flags are accepted by the underlying C compile is + /// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`. + pub fn new() -> Self { + let compiler = env::var("CC").unwrap(); + + let mut cmd = Command::new(compiler); + + let default_cflags = env::var("CC_DEFAULT_FLAGS").unwrap(); + for flag in default_cflags.split(char::is_whitespace) { + cmd.arg(flag); + } + + Self { cmd } + } + + /// Specify path of the input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Add a *platform-and-compiler-specific* argument. Please consult the docs for the various + /// possible C compilers on the various platforms to check which arguments are legal for + /// which compiler. + pub fn arg(&mut self, flag: &str) -> &mut Self { + self.cmd.arg(flag); + self + } + + /// Add multiple *platform-and-compiler-specific* arguments. Please consult the docs for the + /// various possible C compilers on the various platforms to check which arguments are legal + /// for which compiler. + pub fn args(&mut self, args: &[&str]) -> &mut Self { + self.cmd.args(args); + self + } + + /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable + /// is under `$TMPDIR`. + pub fn out_exe(&mut self, name: &str) -> &mut Self { + // Ref: tools.mk (irrelevant lines omitted): + // + // ```makefile + // ifdef IS_MSVC + // OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \ + // -Fo:`cygpath -w $(TMPDIR)/$(1).obj` + // else + // OUT_EXE=-o $(TMPDIR)/$(1) + // endif + // ``` + + if is_msvc() { + let fe_path = cygpath_windows(tmp_dir().join(bin_name(name))); + let fo_path = cygpath_windows(tmp_dir().join(format!("{name}.obj"))); + self.cmd.arg(format!("-Fe:{fe_path}")); + self.cmd.arg(format!("-Fo:{fo_path}")); + } else { + self.cmd.arg("-o"); + self.cmd.arg(tmp_dir().join(name)); + } + + self + } + + /// Run the constructed C invocation command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } + + /// Inspect what the underlying [`Command`] is up to the current construction. + pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { + f(&self.cmd); + self + } +} + +/// `EXTRACFLAGS` +pub fn extra_c_flags() -> Vec<&'static str> { + // Adapted from tools.mk (trimmed): + // + // ```makefile + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib + // else + // EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization + // endif + // else + // ifeq ($(UNAME),Darwin) + // EXTRACFLAGS := -lresolv + // else + // ifeq ($(UNAME),FreeBSD) + // EXTRACFLAGS := -lm -lpthread -lgcc_s + // else + // ifeq ($(UNAME),SunOS) + // EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv + // else + // ifeq ($(UNAME),OpenBSD) + // EXTRACFLAGS := -lm -lpthread -lc++abi + // else + // EXTRACFLAGS := -lm -lrt -ldl -lpthread + // endif + // endif + // endif + // endif + // endif + // ``` + + if is_windows() { + if is_msvc() { + vec![ + "ws2_32.lib", + "userenv.lib", + "advapi32.lib", + "bcrypt.lib", + "ntdll.lib", + "synchronization.lib", + ] + } else { + vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"] + } + } else { + match uname() { + n if n.contains("Darwin") => vec!["-lresolv"], + n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"], + n if n.contains("SunOS") => { + vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"] + } + n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"], + _ => vec!["-lm", "-lrt", "-ldl", "-lpthread"], + } + } +} + +/// `EXTRACXXFLAGS` +pub fn extra_cxx_flags() -> Vec<&'static str> { + // Adapted from tools.mk (trimmed): + // + // ```makefile + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // else + // EXTRACXXFLAGS := -lstdc++ + // endif + // else + // ifeq ($(UNAME),Darwin) + // EXTRACXXFLAGS := -lc++ + // else + // ifeq ($(UNAME),FreeBSD) + // else + // ifeq ($(UNAME),SunOS) + // else + // ifeq ($(UNAME),OpenBSD) + // else + // EXTRACXXFLAGS := -lstdc++ + // endif + // endif + // endif + // endif + // endif + // ``` + if is_windows() { + if is_msvc() { vec![] } else { vec!["-lstdc++"] } + } else { + match uname() { + n if n.contains("Darwin") => vec!["-lc++"], + _ => vec!["-lstdc++"], + } + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 48fa2bbf1ac45..e70acf5857165 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -1,14 +1,16 @@ +pub mod cc; pub mod run; pub mod rustc; pub mod rustdoc; use std::env; -use std::path::PathBuf; -use std::process::Output; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; pub use object; pub use wasmparser; +pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use run::{run, run_fail}; pub use rustc::{aux_build, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; @@ -18,6 +20,89 @@ pub fn tmp_dir() -> PathBuf { env::var_os("TMPDIR").unwrap().into() } +/// `TARGET` +pub fn target() -> String { + env::var("TARGET").unwrap() +} + +/// Check if target is windows-like. +pub fn is_windows() -> bool { + env::var_os("IS_WINDOWS").is_some() +} + +/// Check if target uses msvc. +pub fn is_msvc() -> bool { + env::var_os("IS_MSVC").is_some() +} + +/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a +/// path with `$TMPDIR` joined with platform-and-compiler-specific library name. +pub fn static_lib(name: &str) -> PathBuf { + tmp_dir().join(static_lib_name(name)) +} + +/// Construct the static library name based on the platform. +pub fn static_lib_name(name: &str) -> String { + // See tools.mk (irrelevant lines omitted): + // + // ```makefile + // ifeq ($(UNAME),Darwin) + // STATICLIB = $(TMPDIR)/lib$(1).a + // else + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // STATICLIB = $(TMPDIR)/$(1).lib + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // endif + // ``` + assert!(!name.contains(char::is_whitespace), "name cannot contain whitespace"); + + if target().contains("msvc") { format!("{name}.lib") } else { format!("lib{name}.a") } +} + +/// Construct the binary name based on platform. +pub fn bin_name(name: &str) -> String { + if is_windows() { format!("{name}.exe") } else { name.to_string() } +} + +/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is +/// available on the platform! +#[track_caller] +pub fn cygpath_windows>(path: P) -> String { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let mut cygpath = Command::new("cygpath"); + cygpath.arg("-w"); + cygpath.arg(path.as_ref()); + let output = cygpath.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", cygpath), output, caller_line_number); + } + let s = String::from_utf8(output.stdout).unwrap(); + // cygpath -w can attach a newline + s.trim().to_string() +} + +/// Run `uname`. This assumes that `uname` is available on the platform! +#[track_caller] +pub fn uname() -> String { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let mut uname = Command::new("uname"); + let output = uname.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", uname), output, caller_line_number); + } + String::from_utf8(output.stdout).unwrap() +} + fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! { if output.status.success() { eprintln!("command incorrectly succeeded at line {caller_line_number}"); diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 42dcf54da22e0..e33ea9d6e40a3 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -2,17 +2,14 @@ use std::env; use std::path::{Path, PathBuf}; use std::process::{Command, Output}; -use super::handle_failed_output; +use crate::is_windows; -fn run_common(bin_name: &str) -> (Command, Output) { - let target = env::var("TARGET").unwrap(); - - let bin_name = - if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; +use super::{bin_name, handle_failed_output}; +fn run_common(name: &str) -> (Command, Output) { let mut bin_path = PathBuf::new(); bin_path.push(env::var("TMPDIR").unwrap()); - bin_path.push(&bin_name); + bin_path.push(&bin_name(name)); let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); let mut cmd = Command::new(bin_path); cmd.env(&ld_lib_path_envvar, { @@ -27,7 +24,7 @@ fn run_common(bin_name: &str) -> (Command, Output) { env::join_paths(paths.iter()).unwrap() }); - if target.contains("windows") { + if is_windows() { let mut paths = vec![]; for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { paths.push(p.to_path_buf()); @@ -42,11 +39,11 @@ fn run_common(bin_name: &str) -> (Command, Output) { /// Run a built binary and make sure it succeeds. #[track_caller] -pub fn run(bin_name: &str) -> Output { +pub fn run(name: &str) -> Output { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); - let (cmd, output) = run_common(bin_name); + let (cmd, output) = run_common(name); if !output.status.success() { handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); } @@ -55,11 +52,11 @@ pub fn run(bin_name: &str) -> Output { /// Run a built binary and make sure it fails. #[track_caller] -pub fn run_fail(bin_name: &str) -> Output { +pub fn run_fail(name: &str) -> Output { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); - let (cmd, output) = run_common(bin_name); + let (cmd, output) = run_common(name); if output.status.success() { handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 347ea1223eb87..c3ed1ff689145 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -5,7 +5,6 @@ run-make/allocator-shim-circular-deps/Makefile run-make/allow-non-lint-warnings-cmdline/Makefile run-make/allow-warnings-cmdline-stability/Makefile run-make/archive-duplicate-names/Makefile -run-make/arguments-non-c-like-enum/Makefile run-make/atomic-lock-free/Makefile run-make/bare-outfile/Makefile run-make/branch-protection-check-IBT/Makefile @@ -131,7 +130,6 @@ run-make/issue-53964/Makefile run-make/issue-64153/Makefile run-make/issue-68794-textrel-on-minimal-lib/Makefile run-make/issue-69368/Makefile -run-make/issue-7349/Makefile run-make/issue-83045/Makefile run-make/issue-83112-incr-test-moved-file/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b74afa0d3e86e..aec2856dbbc83 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -56,7 +56,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>) Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)), ), // tidy-alphabetical-start - //("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored + ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo @@ -164,15 +164,12 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[ // tidy-alphabetical-end ]; -// FIXME uncomment once all deps are vendored -/* const EXCEPTIONS_GCC: ExceptionList = &[ // tidy-alphabetical-start ("gccjit", "GPL-3.0"), ("gccjit_sys", "GPL-3.0"), // tidy-alphabetical-end ]; -*/ const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[ ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0 diff --git a/tests/codegen/no-redundant-item-monomorphization.rs b/tests/codegen/no-redundant-item-monomorphization.rs new file mode 100644 index 0000000000000..466037c377000 --- /dev/null +++ b/tests/codegen/no-redundant-item-monomorphization.rs @@ -0,0 +1,33 @@ +// Test to make sure that inner functions within a polymorphic outer function +// don't get re-codegened when the outer function is monomorphized. The test +// code monomorphizes the outer functions several times, but the magic constants +// used in the inner functions should each appear only once in the generated IR. + +// issue: rust-lang/rust#7349 +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 + +// CHECK-COUNT-1: ret i32 8675309 +// CHECK-COUNT-1: ret i32 11235813 + +fn outer() { + #[allow(dead_code)] + fn inner() -> u32 { + 8675309 + } + inner(); +} + +extern "C" fn outer_foreign() { + #[allow(dead_code)] + fn inner() -> u32 { + 11235813 + } + inner(); +} + +fn main() { + outer::(); + outer::(); + outer_foreign::(); + outer_foreign::(); +} diff --git a/tests/run-make/arguments-non-c-like-enum/Makefile b/tests/run-make/arguments-non-c-like-enum/Makefile deleted file mode 100644 index 0c8d8bf3acc60..0000000000000 --- a/tests/run-make/arguments-non-c-like-enum/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) --crate-type=staticlib nonclike.rs - $(CC) test.c $(call STATICLIB,nonclike) $(call OUT_EXE,test) \ - $(EXTRACFLAGS) $(EXTRACXXFLAGS) - $(call RUN,test) diff --git a/tests/run-make/arguments-non-c-like-enum/rmake.rs b/tests/run-make/arguments-non-c-like-enum/rmake.rs new file mode 100644 index 0000000000000..624a7fb22518d --- /dev/null +++ b/tests/run-make/arguments-non-c-like-enum/rmake.rs @@ -0,0 +1,20 @@ +//! Check that non-trivial `repr(C)` enum in Rust has valid C layout. +//@ ignore-cross-compile + +extern crate run_make_support; + +use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib}; + +pub fn main() { + use std::path::Path; + + rustc().input("nonclike.rs").crate_type("staticlib").run(); + cc().input("test.c") + .input(static_lib("nonclike")) + .out_exe("test") + .args(&extra_c_flags()) + .args(&extra_cxx_flags()) + .inspect(|cmd| eprintln!("{cmd:?}")) + .run(); + run("test"); +} diff --git a/tests/run-make/issue-7349/Makefile b/tests/run-make/issue-7349/Makefile deleted file mode 100644 index dc073b77fe128..0000000000000 --- a/tests/run-make/issue-7349/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include ../tools.mk - -# Test to make sure that inner functions within a polymorphic outer function -# don't get re-codegened when the outer function is monomorphized. The test -# code monomorphizes the outer functions several times, but the magic constants -# used in the inner functions should each appear only once in the generated IR. - -all: - $(RUSTC) foo.rs --emit=llvm-ir - [ "$$(grep -c 'ret i32 8675309' "$(TMPDIR)/foo.ll")" -eq "1" ] - [ "$$(grep -c 'ret i32 11235813' "$(TMPDIR)/foo.ll")" -eq "1" ] diff --git a/tests/run-make/issue-7349/foo.rs b/tests/run-make/issue-7349/foo.rs deleted file mode 100644 index 246a12595808b..0000000000000 --- a/tests/run-make/issue-7349/foo.rs +++ /dev/null @@ -1,22 +0,0 @@ -fn outer() { - #[allow(dead_code)] - fn inner() -> u32 { - 8675309 - } - inner(); -} - -extern "C" fn outer_foreign() { - #[allow(dead_code)] - fn inner() -> u32 { - 11235813 - } - inner(); -} - -fn main() { - outer::(); - outer::(); - outer_foreign::(); - outer_foreign::(); -} diff --git a/tests/ui/async-await/async-closures/captures.rs b/tests/ui/async-await/async-closures/captures.rs index e3ab8713709d4..0a9d0529bf542 100644 --- a/tests/ui/async-await/async-closures/captures.rs +++ b/tests/ui/async-await/async-closures/captures.rs @@ -79,4 +79,38 @@ async fn async_main() { }; call_once(c).await; } + + fn force_fnonce(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T { + f + } + + // Capture something with `move`, but infer to `AsyncFnOnce` + { + let x = Hello(6); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(7); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + } + + // Capture something by-ref, but infer to `AsyncFnOnce` + { + let x = Hello(8); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(9); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + } } diff --git a/tests/ui/async-await/async-closures/captures.run.stdout b/tests/ui/async-await/async-closures/captures.run.stdout index a0db6d236fef1..42a7999b2dcdd 100644 --- a/tests/ui/async-await/async-closures/captures.run.stdout +++ b/tests/ui/async-await/async-closures/captures.run.stdout @@ -8,3 +8,7 @@ Hello(3) Hello(4) Hello(4) Hello(5) +Hello(6) +Hello(7) +Hello(8) +Hello(9) diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs index 8502bb6e2d45d..3d6f856874f2c 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -2,18 +2,22 @@ #![feature(async_closure)] -fn main() { - fn needs_async_fn(_: impl async Fn()) {} +fn needs_async_fn(_: impl async Fn()) {} +fn a() { let mut x = 1; needs_async_fn(async || { - //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` + //~^ ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure x += 1; }); +} +fn b() { let x = String::new(); needs_async_fn(move || async move { //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce` println!("{x}"); }); } + +fn main() {} diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index d0f1948e48f83..e56389b320273 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -1,26 +1,5 @@ -error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` - --> $DIR/wrong-fn-kind.rs:9:20 - | -LL | needs_async_fn(async || { - | -------------- -^^^^^^^ - | | | - | _____|______________this closure implements `async FnMut`, not `async Fn` - | | | - | | required by a bound introduced by this call -LL | | -LL | | x += 1; - | | - closure is `async FnMut` because it mutates the variable `x` here -LL | | }); - | |_____- the requirement to implement `async Fn` derives from here - | -note: required by a bound in `needs_async_fn` - --> $DIR/wrong-fn-kind.rs:6:31 - | -LL | fn needs_async_fn(_: impl async Fn()) {} - | ^^^^^^^^^^ required by this bound in `needs_async_fn` - error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce` - --> $DIR/wrong-fn-kind.rs:15:20 + --> $DIR/wrong-fn-kind.rs:17:20 | LL | needs_async_fn(move || async move { | -------------- -^^^^^^ @@ -35,11 +14,29 @@ LL | | }); | |_____- the requirement to implement `async Fn` derives from here | note: required by a bound in `needs_async_fn` - --> $DIR/wrong-fn-kind.rs:6:31 + --> $DIR/wrong-fn-kind.rs:5:27 + | +LL | fn needs_async_fn(_: impl async Fn()) {} + | ^^^^^^^^^^ required by this bound in `needs_async_fn` + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-fn-kind.rs:9:29 | -LL | fn needs_async_fn(_: impl async Fn()) {} - | ^^^^^^^^^^ required by this bound in `needs_async_fn` +LL | fn needs_async_fn(_: impl async Fn()) {} + | --------------- change this to accept `FnMut` instead of `Fn` +... +LL | needs_async_fn(async || { + | _____--------------_--------_^ + | | | | + | | | in this closure + | | expects `Fn` instead of `FnMut` +LL | | +LL | | x += 1; + | | - mutable borrow occurs due to use of `x` in closure +LL | | }); + | |_____^ cannot borrow as mutable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0525`. +Some errors have detailed explanations: E0525, E0596. +For more information about an error, try `rustc --explain E0525`. diff --git a/tests/ui/coherence/skip-reporting-if-references-err.current.stderr b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr new file mode 100644 index 0000000000000..5eef3256b2c36 --- /dev/null +++ b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr @@ -0,0 +1,27 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/skip-reporting-if-references-err.rs:10:9 + | +LL | impl ToUnit for T {} + | ^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | impl ToUnit<'_> for T {} + | ++++ + +error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied + --> $DIR/skip-reporting-if-references-err.rs:15:29 + | +LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()` + +error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied + --> $DIR/skip-reporting-if-references-err.rs:15:18 + | +LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0726. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/coherence/skip-reporting-if-references-err.next.stderr b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr new file mode 100644 index 0000000000000..5de4cf626e481 --- /dev/null +++ b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr @@ -0,0 +1,14 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/skip-reporting-if-references-err.rs:10:9 + | +LL | impl ToUnit for T {} + | ^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | impl ToUnit<'_> for T {} + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/coherence/skip-reporting-if-references-err.rs b/tests/ui/coherence/skip-reporting-if-references-err.rs new file mode 100644 index 0000000000000..f9eaa498232da --- /dev/null +++ b/tests/ui/coherence/skip-reporting-if-references-err.rs @@ -0,0 +1,19 @@ +// Regression test for #121006. +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait ToUnit<'a> { + type Unit; +} + +impl ToUnit for T {} +//~^ ERROR implicit elided lifetime not allowed here + +trait Overlap {} +impl Overlap for fn(U) {} +impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} +//[current]~^ ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied +//[current]~| ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs new file mode 100644 index 0000000000000..ed5db56e0e83d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs @@ -0,0 +1,14 @@ +pub fn main() { + if let Some(Some(&x)) = &Some(&Some(0)) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let Some(&Some(x)) = &Some(Some(0)) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } +} diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr new file mode 100644 index 0000000000000..0f0051325cdf0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr @@ -0,0 +1,49 @@ +error[E0308]: mismatched types + --> $DIR/feature-gate-ref_pat_everywhere.rs:2:22 + | +LL | if let Some(Some(&x)) = &Some(&Some(0)) { + | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(Some(x)) = &Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/feature-gate-ref_pat_everywhere.rs:6:17 + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&_` + | + = note: expected enum `Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 + | +LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 + | +LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) { + | ~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs new file mode 100644 index 0000000000000..9dd7a7893ec71 --- /dev/null +++ b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs @@ -0,0 +1,16 @@ +#![allow(incomplete_features)] +#![feature(ref_pat_everywhere)] +pub fn main() { + if let Some(&x) = Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let &Some(x) = &mut Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let Some(&x) = &mut Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } +} diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr new file mode 100644 index 0000000000000..d512ea5f957da --- /dev/null +++ b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr @@ -0,0 +1,44 @@ +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:4:17 + | +LL | if let Some(&x) = Some(0) { + | ^^ ------- this expression has type `Option<{integer}>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(x) = Some(0) { + | ~ + +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:8:12 + | +LL | if let &Some(x) = &mut Some(0) { + | ^^^^^^^^ ------------ this expression has type `&mut Option<{integer}>` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:12:17 + | +LL | if let Some(&x) = &mut Some(0) { + | ^^ ------------ this expression has type `&mut Option<{integer}>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(x) = &mut Some(0) { + | ~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere.rs b/tests/ui/match/ref_pat_everywhere.rs new file mode 100644 index 0000000000000..b3daca484092b --- /dev/null +++ b/tests/ui/match/ref_pat_everywhere.rs @@ -0,0 +1,18 @@ +//@ run-pass +#![allow(incomplete_features)] +#![feature(ref_pat_everywhere)] + +pub fn main() { + if let Some(Some(&x)) = &Some(&Some(0)) { + let _: u32 = x; + } + if let Some(&Some(x)) = &Some(Some(0)) { + let _: u32 = x; + } + if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + let _: u32 = x; + } + if let Some(Some(&x)) = &Some(&mut Some(0)) { + let _: u32 = x; + } +} diff --git a/triagebot.toml b/triagebot.toml index 55f0d32398ff1..3db0f7dc44392 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -469,11 +469,11 @@ message = "Some changes occurred in need_type_info.rs" cc = ["@lcnr"] [mentions."compiler/rustc_middle/src/ty/relate.rs"] -message = "Type relation code was changed" +message = "changes to the core type system" cc = ["@compiler-errors", "@lcnr"] [mentions."compiler/rustc_infer/src/infer/relate"] -message = "Type relation code was changed" +message = "changes to the core type system" cc = ["@compiler-errors", "@lcnr"] [mentions."compiler/rustc_middle/src/mir/interpret"] @@ -484,6 +484,10 @@ cc = ["@rust-lang/miri"] message = "Some changes occurred to MIR optimizations" cc = ["@rust-lang/wg-mir-opt"] +[mentions."compiler/rustc_trait_selection/src/traits/wf.rs"] +message = "changes to the core type system" +cc = ["@compiler-errors", "@lcnr"] + [mentions."compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"] message = "Some changes occurred in `const_evaluatable.rs`" cc = ["@BoxyUwU"]