From 999695bab9779db8b9c6dc5fc2135777562eae47 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 7 Jan 2025 02:26:52 +0000 Subject: [PATCH 01/12] Make sure to use Receiver trait when extracting object method candidate --- .../rustc_hir_typeck/src/method/confirm.rs | 14 ++++++-- ...arbitrary_self_types_dispatch_to_vtable.rs | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 0c93c9817b467..ea06518a6d3d0 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -347,9 +347,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // yield an object-type (e.g., `&Object` or `Box` // etc). - // FIXME: this feels, like, super dubious - self.fcx - .autoderef(self.span, self_ty) + let mut autoderef = self.fcx.autoderef(self.span, self_ty); + + // We don't need to gate this behind arbitrary self types + // per se, but it does make things a bit more gated. + if self.tcx.features().arbitrary_self_types() + || self.tcx.features().arbitrary_self_types_pointers() + { + autoderef = autoderef.use_receiver_trait(); + } + + autoderef .include_raw_pointers() .find_map(|(ty, _)| match ty.kind() { ty::Dynamic(data, ..) => Some(closure( diff --git a/tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs b/tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs new file mode 100644 index 0000000000000..f9e346ea11e21 --- /dev/null +++ b/tests/ui/self/arbitrary_self_types_dispatch_to_vtable.rs @@ -0,0 +1,33 @@ +//@ check-pass + +#![feature(derive_coerce_pointee)] +#![feature(arbitrary_self_types)] + +use std::marker::CoercePointee; +use std::ops::Receiver; + +// `CoercePointee` isn't needed here, it's just a simpler +// (and more conceptual) way of deriving `DispatchFromDyn`. +// You could think of `MyDispatcher` as a smart pointer +// that just doesn't deref to its target type. +#[derive(CoercePointee)] +#[repr(transparent)] +struct MyDispatcher(*const T); + +impl Receiver for MyDispatcher { + type Target = T; +} +struct Test; + +trait Trait { + fn test(self: MyDispatcher); +} + +impl Trait for Test { + fn test(self: MyDispatcher) { + todo!() + } +} +fn main() { + MyDispatcher::(core::ptr::null_mut::()).test(); +} From 6c4cf30009bd0cad81202fbcc2e835bc66b14e74 Mon Sep 17 00:00:00 2001 From: Amy Kwan Date: Tue, 4 Feb 2025 13:57:20 -0500 Subject: [PATCH 02/12] [AIX] Update tests/ui/wait-forked-but-failed-child.rs to accomodate exiting and idle processes. --- tests/ui/wait-forked-but-failed-child.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/wait-forked-but-failed-child.rs index 04f1c1a65d5cb..d756e6515b77d 100644 --- a/tests/ui/wait-forked-but-failed-child.rs +++ b/tests/ui/wait-forked-but-failed-child.rs @@ -31,8 +31,17 @@ fn find_zombies() { // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html let ps_cmd_output = Command::new("ps").args(&["-A", "-o", "pid,ppid,args"]).output().unwrap(); let ps_output = String::from_utf8_lossy(&ps_cmd_output.stdout); + // On AIX, the PPID is not always present, such as when a process is blocked + // (marked as ), or if a process is idle. In these situations, + // the PPID column contains a "-" for the respective process. + // Filter out any lines that have a "-" as the PPID as the PPID is + // expected to be an integer. + let filtered_ps: Vec<_> = ps_output + .lines() + .filter(|line| line.split(' ').filter(|x| 0 < x.len()).nth(1) != Some("-")) + .collect(); - for (line_no, line) in ps_output.split('\n').enumerate() { + for (line_no, line) in filtered_ps.into_iter().enumerate() { if 0 < line_no && 0 < line.len() && my_pid == line.split(' ').filter(|w| 0 < w.len()).nth(1) .expect("1st column should be PPID") From 427c328bdb5a7d242d2c92e168ab75b7a929321a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH 03/12] Add ffi tests for pattern types --- tests/ui/lint/clashing-extern-fn.rs | 41 ++++++++- tests/ui/lint/clashing-extern-fn.stderr | 116 +++++++++++++++++++++++- tests/ui/lint/lint-ctypes-enum.rs | 1 + tests/ui/lint/lint-ctypes-enum.stderr | 49 ++++++---- 4 files changed, 185 insertions(+), 22 deletions(-) diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 9bbb20246df9d..0464299348bdb 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -1,7 +1,7 @@ //@ check-pass //@ aux-build:external_extern_fn.rs #![crate_type = "lib"] - +#![feature(pattern_type_macro, pattern_types)] mod redeclared_different_signature { mod a { extern "C" { @@ -490,3 +490,42 @@ mod hidden_niche { } } } + +mod pattern_types { + mod a { + use std::pat::pattern_type; + #[repr(transparent)] + struct NonZeroUsize(pattern_type!(usize is 1..)); + extern "C" { + fn pt_non_zero_usize() -> pattern_type!(usize is 1..); + //~^ WARN not FFI-safe + fn pt_non_zero_usize_opt() -> Option; + //~^ WARN not FFI-safe + fn pt_non_zero_usize_opt_full_range() -> Option; + //~^ WARN not FFI-safe + fn pt_non_null_ptr() -> pattern_type!(usize is 1..); + //~^ WARN not FFI-safe + fn pt_non_zero_usize_wrapper() -> NonZeroUsize; + //~^ WARN not FFI-safe + fn pt_non_zero_usize_wrapper_opt() -> Option; + //~^ WARN not FFI-safe + } + } + mod b { + extern "C" { + // If there's a clash in either of these cases you're either gaining an incorrect + // invariant that the value is non-zero, or you're missing out on that invariant. Both + // cases are warning for, from both a caller-convenience and optimisation perspective. + fn pt_non_zero_usize() -> usize; + //~^ WARN `pt_non_zero_usize` redeclared with a different signature + fn pt_non_zero_usize_opt() -> usize; + //~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature + fn pt_non_null_ptr() -> *const (); + //~^ WARN `pt_non_null_ptr` redeclared with a different signature + fn pt_non_zero_usize_wrapper() -> usize; + //~^ WARN `pt_non_zero_usize_wrapper` redeclared with a different signature + fn pt_non_zero_usize_wrapper_opt() -> usize; + //~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature + } + } +} diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 48dd1adbc1fa2..acf31a1f5dd46 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -17,6 +17,60 @@ LL | fn hidden_niche_unsafe_cell() -> Option $DIR/clashing-extern-fn.rs:500:39 + | +LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using the base type instead + = note: pattern types have no C equivalent + +warning: `extern` block uses type `Option<(usize) is 1..=>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:502:43 + | +LL | fn pt_non_zero_usize_opt() -> Option; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +warning: `extern` block uses type `Option<(usize) is 0..=>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:504:54 + | +LL | fn pt_non_zero_usize_opt_full_range() -> Option; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +warning: `extern` block uses type `(usize) is 1..=`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:506:37 + | +LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using the base type instead + = note: pattern types have no C equivalent + +warning: `extern` block uses type `(usize) is 1..=`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:508:47 + | +LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; + | ^^^^^^^^^^^^ not FFI-safe + | + = help: consider using the base type instead + = note: pattern types have no C equivalent + +warning: `extern` block uses type `Option`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:510:51 + | +LL | fn pt_non_zero_usize_wrapper_opt() -> Option; + | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + warning: `clash` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:13:13 | @@ -258,5 +312,65 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: 22 warnings emitted +warning: `pt_non_zero_usize` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:519:13 + | +LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); + | ------------------------------------------------------ `pt_non_zero_usize` previously declared here +... +LL | fn pt_non_zero_usize() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` + found `unsafe extern "C" fn() -> usize` + +warning: `pt_non_zero_usize_opt` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:521:13 + | +LL | fn pt_non_zero_usize_opt() -> Option; + | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here +... +LL | fn pt_non_zero_usize_opt() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> Option<(usize) is 1..=>` + found `unsafe extern "C" fn() -> usize` + +warning: `pt_non_null_ptr` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:523:13 + | +LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); + | ---------------------------------------------------- `pt_non_null_ptr` previously declared here +... +LL | fn pt_non_null_ptr() -> *const (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` + found `unsafe extern "C" fn() -> *const ()` + +warning: `pt_non_zero_usize_wrapper` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:525:13 + | +LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; + | ----------------------------------------------- `pt_non_zero_usize_wrapper` previously declared here +... +LL | fn pt_non_zero_usize_wrapper() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> NonZeroUsize` + found `unsafe extern "C" fn() -> usize` + +warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:527:13 + | +LL | fn pt_non_zero_usize_wrapper_opt() -> Option; + | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here +... +LL | fn pt_non_zero_usize_wrapper_opt() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> Option` + found `unsafe extern "C" fn() -> usize` + +warning: 33 warnings emitted diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs index 19af1de95760b..0d19d5b534713 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/lint-ctypes-enum.rs @@ -94,6 +94,7 @@ extern "C" { fn option_transparent_union(x: Option>>); //~^ ERROR `extern` block uses type fn option_repr_rust(x: Option>>); //~ ERROR `extern` block uses type + fn option_u8(x: Option); //~ ERROR `extern` block uses type fn result_ref_t(x: Result<&'static u8, ()>); fn result_fn_t(x: Result); diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 8e92e7e694627..a491bd1960563 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -79,8 +79,17 @@ LL | fn option_repr_rust(x: Option>>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint +error: `extern` block uses type `Option`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:97:21 + | +LL | fn option_u8(x: Option); + | ^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:106:33 + --> $DIR/lint-ctypes-enum.rs:107:33 | LL | fn result_nonzero_u128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -88,7 +97,7 @@ LL | fn result_nonzero_u128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:113:33 + --> $DIR/lint-ctypes-enum.rs:114:33 | LL | fn result_nonzero_i128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -96,7 +105,7 @@ LL | fn result_nonzero_i128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:118:38 + --> $DIR/lint-ctypes-enum.rs:119:38 | LL | fn result_transparent_union_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -105,7 +114,7 @@ LL | fn result_transparent_union_t(x: Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:120:30 + --> $DIR/lint-ctypes-enum.rs:121:30 | LL | fn result_repr_rust_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -114,7 +123,7 @@ LL | fn result_repr_rust_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `Result, U>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:124:51 + --> $DIR/lint-ctypes-enum.rs:125:51 | LL | fn result_1zst_exhaustive_single_variant_t(x: Result, U>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -123,7 +132,7 @@ LL | fn result_1zst_exhaustive_single_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, B>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:126:53 + --> $DIR/lint-ctypes-enum.rs:127:53 | LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result, B>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -132,7 +141,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result = note: enum has no representation hint error: `extern` block uses type `Result, NonExhaustive>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:128:51 + --> $DIR/lint-ctypes-enum.rs:129:51 | LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, NonExhaustive>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -141,7 +150,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, Field>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:131:49 + --> $DIR/lint-ctypes-enum.rs:132:49 | LL | fn result_1zst_exhaustive_single_field_t(x: Result, Field>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -150,7 +159,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result, Fi = note: enum has no representation hint error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:133:30 + --> $DIR/lint-ctypes-enum.rs:134:30 | LL | fn result_cascading_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -159,7 +168,7 @@ LL | fn result_cascading_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:144:33 + --> $DIR/lint-ctypes-enum.rs:145:33 | LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +176,7 @@ LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:151:33 + --> $DIR/lint-ctypes-enum.rs:152:33 | LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -175,7 +184,7 @@ LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:156:38 + --> $DIR/lint-ctypes-enum.rs:157:38 | LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -184,7 +193,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:158:30 + --> $DIR/lint-ctypes-enum.rs:159:30 | LL | fn result_repr_rust_e(x: Result<(), Rust>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -193,7 +202,7 @@ LL | fn result_repr_rust_e(x: Result<(), Rust>>); = note: enum has no representation hint error: `extern` block uses type `Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:162:51 + --> $DIR/lint-ctypes-enum.rs:163:51 | LL | fn result_1zst_exhaustive_single_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -202,7 +211,7 @@ LL | fn result_1zst_exhaustive_single_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:164:53 + --> $DIR/lint-ctypes-enum.rs:165:53 | LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -211,7 +220,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:166:51 + --> $DIR/lint-ctypes-enum.rs:167:51 | LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -220,7 +229,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:169:49 + --> $DIR/lint-ctypes-enum.rs:170:49 | LL | fn result_1zst_exhaustive_single_field_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -229,7 +238,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:171:30 + --> $DIR/lint-ctypes-enum.rs:172:30 | LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -238,7 +247,7 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); = note: enum has no representation hint error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:173:27 + --> $DIR/lint-ctypes-enum.rs:174:27 | LL | fn result_unit_t_e(x: Result<(), ()>); | ^^^^^^^^^^^^^^ not FFI-safe @@ -246,5 +255,5 @@ LL | fn result_unit_t_e(x: Result<(), ()>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors From 032bd6434e2196c7e279c97775a285fa12228fea Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH 04/12] Correctly handle pattern types in FFI safety --- compiler/rustc_lint/messages.ftl | 3 -- compiler/rustc_lint/src/types.rs | 8 ++--- tests/ui/lint/clashing-extern-fn.rs | 3 -- tests/ui/lint/clashing-extern-fn.stderr | 45 +++++-------------------- 4 files changed, 12 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 55c6a122d35d5..480d97e377a40 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -390,9 +390,6 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` lint_improper_ctypes_opaque = opaque types have no C equivalent -lint_improper_ctypes_pat_help = consider using the base type instead - -lint_improper_ctypes_pat_reason = pattern types have no C equivalent lint_improper_ctypes_slice_help = consider using a raw pointer instead lint_improper_ctypes_slice_reason = slices have no C equivalent diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 0060f33888ebd..204db43d05ebd 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1240,11 +1240,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { help: Some(fluent::lint_improper_ctypes_char_help), }, - ty::Pat(..) => FfiUnsafe { - ty, - reason: fluent::lint_improper_ctypes_pat_reason, - help: Some(fluent::lint_improper_ctypes_pat_help), - }, + // It's just extra invariants on the type that you need to uphold, + // but only the base type is relevant for being representable in FFI. + ty::Pat(base, ..) => self.check_type_for_ffi(acc, base), ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 0464299348bdb..012eda761f424 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -498,15 +498,12 @@ mod pattern_types { struct NonZeroUsize(pattern_type!(usize is 1..)); extern "C" { fn pt_non_zero_usize() -> pattern_type!(usize is 1..); - //~^ WARN not FFI-safe fn pt_non_zero_usize_opt() -> Option; //~^ WARN not FFI-safe fn pt_non_zero_usize_opt_full_range() -> Option; //~^ WARN not FFI-safe fn pt_non_null_ptr() -> pattern_type!(usize is 1..); - //~^ WARN not FFI-safe fn pt_non_zero_usize_wrapper() -> NonZeroUsize; - //~^ WARN not FFI-safe fn pt_non_zero_usize_wrapper_opt() -> Option; //~^ WARN not FFI-safe } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index acf31a1f5dd46..16d251c1d7a7b 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -17,17 +17,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option $DIR/clashing-extern-fn.rs:500:39 - | -LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider using the base type instead - = note: pattern types have no C equivalent - warning: `extern` block uses type `Option<(usize) is 1..=>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:502:43 + --> $DIR/clashing-extern-fn.rs:501:43 | LL | fn pt_non_zero_usize_opt() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -36,7 +27,7 @@ LL | fn pt_non_zero_usize_opt() -> Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:504:54 + --> $DIR/clashing-extern-fn.rs:503:54 | LL | fn pt_non_zero_usize_opt_full_range() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -44,26 +35,8 @@ LL | fn pt_non_zero_usize_opt_full_range() -> Option $DIR/clashing-extern-fn.rs:506:37 - | -LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider using the base type instead - = note: pattern types have no C equivalent - -warning: `extern` block uses type `(usize) is 1..=`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:508:47 - | -LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; - | ^^^^^^^^^^^^ not FFI-safe - | - = help: consider using the base type instead - = note: pattern types have no C equivalent - warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:510:51 + --> $DIR/clashing-extern-fn.rs:507:51 | LL | fn pt_non_zero_usize_wrapper_opt() -> Option; | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -313,7 +286,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option Option>>` warning: `pt_non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:519:13 + --> $DIR/clashing-extern-fn.rs:516:13 | LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); | ------------------------------------------------------ `pt_non_zero_usize` previously declared here @@ -325,7 +298,7 @@ LL | fn pt_non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_zero_usize_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:521:13 + --> $DIR/clashing-extern-fn.rs:518:13 | LL | fn pt_non_zero_usize_opt() -> Option; | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here @@ -337,7 +310,7 @@ LL | fn pt_non_zero_usize_opt() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:523:13 + --> $DIR/clashing-extern-fn.rs:520:13 | LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); | ---------------------------------------------------- `pt_non_null_ptr` previously declared here @@ -349,7 +322,7 @@ LL | fn pt_non_null_ptr() -> *const (); found `unsafe extern "C" fn() -> *const ()` warning: `pt_non_zero_usize_wrapper` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:525:13 + --> $DIR/clashing-extern-fn.rs:522:13 | LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; | ----------------------------------------------- `pt_non_zero_usize_wrapper` previously declared here @@ -361,7 +334,7 @@ LL | fn pt_non_zero_usize_wrapper() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:527:13 + --> $DIR/clashing-extern-fn.rs:524:13 | LL | fn pt_non_zero_usize_wrapper_opt() -> Option; | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here @@ -372,5 +345,5 @@ LL | fn pt_non_zero_usize_wrapper_opt() -> usize; = note: expected `unsafe extern "C" fn() -> Option` found `unsafe extern "C" fn() -> usize` -warning: 33 warnings emitted +warning: 30 warnings emitted From c5bc46745e125a508766daaabd96c9bbb40b80a7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH 05/12] Correctly handle pattern types in FFI redeclaration lints --- compiler/rustc_lint/src/foreign_modules.rs | 9 +- compiler/rustc_lint/src/types.rs | 109 +++++++++++---------- tests/ui/lint/clashing-extern-fn.rs | 2 - tests/ui/lint/clashing-extern-fn.stderr | 32 +----- 4 files changed, 64 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 45b188205d228..636779fe9b4cf 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -241,10 +241,7 @@ fn structurally_same_type_impl<'tcx>( if let ty::Adt(def, args) = *ty.kind() { let is_transparent = def.repr().transparent(); let is_non_null = types::nonnull_optimization_guaranteed(tcx, def); - debug!( - "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", - ty, is_transparent, is_non_null - ); + debug!(?ty, is_transparent, is_non_null); if is_transparent && !is_non_null { debug_assert_eq!(def.variants().len(), 1); let v = &def.variant(FIRST_VARIANT); @@ -378,14 +375,14 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. - (Adt(..), _) if is_primitive_or_pointer(b) => { + (Adt(..) | Pat(..), _) if is_primitive_or_pointer(b) => { if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { a_inner == b } else { false } } - (_, Adt(..)) if is_primitive_or_pointer(a) => { + (_, Adt(..) | Pat(..)) if is_primitive_or_pointer(a) => { if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { b_inner == a } else { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 204db43d05ebd..de38cf9a70cb7 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -891,9 +891,8 @@ fn get_nullable_type<'tcx>( }; return get_nullable_type(tcx, typing_env, inner_field_ty); } - ty::Int(ty) => Ty::new_int(tcx, ty), - ty::Uint(ty) => Ty::new_uint(tcx, ty), - ty::RawPtr(ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), + ty::Pat(base, ..) => return get_nullable_type(tcx, typing_env, base), + ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => ty, // As these types are always non-null, the nullable equivalent of // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), @@ -949,63 +948,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>( ckind: CItemKind, ) -> Option> { debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty); - if let ty::Adt(ty_def, args) = ty.kind() { - let field_ty = match &ty_def.variants().raw[..] { - [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { - ([], [field]) | ([field], []) => field.ty(tcx, args), - ([field1], [field2]) => { - let ty1 = field1.ty(tcx, args); - let ty2 = field2.ty(tcx, args); - - if is_niche_optimization_candidate(tcx, typing_env, ty1) { - ty2 - } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { - ty1 - } else { - return None; + match ty.kind() { + ty::Adt(ty_def, args) => { + let field_ty = match &ty_def.variants().raw[..] { + [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { + ([], [field]) | ([field], []) => field.ty(tcx, args), + ([field1], [field2]) => { + let ty1 = field1.ty(tcx, args); + let ty2 = field2.ty(tcx, args); + + if is_niche_optimization_candidate(tcx, typing_env, ty1) { + ty2 + } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { + ty1 + } else { + return None; + } } - } + _ => return None, + }, _ => return None, - }, - _ => return None, - }; + }; - if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { - return None; - } + if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { + return None; + } - // At this point, the field's type is known to be nonnull and the parent enum is Option-like. - // If the computed size for the field and the enum are different, the nonnull optimization isn't - // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); - if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { - bug!("improper_ctypes: Option nonnull optimization not applied?"); - } + // At this point, the field's type is known to be nonnull and the parent enum is Option-like. + // If the computed size for the field and the enum are different, the nonnull optimization isn't + // being applied (and we've got a problem somewhere). + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); + if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { + bug!("improper_ctypes: Option nonnull optimization not applied?"); + } - // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); - if field_ty_layout.is_err() && !field_ty.has_non_region_param() { - bug!("should be able to compute the layout of non-polymorphic type"); - } + // Return the nullable type this Option-like enum can be safely represented with. + let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); + if field_ty_layout.is_err() && !field_ty.has_non_region_param() { + bug!("should be able to compute the layout of non-polymorphic type"); + } - let field_ty_abi = &field_ty_layout.ok()?.backend_repr; - if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { - match field_ty_scalar.valid_range(&tcx) { - WrappingRange { start: 0, end } - if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => - { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start, end } => { - unreachable!("Unhandled start and end range: ({}, {})", start, end) - } - }; + let field_ty_abi = &field_ty_layout.ok()?.backend_repr; + if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { + match field_ty_scalar.valid_range(&tcx) { + WrappingRange { start: 0, end } + if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => + { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start: 1, .. } => { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start, end } => { + unreachable!("Unhandled start and end range: ({}, {})", start, end) + } + }; + } + None } + ty::Pat(base, pat) => match **pat { + ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, *base), + }, + _ => None, } - None } impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 012eda761f424..1d1c07b66b2f2 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -514,13 +514,11 @@ mod pattern_types { // invariant that the value is non-zero, or you're missing out on that invariant. Both // cases are warning for, from both a caller-convenience and optimisation perspective. fn pt_non_zero_usize() -> usize; - //~^ WARN `pt_non_zero_usize` redeclared with a different signature fn pt_non_zero_usize_opt() -> usize; //~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature fn pt_non_null_ptr() -> *const (); //~^ WARN `pt_non_null_ptr` redeclared with a different signature fn pt_non_zero_usize_wrapper() -> usize; - //~^ WARN `pt_non_zero_usize_wrapper` redeclared with a different signature fn pt_non_zero_usize_wrapper_opt() -> usize; //~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 16d251c1d7a7b..a2fc9e7749237 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -285,20 +285,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: `pt_non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:516:13 - | -LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); - | ------------------------------------------------------ `pt_non_zero_usize` previously declared here -... -LL | fn pt_non_zero_usize() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_zero_usize_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:518:13 + --> $DIR/clashing-extern-fn.rs:517:13 | LL | fn pt_non_zero_usize_opt() -> Option; | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here @@ -310,7 +298,7 @@ LL | fn pt_non_zero_usize_opt() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:520:13 + --> $DIR/clashing-extern-fn.rs:519:13 | LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); | ---------------------------------------------------- `pt_non_null_ptr` previously declared here @@ -321,20 +309,8 @@ LL | fn pt_non_null_ptr() -> *const (); = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` found `unsafe extern "C" fn() -> *const ()` -warning: `pt_non_zero_usize_wrapper` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:522:13 - | -LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; - | ----------------------------------------------- `pt_non_zero_usize_wrapper` previously declared here -... -LL | fn pt_non_zero_usize_wrapper() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> NonZeroUsize` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:524:13 + --> $DIR/clashing-extern-fn.rs:522:13 | LL | fn pt_non_zero_usize_wrapper_opt() -> Option; | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here @@ -345,5 +321,5 @@ LL | fn pt_non_zero_usize_wrapper_opt() -> usize; = note: expected `unsafe extern "C" fn() -> Option` found `unsafe extern "C" fn() -> usize` -warning: 30 warnings emitted +warning: 28 warnings emitted From 60ed9db5a612f288ca5e241274c728b449671b30 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 28 Jan 2025 11:08:22 +0000 Subject: [PATCH 06/12] Handle pattern types wrapped in `Option` in FFI checks --- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/types.rs | 31 ++++++++++++++++ tests/ui/lint/clashing-extern-fn.rs | 4 --- tests/ui/lint/clashing-extern-fn.stderr | 48 ++----------------------- 4 files changed, 35 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 83a168c3f4462..c935796460e21 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -33,6 +33,7 @@ #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(trait_upcasting)] +#![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index de38cf9a70cb7..da95037953e1f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -861,6 +861,37 @@ fn ty_is_known_nonnull<'tcx>( .filter_map(|variant| transparent_newtype_field(tcx, variant)) .any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args), mode)) } + ty::Pat(base, pat) => { + ty_is_known_nonnull(tcx, typing_env, *base, mode) + || Option::unwrap_or_default( + try { + match **pat { + ty::PatternKind::Range { start, end, include_end } => { + match (start, end) { + (Some(start), None) => { + start.try_to_value()?.try_to_bits(tcx, typing_env)? > 0 + } + (Some(start), Some(end)) => { + let start = + start.try_to_value()?.try_to_bits(tcx, typing_env)?; + let end = + end.try_to_value()?.try_to_bits(tcx, typing_env)?; + + if include_end { + // This also works for negative numbers, as we just need + // to ensure we aren't wrapping over zero. + start > 0 && end >= start + } else { + start > 0 && end > start + } + } + _ => false, + } + } + } + }, + ) + } _ => false, } } diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 1d1c07b66b2f2..e4477c9620221 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -499,13 +499,11 @@ mod pattern_types { extern "C" { fn pt_non_zero_usize() -> pattern_type!(usize is 1..); fn pt_non_zero_usize_opt() -> Option; - //~^ WARN not FFI-safe fn pt_non_zero_usize_opt_full_range() -> Option; //~^ WARN not FFI-safe fn pt_non_null_ptr() -> pattern_type!(usize is 1..); fn pt_non_zero_usize_wrapper() -> NonZeroUsize; fn pt_non_zero_usize_wrapper_opt() -> Option; - //~^ WARN not FFI-safe } } mod b { @@ -515,12 +513,10 @@ mod pattern_types { // cases are warning for, from both a caller-convenience and optimisation perspective. fn pt_non_zero_usize() -> usize; fn pt_non_zero_usize_opt() -> usize; - //~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature fn pt_non_null_ptr() -> *const (); //~^ WARN `pt_non_null_ptr` redeclared with a different signature fn pt_non_zero_usize_wrapper() -> usize; fn pt_non_zero_usize_wrapper_opt() -> usize; - //~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature } } } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index a2fc9e7749237..118b18b224c05 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -17,17 +17,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:501:43 - | -LL | fn pt_non_zero_usize_opt() -> Option; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - warning: `extern` block uses type `Option<(usize) is 0..=>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:503:54 + --> $DIR/clashing-extern-fn.rs:502:54 | LL | fn pt_non_zero_usize_opt_full_range() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -35,15 +26,6 @@ LL | fn pt_non_zero_usize_opt_full_range() -> Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:507:51 - | -LL | fn pt_non_zero_usize_wrapper_opt() -> Option; - | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - warning: `clash` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:13:13 | @@ -285,20 +267,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: `pt_non_zero_usize_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:517:13 - | -LL | fn pt_non_zero_usize_opt() -> Option; - | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here -... -LL | fn pt_non_zero_usize_opt() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> Option<(usize) is 1..=>` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:519:13 + --> $DIR/clashing-extern-fn.rs:516:13 | LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); | ---------------------------------------------------- `pt_non_null_ptr` previously declared here @@ -309,17 +279,5 @@ LL | fn pt_non_null_ptr() -> *const (); = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` found `unsafe extern "C" fn() -> *const ()` -warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:522:13 - | -LL | fn pt_non_zero_usize_wrapper_opt() -> Option; - | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here -... -LL | fn pt_non_zero_usize_wrapper_opt() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> Option` - found `unsafe extern "C" fn() -> usize` - -warning: 28 warnings emitted +warning: 24 warnings emitted From e58aa2105f3460c2da7aa747e7046a927d5cae7c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Jan 2025 15:01:45 +0100 Subject: [PATCH 07/12] Re-enable "jump to def" feature on rustc docs --- compiler/rustc_interface/src/passes.rs | 4 +++- src/bootstrap/src/core/build_steps/doc.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8a121c5a8655e..ad0762fc22256 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -827,7 +827,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if tcx.sess.opts.unstable_opts.input_stats { rustc_passes::input_stats::print_hir_stats(tcx); } - #[cfg(debug_assertions)] + // When using rustdoc's "jump to def" feature, it enters this code and `check_crate` + // is not defined. So we need to cfg it out. + #[cfg(all(not(doc), debug_assertions))] rustc_passes::hir_id_validator::check_crate(tcx); let sess = tcx.sess; sess.time("misc_checking_1", || { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 0eb4080c053a7..dedcc139ae198 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -830,7 +830,8 @@ impl Step for Rustc { cargo.rustdocflag("--show-type-layout"); // FIXME: `--generate-link-to-definition` tries to resolve cfged out code // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 - // cargo.rustdocflag("--generate-link-to-definition"); + // If there is any bug, please comment out the next line. + cargo.rustdocflag("--generate-link-to-definition"); compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); cargo.arg("-Zskip-rustdoc-fingerprint"); From 46272855a65c9f4adac8184cb107597b44c739ea Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 6 Feb 2025 10:25:40 +0530 Subject: [PATCH 08/12] sys: net: Add UEFI stubs - Just a copy of sys/net/unsupported. - Will make the future net PRs easier to review. Signed-off-by: Ayush Singh --- .../std/src/sys/net/connection/uefi/mod.rs | 369 ++++++++++++++++++ library/std/src/sys/net/mod.rs | 5 + 2 files changed, 374 insertions(+) create mode 100644 library/std/src/sys/net/connection/uefi/mod.rs diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs new file mode 100644 index 0000000000000..87e6106468fdb --- /dev/null +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -0,0 +1,369 @@ +use crate::fmt; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::sys::unsupported; +use crate::time::Duration; + +pub struct TcpStream(!); + +impl TcpStream { + pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn read_timeout(&self) -> io::Result> { + self.0 + } + + pub fn write_timeout(&self) -> io::Result> { + self.0 + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn read(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { + self.0 + } + + pub fn is_read_vectored(&self) -> bool { + self.0 + } + + pub fn write(&self, _: &[u8]) -> io::Result { + self.0 + } + + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { + self.0 + } + + pub fn is_write_vectored(&self) -> bool { + self.0 + } + + pub fn peer_addr(&self) -> io::Result { + self.0 + } + + pub fn socket_addr(&self) -> io::Result { + self.0 + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + self.0 + } + + pub fn duplicate(&self) -> io::Result { + self.0 + } + + pub fn set_linger(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn linger(&self) -> io::Result> { + self.0 + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn nodelay(&self) -> io::Result { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result { + self.0 + } + + pub fn take_error(&self) -> io::Result> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct TcpListener(!); + +impl TcpListener { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + self.0 + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + self.0 + } + + pub fn duplicate(&self) -> io::Result { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result { + self.0 + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn only_v6(&self) -> io::Result { + self.0 + } + + pub fn take_error(&self) -> io::Result> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct UdpSocket(!); + +impl UdpSocket { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn peer_addr(&self) -> io::Result { + self.0 + } + + pub fn socket_addr(&self) -> io::Result { + self.0 + } + + pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0 + } + + pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0 + } + + pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { + self.0 + } + + pub fn duplicate(&self) -> io::Result { + self.0 + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn read_timeout(&self) -> io::Result> { + self.0 + } + + pub fn write_timeout(&self) -> io::Result> { + self.0 + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn broadcast(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn multicast_loop_v4(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn multicast_loop_v6(&self) -> io::Result { + self.0 + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + self.0 + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + self.0 + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + self.0 + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result { + self.0 + } + + pub fn take_error(&self) -> io::Result> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn send(&self, _: &[u8]) -> io::Result { + self.0 + } + + pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct LookupHost(!); + +impl LookupHost { + pub fn port(&self) -> u16 { + self.0 + } +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + self.0 + } +} + +impl TryFrom<&str> for LookupHost { + type Error = io::Error; + + fn try_from(_v: &str) -> io::Result { + unsupported() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(_v: (&'a str, u16)) -> io::Result { + unsupported() + } +} + +#[allow(nonstandard_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + #[allow(dead_code)] + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + #[allow(dead_code)] + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } +} diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs index 5aa197fbc0df3..646679a1cc8b9 100644 --- a/library/std/src/sys/net/mod.rs +++ b/library/std/src/sys/net/mod.rs @@ -25,6 +25,11 @@ cfg_if::cfg_if! { mod xous; pub use xous::*; } + } else if #[cfg(target_os = "uefi")] { + mod connection { + mod uefi; + pub use uefi::*; + } } else { mod connection { mod unsupported; From 9e345fd3ed1dcd598989c8468a3ca95f0eddd345 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 6 Feb 2025 18:49:53 +0800 Subject: [PATCH 09/12] tests(std/net): remove outdated `base_port` calculation This was never modified since `std::net` was originally introduced, when each CI job was running multiple jobs concurrently which caused issues with fighting over the same ports. This is not the case in the current CI infrastructure, so remove this relic. --- library/std/src/net/test.rs | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/library/std/src/net/test.rs b/library/std/src/net/test.rs index d318d457f3569..a5c3983cd89ec 100644 --- a/library/std/src/net/test.rs +++ b/library/std/src/net/test.rs @@ -5,14 +5,15 @@ use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToS use crate::sync::atomic::{AtomicUsize, Ordering}; static PORT: AtomicUsize = AtomicUsize::new(0); +const BASE_PORT: u16 = 19600; pub fn next_test_ip4() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port(); + let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT; SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) } pub fn next_test_ip6() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port(); + let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT; SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), port, 0, 0)) } @@ -30,31 +31,3 @@ pub fn tsa(a: A) -> Result, String> { Err(e) => Err(e.to_string()), } } - -// The bots run multiple builds at the same time, and these builds -// all want to use ports. This function figures out which workspace -// it is running in and assigns a port range based on it. -fn base_port() -> u16 { - let cwd = if cfg!(target_env = "sgx") { - String::from("sgx") - } else { - env::current_dir().unwrap().into_os_string().into_string().unwrap() - }; - let dirs = [ - "32-opt", - "32-nopt", - "musl-64-opt", - "cross-opt", - "64-opt", - "64-nopt", - "64-opt-vg", - "64-debug-opt", - "all-opt", - "snap3", - "dist", - "sgx", - ]; - dirs.iter().enumerate().find(|&(_, dir)| cwd.contains(dir)).map(|p| p.0).unwrap_or(0) as u16 - * 1000 - + 19600 -} From d17a4a7f9ac94ea0901cd6f200ea73833eac6c05 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 5 Feb 2025 18:03:26 +0000 Subject: [PATCH 10/12] Add opt_alias_variances and use it in outlives code --- .../src/type_check/opaque_types.rs | 12 ++++---- .../src/infer/outlives/for_liveness.rs | 10 +++---- .../src/infer/outlives/obligations.rs | 6 ++-- .../rustc_infer/src/infer/outlives/verify.rs | 8 +++--- compiler/rustc_middle/src/ty/context.rs | 8 ++++++ compiler/rustc_middle/src/ty/util.rs | 23 +++++++++++++++ compiler/rustc_type_ir/src/interner.rs | 6 ++++ compiler/rustc_type_ir/src/outlives.rs | 18 +++++------- compiler/rustc_type_ir/src/predicate.rs | 11 ++++++++ compiler/rustc_type_ir/src/relate.rs | 28 +++++-------------- .../precise-capturing/rpitit-outlives-2.rs | 19 +++++++++++++ .../precise-capturing/rpitit-outlives.rs | 18 ++++++++++++ 12 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs create mode 100644 tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs diff --git a/compiler/rustc_borrowck/src/type_check/opaque_types.rs b/compiler/rustc_borrowck/src/type_check/opaque_types.rs index ad4e006c21ae8..17482cc0cbd22 100644 --- a/compiler/rustc_borrowck/src/type_check/opaque_types.rs +++ b/compiler/rustc_borrowck/src/type_check/opaque_types.rs @@ -284,7 +284,7 @@ where return; } - match ty.kind() { + match *ty.kind() { ty::Closure(_, args) => { // Skip lifetime parameters of the enclosing item(s) @@ -316,10 +316,12 @@ where args.as_coroutine().resume_ty().visit_with(self); } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - // Skip lifetime parameters that are not captures. - let variances = self.tcx.variances_of(*def_id); - + ty::Alias(kind, ty::AliasTy { def_id, args, .. }) + if let Some(variances) = self.tcx.opt_alias_variances(kind, def_id) => + { + // Skip lifetime parameters that are not captured, since they do + // not need member constraints registered for them; we'll erase + // them (and hopefully in the future replace them with placeholders). for (v, s) in std::iter::zip(variances, args.iter()) { if *v != ty::Bivariant { s.visit_with(self); diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs index c02ab98b2baeb..379410641fe5b 100644 --- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs +++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs @@ -48,7 +48,7 @@ where return ty.super_visit_with(self); } - match ty.kind() { + match *ty.kind() { // We can prove that an alias is live two ways: // 1. All the components are live. // @@ -95,11 +95,9 @@ where assert!(r.type_flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS)); r.visit_with(self); } else { - // Skip lifetime parameters that are not captures. - let variances = match kind { - ty::Opaque => Some(self.tcx.variances_of(*def_id)), - _ => None, - }; + // Skip lifetime parameters that are not captured, since they do + // not need to be live. + let variances = tcx.opt_alias_variances(kind, def_id); for (idx, s) in args.iter().enumerate() { if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 84e51b18dc5b6..86a47426049a6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -392,13 +392,13 @@ where // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. - let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque; + let kind = alias_ty.kind(self.tcx); if approx_env_bounds.is_empty() && trait_bounds.is_empty() - && (alias_ty.has_infer_regions() || is_opaque) + && (alias_ty.has_infer_regions() || kind == ty::Opaque) { debug!("no declared bounds"); - let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id)); + let opt_variances = self.tcx.opt_alias_variances(kind, alias_ty.def_id); self.args_must_outlive(alias_ty.args, origin, region, opt_variances); return; } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index d68f3639176f9..c14c288c6e4e6 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -102,12 +102,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { #[instrument(level = "debug", skip(self))] pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> { - let alias_ty_as_ty = alias_ty.to_ty(self.tcx); - // Search the env for where clauses like `P: 'a`. let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| { if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() - && ty == alias_ty_as_ty + && let ty::Alias(_, alias_ty_from_bound) = *ty.kind() + && alias_ty_from_bound == alias_ty { // Micro-optimize if this is an exact match (this // occurs often when there are no region variables @@ -127,7 +126,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components); + let kind = alias_ty.kind(self.tcx); + compute_alias_components_recursive(self.tcx, kind, alias_ty, &mut components); self.bound_from_components(&components) }; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c6fc5f98f56f2..82b4fe193f014 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -194,6 +194,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.variances_of(def_id) } + fn opt_alias_variances( + self, + kind: impl Into, + def_id: DefId, + ) -> Option<&'tcx [ty::Variance]> { + self.opt_alias_variances(kind, def_id) + } + fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of(def_id) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 318bd0c7ec020..632a16d6b4b4a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -951,6 +951,29 @@ impl<'tcx> TyCtxt<'tcx> { ty } + + // Computes the variances for an alias (opaque or RPITIT) that represent + // its (un)captured regions. + pub fn opt_alias_variances( + self, + kind: impl Into, + def_id: DefId, + ) -> Option<&'tcx [ty::Variance]> { + match kind.into() { + ty::AliasTermKind::ProjectionTy => { + if self.is_impl_trait_in_trait(def_id) { + Some(self.variances_of(def_id)) + } else { + None + } + } + ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)), + ty::AliasTermKind::InherentTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => None, + } + } } struct OpaqueTypeExpander<'tcx> { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a6c72da0c564a..aae2d2e96b96f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -141,6 +141,12 @@ pub trait Interner: type VariancesOf: Copy + Debug + SliceLike; fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; + fn opt_alias_variances( + self, + kind: impl Into, + def_id: Self::DefId, + ) -> Option; + fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; type AdtDef: AdtDef; diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index c26e211a79402..b09a378d34143 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -148,7 +148,7 @@ impl TypeVisitor for OutlivesCollector<'_, I> { // trait-ref. Therefore, if we see any higher-ranked regions, // we simply fallback to the most restrictive rule, which // requires that `Pi: 'a` for all `i`. - ty::Alias(_, alias_ty) => { + ty::Alias(kind, alias_ty) => { if !alias_ty.has_escaping_bound_vars() { // best case: no escaping regions, so push the // projection and skip the subtree (thus generating no @@ -162,7 +162,7 @@ impl TypeVisitor for OutlivesCollector<'_, I> { // OutlivesProjectionComponents. Continue walking // through and constrain Pi. let mut subcomponents = smallvec![]; - compute_alias_components_recursive(self.cx, ty, &mut subcomponents); + compute_alias_components_recursive(self.cx, kind, alias_ty, &mut subcomponents); self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } @@ -217,21 +217,17 @@ impl TypeVisitor for OutlivesCollector<'_, I> { } } -/// Collect [Component]s for *all* the args of `parent`. +/// Collect [Component]s for *all* the args of `alias_ty`. /// -/// This should not be used to get the components of `parent` itself. +/// This should not be used to get the components of `alias_ty` itself. /// Use [push_outlives_components] instead. pub fn compute_alias_components_recursive( cx: I, - alias_ty: I::Ty, + kind: ty::AliasTyKind, + alias_ty: ty::AliasTy, out: &mut SmallVec<[Component; 4]>, ) { - let ty::Alias(kind, alias_ty) = alias_ty.kind() else { - unreachable!("can only call `compute_alias_components_recursive` on an alias type") - }; - - let opt_variances = - if kind == ty::Opaque { Some(cx.variances_of(alias_ty.def_id)) } else { None }; + let opt_variances = cx.opt_alias_variances(kind, alias_ty.def_id); let mut visitor = OutlivesCollector { cx, out, visited: Default::default() }; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 9a80f97e274d2..f75b292760027 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -469,6 +469,17 @@ impl AliasTermKind { } } +impl From for AliasTermKind { + fn from(value: ty::AliasTyKind) -> Self { + match value { + ty::Projection => AliasTermKind::ProjectionTy, + ty::Opaque => AliasTermKind::OpaqueTy, + ty::Weak => AliasTermKind::WeakTy, + ty::Inherent => AliasTermKind::InherentTy, + } + } +} + /// Represents the unprojected term of a projection goal. /// /// * For a projection, this would be `>::N<...>`. diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 5b696ee5ed400..d065384b58e23 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -236,28 +236,14 @@ impl Relate for ty::AliasTy { ExpectedFound::new(a, b) })) } else { - let args = match a.kind(relation.cx()) { - ty::Opaque => relate_args_with_variances( - relation, - a.def_id, - relation.cx().variances_of(a.def_id), - a.args, - b.args, + let cx = relation.cx(); + let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) { + relate_args_with_variances( + relation, a.def_id, variances, a.args, b.args, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?, - ty::Projection if relation.cx().is_impl_trait_in_trait(a.def_id) => { - relate_args_with_variances( - relation, - a.def_id, - relation.cx().variances_of(a.def_id), - a.args, - b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )? - } - ty::Projection | ty::Weak | ty::Inherent => { - relate_args_invariantly(relation, a.args, b.args)? - } + )? + } else { + relate_args_invariantly(relation, a.args, b.args)? }; Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args)) } diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs new file mode 100644 index 0000000000000..6f7e1a0eaefae --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs @@ -0,0 +1,19 @@ +//@ check-pass + +// Ensure that we skip uncaptured args from RPITITs when comptuing outlives. + +#![feature(precise_capturing_in_traits)] + +struct Invariant(*mut T); + +trait Foo { + fn hello<'s: 's>(&'s self) -> Invariant>; +} + +fn outlives_static(_: impl Sized + 'static) {} + +fn hello<'s, T: Foo + 'static>(x: &'s T) { + outlives_static(x.hello()); +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs new file mode 100644 index 0000000000000..94d81d766f725 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs @@ -0,0 +1,18 @@ +//@ check-pass + +// Ensure that we skip uncaptured args from RPITITs when collecting the regions +// to enforce member constraints in opaque type inference. + +#![feature(precise_capturing_in_traits)] + +struct Invariant(*mut T); + +trait Foo { + fn hello<'s: 's>(&'s self) -> Invariant>; +} + +fn hello<'s, T: Foo>(x: &'s T) -> Invariant { + x.hello() +} + +fn main() {} From bdaf7a8fd7b3c670a6a5c506e065fa032432b401 Mon Sep 17 00:00:00 2001 From: Amy Kwan Date: Thu, 6 Feb 2025 15:05:53 -0500 Subject: [PATCH 11/12] Use split_whitespace() when filtering lines in the ps output --- tests/ui/wait-forked-but-failed-child.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/wait-forked-but-failed-child.rs index d756e6515b77d..4a7f2bee9d954 100644 --- a/tests/ui/wait-forked-but-failed-child.rs +++ b/tests/ui/wait-forked-but-failed-child.rs @@ -38,7 +38,7 @@ fn find_zombies() { // expected to be an integer. let filtered_ps: Vec<_> = ps_output .lines() - .filter(|line| line.split(' ').filter(|x| 0 < x.len()).nth(1) != Some("-")) + .filter(|line| line.split_whitespace().nth(1) != Some("-")) .collect(); for (line_no, line) in filtered_ps.into_iter().enumerate() { From 630727006f99b0773dbb1e7266e8bbc0cee97d40 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 7 Feb 2025 09:45:19 +0000 Subject: [PATCH 12/12] Move two windows process tests to tests/ui --- library/std/src/process/tests.rs | 148 ------------------ tests/ui/process/win-creation-flags.rs | 51 ++++++ .../ui/process/win-proc-thread-attributes.rs | 118 ++++++++++++++ 3 files changed, 169 insertions(+), 148 deletions(-) create mode 100644 tests/ui/process/win-creation-flags.rs create mode 100644 tests/ui/process/win-proc-thread-attributes.rs diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 1323aba38b7cc..9b87259abefc1 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -391,154 +391,6 @@ fn test_interior_nul_in_env_value_is_error() { } } -/// Tests that process creation flags work by debugging a process. -/// Other creation flags make it hard or impossible to detect -/// behavioral changes in the process. -#[test] -#[cfg(windows)] -fn test_creation_flags() { - use crate::os::windows::process::CommandExt; - use crate::sys::c::{BOOL, INFINITE}; - #[repr(C)] - struct DEBUG_EVENT { - pub event_code: u32, - pub process_id: u32, - pub thread_id: u32, - // This is a union in the real struct, but we don't - // need this data for the purposes of this test. - pub _junk: [u8; 164], - } - - extern "system" { - fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: u32) -> BOOL; - fn ContinueDebugEvent(dwProcessId: u32, dwThreadId: u32, dwContinueStatus: u32) -> BOOL; - } - - const DEBUG_PROCESS: u32 = 1; - const EXIT_PROCESS_DEBUG_EVENT: u32 = 5; - const DBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001; - - let mut child = Command::new("cmd") - .creation_flags(DEBUG_PROCESS) - .stdin(Stdio::piped()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn() - .unwrap(); - child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); - let mut events = 0; - let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] }; - loop { - if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { - panic!("WaitForDebugEvent failed!"); - } - events += 1; - - if event.event_code == EXIT_PROCESS_DEBUG_EVENT { - break; - } - - if unsafe { - ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED) - } == 0 - { - panic!("ContinueDebugEvent failed!"); - } - } - assert!(events > 0); -} - -/// Tests proc thread attributes by spawning a process with a custom parent process, -/// then comparing the parent process ID with the expected parent process ID. -#[test] -#[cfg(windows)] -fn test_proc_thread_attributes() { - use crate::mem; - use crate::os::windows::io::AsRawHandle; - use crate::os::windows::process::{CommandExt, ProcThreadAttributeList}; - use crate::sys::c::{BOOL, CloseHandle, HANDLE}; - use crate::sys::cvt; - - #[repr(C)] - #[allow(non_snake_case)] - struct PROCESSENTRY32W { - dwSize: u32, - cntUsage: u32, - th32ProcessID: u32, - th32DefaultHeapID: usize, - th32ModuleID: u32, - cntThreads: u32, - th32ParentProcessID: u32, - pcPriClassBase: i32, - dwFlags: u32, - szExeFile: [u16; 260], - } - - extern "system" { - fn CreateToolhelp32Snapshot(dwflags: u32, th32processid: u32) -> HANDLE; - fn Process32First(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL; - fn Process32Next(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL; - } - - const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000; - const TH32CS_SNAPPROCESS: u32 = 0x00000002; - - struct ProcessDropGuard(crate::process::Child); - - impl Drop for ProcessDropGuard { - fn drop(&mut self) { - let _ = self.0.kill(); - } - } - - let mut parent = Command::new("cmd"); - parent.stdout(Stdio::null()).stderr(Stdio::null()); - - let parent = ProcessDropGuard(parent.spawn().unwrap()); - - let mut child_cmd = Command::new("cmd"); - child_cmd.stdout(Stdio::null()).stderr(Stdio::null()); - - let parent_process_handle = parent.0.as_raw_handle(); - - let mut attribute_list = ProcThreadAttributeList::build() - .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle) - .finish() - .unwrap(); - - let child = ProcessDropGuard(child_cmd.spawn_with_attributes(&mut attribute_list).unwrap()); - - let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; - - let mut process_entry = PROCESSENTRY32W { - dwSize: mem::size_of::() as u32, - cntUsage: 0, - th32ProcessID: 0, - th32DefaultHeapID: 0, - th32ModuleID: 0, - cntThreads: 0, - th32ParentProcessID: 0, - pcPriClassBase: 0, - dwFlags: 0, - szExeFile: [0; 260], - }; - - unsafe { cvt(Process32First(h_snapshot, &mut process_entry as *mut _)) }.unwrap(); - - loop { - if child.0.id() == process_entry.th32ProcessID { - break; - } - unsafe { cvt(Process32Next(h_snapshot, &mut process_entry as *mut _)) }.unwrap(); - } - - unsafe { cvt(CloseHandle(h_snapshot)) }.unwrap(); - - assert_eq!(parent.0.id(), process_entry.th32ParentProcessID); - - drop(child) -} - #[test] fn test_command_implements_send_sync() { fn take_send_sync_type(_: T) {} diff --git a/tests/ui/process/win-creation-flags.rs b/tests/ui/process/win-creation-flags.rs new file mode 100644 index 0000000000000..0c7c6883d68e3 --- /dev/null +++ b/tests/ui/process/win-creation-flags.rs @@ -0,0 +1,51 @@ +// Test that windows `creation_flags` extension to `Command` works. + +//@ run-pass +//@ only-windows +//@ needs-subprocess + +use std::env; +use std::os::windows::process::CommandExt; +use std::process::{Command, exit}; + +fn main() { + if env::args().skip(1).any(|s| s == "--child") { + child(); + } else { + parent(); + } +} + +fn parent() { + let exe = env::current_exe().unwrap(); + + // Use the DETACH_PROCESS to create a subprocess that isn't attached to the console. + // The subprocess's exit status will be 0 if it's detached. + let status = Command::new(&exe) + .arg("--child") + .creation_flags(DETACH_PROCESS) + .spawn() + .unwrap() + .wait() + .unwrap(); + assert_eq!(status.code(), Some(0)); + + // Try without DETACH_PROCESS to ensure this test works. + let status = Command::new(&exe).arg("--child").spawn().unwrap().wait().unwrap(); + assert_eq!(status.code(), Some(1)); +} + +// exits with 1 if the console is attached or 0 otherwise +fn child() { + // Get the attached console's code page. + // This will fail (return 0) if no console is attached. + let has_console = GetConsoleCP() != 0; + exit(has_console as i32); +} + +// Windows API definitions. +const DETACH_PROCESS: u32 = 0x00000008; +#[link(name = "kernel32")] +unsafe extern "system" { + safe fn GetConsoleCP() -> u32; +} diff --git a/tests/ui/process/win-proc-thread-attributes.rs b/tests/ui/process/win-proc-thread-attributes.rs new file mode 100644 index 0000000000000..91bb0b17e9539 --- /dev/null +++ b/tests/ui/process/win-proc-thread-attributes.rs @@ -0,0 +1,118 @@ +// Tests proc thread attributes by spawning a process with a custom parent process, +// then comparing the parent process ID with the expected parent process ID. + +//@ run-pass +//@ only-windows +//@ needs-subprocess +//@ edition: 2021 + +#![feature(windows_process_extensions_raw_attribute)] + +use std::os::windows::io::AsRawHandle; +use std::os::windows::process::{CommandExt, ProcThreadAttributeList}; +use std::process::{Child, Command}; +use std::{env, mem, ptr, thread, time}; + +// Make a best effort to ensure child processes always exit. +struct ProcessDropGuard(Child); +impl Drop for ProcessDropGuard { + fn drop(&mut self) { + let _ = self.0.kill(); + } +} + +fn main() { + if env::args().skip(1).any(|s| s == "--child") { + child(); + } else { + parent(); + } +} + +fn parent() { + let exe = env::current_exe().unwrap(); + + let (fake_parent_id, child_parent_id) = { + // Create a process to be our fake parent process. + let fake_parent = Command::new(&exe).arg("--child").spawn().unwrap(); + let fake_parent = ProcessDropGuard(fake_parent); + let parent_handle = fake_parent.0.as_raw_handle(); + + // Create another process with the parent process set to the fake. + let mut attribute_list = ProcThreadAttributeList::build() + .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_handle) + .finish() + .unwrap(); + let child = + Command::new(&exe).arg("--child").spawn_with_attributes(&mut attribute_list).unwrap(); + let child = ProcessDropGuard(child); + + // Return the fake's process id and the child's parent's id. + (process_info(&fake_parent.0).process_id(), process_info(&child.0).parent_id()) + }; + + assert_eq!(fake_parent_id, child_parent_id); +} + +// A process that stays running until killed. +fn child() { + // Don't wait forever if something goes wrong. + thread::sleep(time::Duration::from_secs(60)); +} + +fn process_info(child: &Child) -> PROCESS_BASIC_INFORMATION { + unsafe { + let mut info: PROCESS_BASIC_INFORMATION = mem::zeroed(); + let result = NtQueryInformationProcess( + child.as_raw_handle(), + ProcessBasicInformation, + ptr::from_mut(&mut info).cast(), + mem::size_of_val(&info).try_into().unwrap(), + ptr::null_mut(), + ); + assert_eq!(result, 0); + info + } +} + +// Windows API +mod winapi { + #![allow(nonstandard_style)] + use std::ffi::c_void; + + pub type HANDLE = *mut c_void; + type NTSTATUS = i32; + type PROCESSINFOCLASS = i32; + + pub const ProcessBasicInformation: i32 = 0; + pub const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000; + #[repr(C)] + pub struct PROCESS_BASIC_INFORMATION { + pub ExitStatus: NTSTATUS, + pub PebBaseAddress: *mut (), + pub AffinityMask: usize, + pub BasePriority: i32, + pub UniqueProcessId: usize, + pub InheritedFromUniqueProcessId: usize, + } + impl PROCESS_BASIC_INFORMATION { + pub fn parent_id(&self) -> usize { + self.InheritedFromUniqueProcessId + } + pub fn process_id(&self) -> usize { + self.UniqueProcessId + } + } + + #[link(name = "ntdll")] + extern "system" { + pub fn NtQueryInformationProcess( + ProcessHandle: HANDLE, + ProcessInformationClass: PROCESSINFOCLASS, + ProcessInformation: *mut c_void, + ProcessInformationLength: u32, + ReturnLength: *mut u32, + ) -> NTSTATUS; + } +} +use winapi::*;