From 44b2e6c07d96112a4c2229638f5e73a3f078136f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 23 Sep 2023 22:51:43 -0400 Subject: [PATCH 01/17] Stabilize target_feature_11 --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 27 +++------ compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 2 - library/core/src/lib.rs | 1 - .../closure-inherit-target-feature.rs | 1 - .../codegen/target-feature-inline-closure.rs | 1 - tests/mir-opt/inline/inline_compatibility.rs | 1 - tests/ui/asm/x86_64/issue-89875.rs | 2 - .../fn-exception-target-features.rs | 9 ++- .../fn-exception-target-features.stderr | 4 +- .../start_lang_item_with_target_feature.rs | 2 +- .../panic-handler-with-target-feature.rs | 1 - .../panic-handler-with-target-feature.stderr | 2 +- .../rfc-2396-target_feature-11/check-pass.rs | 2 - .../closures-inherit-target_feature.rs | 2 - .../feature-gate-target_feature_11.rs | 6 -- .../feature-gate-target_feature_11.stderr | 15 ----- .../rfcs/rfc-2396-target_feature-11/fn-ptr.rs | 2 - .../rfc-2396-target_feature-11/fn-ptr.stderr | 4 +- .../rfc-2396-target_feature-11/fn-traits.rs | 2 - .../fn-traits.stderr | 28 ++++----- .../issue-108645-target-feature-on-main.rs | 2 - ...issue-108645-target-feature-on-main.stderr | 2 +- .../issue-108655-inline-always-closure.rs | 2 - .../rfc-2396-target_feature-11/issue-99876.rs | 2 - .../return-fn-ptr.rs | 2 - .../rfc-2396-target_feature-11/safe-calls.rs | 2 - .../safe-calls.stderr | 24 ++++---- .../rfc-2396-target_feature-11/trait-impl.rs | 2 - .../trait-impl.stderr | 8 +-- tests/ui/simd-abi-checks.rs | 2 +- tests/ui/target-feature/implied-features.rs | 1 - tests/ui/target-feature/invalid-attribute.rs | 17 ++---- .../target-feature/invalid-attribute.stderr | 60 +++++++------------ 34 files changed, 77 insertions(+), 165 deletions(-) delete mode 100644 tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs delete mode 100644 tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a0bc2d4ea48f1..b9e859b5d1a63 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -260,10 +260,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if safe_target_features { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { // The `#[target_feature]` attribute is allowed on - // WebAssembly targets on all functions, including safe - // ones. Other targets require that `#[target_feature]` is - // only applied to unsafe functions (pending the - // `target_feature_11` feature) because on most targets + // WebAssembly targets on all functions. Prior to stabilizing + // the `target_feature_11` feature, `#[target_feature]` was + // only permitted on unsafe functions because on most targets // execution of instructions that are not supported is // considered undefined behavior. For WebAssembly which is a // 100% safe target at execution time it's not possible to @@ -277,17 +276,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // if a target is documenting some wasm-specific code then // it's not spuriously denied. // - // This exception needs to be kept in sync with allowing - // `#[target_feature]` on `main` and `start`. - } else if !tcx.features().target_feature_11() { - feature_err( - &tcx.sess, - sym::target_feature_11, - attr.span, - "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ) - .with_span_label(tcx.def_span(did), "not an `unsafe` function") - .emit(); + // Now that `#[target_feature]` is permitted on safe functions, + // this exception must still exist for allowing the attribute on + // `main`, `start`, and other functions that are not usually + // allowed. } else { check_target_feature_trait_unsafe(tcx, did, attr.span); } @@ -616,10 +608,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // its parent function, which effectively inherits the features anyway. Boxing this closure // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. - if tcx.features().target_feature_11() - && tcx.is_closure_like(did.to_def_id()) - && !codegen_fn_attrs.inline.always() - { + if tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { let owner_id = tcx.parent(did.to_def_id()); if tcx.def_kind(owner_id).has_codegen_attrs() { codegen_fn_attrs diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 217a7aeb2d7f7..400844d51539a 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -389,6 +389,8 @@ declare_features! ( (accepted, struct_variant, "1.0.0", None), /// Allows `#[target_feature(...)]`. (accepted, target_feature, "1.27.0", None), + /// Allows the use of `#[target_feature]` on safe functions. + (accepted, target_feature_11, "CURRENT_RUSTC_VERSION", Some(69098)), /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301)), /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1a216ebf117c6..dccc168547965 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -618,8 +618,6 @@ declare_features! ( (unstable, strict_provenance_lints, "1.61.0", Some(130351)), /// Allows string patterns to dereference values to match them. (unstable, string_deref_patterns, "1.67.0", Some(87121)), - /// Allows the use of `#[target_feature]` on safe functions. - (unstable, target_feature_11, "1.45.0", Some(69098)), /// Allows using `#[thread_local]` on `static` items. (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c18e0405f7293..4216e7e5814e8 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -190,7 +190,6 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(strict_provenance_lints)] -#![feature(target_feature_11)] #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] diff --git a/tests/assembly/closure-inherit-target-feature.rs b/tests/assembly/closure-inherit-target-feature.rs index 4692653d91fc6..b629d8769edf2 100644 --- a/tests/assembly/closure-inherit-target-feature.rs +++ b/tests/assembly/closure-inherit-target-feature.rs @@ -4,7 +4,6 @@ // make sure the feature is not enabled at compile-time //@ compile-flags: -C opt-level=3 -C target-feature=-sse4.1 -C llvm-args=-x86-asm-syntax=intel -#![feature(target_feature_11)] #![crate_type = "rlib"] use std::arch::x86_64::{__m128, _mm_blend_ps}; diff --git a/tests/codegen/target-feature-inline-closure.rs b/tests/codegen/target-feature-inline-closure.rs index d973bd93e3166..73bdbc0e1a841 100644 --- a/tests/codegen/target-feature-inline-closure.rs +++ b/tests/codegen/target-feature-inline-closure.rs @@ -3,7 +3,6 @@ //@ compile-flags: -Copt-level=3 -Ctarget-cpu=x86-64 #![crate_type = "lib"] -#![feature(target_feature_11)] #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; diff --git a/tests/mir-opt/inline/inline_compatibility.rs b/tests/mir-opt/inline/inline_compatibility.rs index 13f28aaacd6a7..1bb102ccda58a 100644 --- a/tests/mir-opt/inline/inline_compatibility.rs +++ b/tests/mir-opt/inline/inline_compatibility.rs @@ -4,7 +4,6 @@ #![crate_type = "lib"] #![feature(no_sanitize)] -#![feature(target_feature_11)] #![feature(c_variadic)] #[inline] diff --git a/tests/ui/asm/x86_64/issue-89875.rs b/tests/ui/asm/x86_64/issue-89875.rs index af940f05fead7..0252859cff0a2 100644 --- a/tests/ui/asm/x86_64/issue-89875.rs +++ b/tests/ui/asm/x86_64/issue-89875.rs @@ -2,8 +2,6 @@ //@ needs-asm-support //@ only-x86_64 -#![feature(target_feature_11)] - use std::arch::asm; #[target_feature(enable = "avx")] diff --git a/tests/ui/async-await/async-closures/fn-exception-target-features.rs b/tests/ui/async-await/async-closures/fn-exception-target-features.rs index 82fc776fd2c72..66cc413977032 100644 --- a/tests/ui/async-await/async-closures/fn-exception-target-features.rs +++ b/tests/ui/async-await/async-closures/fn-exception-target-features.rs @@ -1,14 +1,13 @@ //@ edition: 2021 //@ only-x86_64 -#![feature(target_feature_11)] -// `target_feature_11` just to test safe functions w/ target features. - -use std::pin::Pin; use std::future::Future; +use std::pin::Pin; #[target_feature(enable = "sse2")] -fn target_feature() -> Pin + 'static>> { todo!() } +fn target_feature() -> Pin + 'static>> { + todo!() +} fn test(f: impl AsyncFn()) {} diff --git a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr index 37977b45250ff..f0846bfdb1250 100644 --- a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr +++ b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `#[target_features] fn() -> Pin + 'static)>> {target_feature}: AsyncFn()` is not satisfied - --> $DIR/fn-exception-target-features.rs:16:10 + --> $DIR/fn-exception-target-features.rs:15:10 | LL | test(target_feature); | ---- ^^^^^^^^^^^^^^ unsatisfied trait bound @@ -8,7 +8,7 @@ LL | test(target_feature); | = help: the trait `AsyncFn()` is not implemented for fn item `#[target_features] fn() -> Pin + 'static)>> {target_feature}` note: required by a bound in `test` - --> $DIR/fn-exception-target-features.rs:13:17 + --> $DIR/fn-exception-target-features.rs:12:17 | LL | fn test(f: impl AsyncFn()) {} | ^^^^^^^^^ required by this bound in `test` diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.rs b/tests/ui/lang-items/start_lang_item_with_target_feature.rs index eb712ba409259..18cd4c9704056 100644 --- a/tests/ui/lang-items/start_lang_item_with_target_feature.rs +++ b/tests/ui/lang-items/start_lang_item_with_target_feature.rs @@ -1,7 +1,7 @@ //@ only-x86_64 //@ check-fail -#![feature(lang_items, no_core, target_feature_11)] +#![feature(lang_items, no_core)] #![no_core] #[lang = "copy"] diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.rs b/tests/ui/panic-handler/panic-handler-with-target-feature.rs index 8d5ea0703afa5..aec00c637bedb 100644 --- a/tests/ui/panic-handler/panic-handler-with-target-feature.rs +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.rs @@ -1,7 +1,6 @@ //@ compile-flags:-C panic=abort //@ only-x86_64 -#![feature(target_feature_11)] #![no_std] #![no_main] diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr index cb17da3a4efbe..ddf0ae77a0a1a 100644 --- a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr @@ -1,5 +1,5 @@ error: `#[panic_handler]` function is not allowed to have `#[target_feature]` - --> $DIR/panic-handler-with-target-feature.rs:11:1 + --> $DIR/panic-handler-with-target-feature.rs:10:1 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs index 674cf930c0a6a..9279e7a955ed8 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs @@ -9,8 +9,6 @@ //@ check-pass //@ only-x86_64 -#![feature(target_feature_11)] - #[target_feature(enable = "sse2")] const fn sse2() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs index 122ef542e7d63..aecea6314d412 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs @@ -3,8 +3,6 @@ //@ check-pass //@ only-x86_64 -#![feature(target_feature_11)] - #[target_feature(enable = "avx")] fn also_use_avx() { println!("Hello from AVX") diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs deleted file mode 100644 index 2add6b2e18653..0000000000000 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ only-x86_64 - -#[target_feature(enable = "sse2")] //~ ERROR can only be applied to `unsafe` functions -fn foo() {} - -fn main() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr deleted file mode 100644 index 4f1994d56fd42..0000000000000 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/feature-gate-target_feature_11.rs:3:1 - | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | fn foo() {} - | -------- not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs index d7c17299d061c..43a5a2f16aac1 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs @@ -1,7 +1,5 @@ //@ only-x86_64 -#![feature(target_feature_11)] - #[target_feature(enable = "avx")] fn foo_avx() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr index 1228404120a4c..5bfbc236bc4e3 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/fn-ptr.rs:14:21 + --> $DIR/fn-ptr.rs:12:21 | LL | #[target_feature(enable = "avx")] | --------------------------------- `#[target_feature]` added here @@ -14,7 +14,7 @@ LL | let foo: fn() = foo_avx; = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers error[E0308]: mismatched types - --> $DIR/fn-ptr.rs:23:21 + --> $DIR/fn-ptr.rs:21:21 | LL | #[target_feature(enable = "sse2")] | ---------------------------------- `#[target_feature]` added here diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs index c880ef0fe8a0e..82053a12b133f 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -1,7 +1,5 @@ //@ only-x86_64 -#![feature(target_feature_11)] - #[target_feature(enable = "avx")] fn foo() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index efc061eca5f59..1c6e3905abb11 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -1,5 +1,5 @@ error[E0277]: expected a `Fn()` closure, found `#[target_features] fn() {foo}` - --> $DIR/fn-traits.rs:31:10 + --> $DIR/fn-traits.rs:29:10 | LL | call(foo); | ---- ^^^ expected an `Fn()` closure, found `#[target_features] fn() {foo}` @@ -11,13 +11,13 @@ LL | call(foo); = note: `#[target_feature]` functions do not implement the `Fn` traits = note: try casting the function to a `fn` pointer or wrapping it in a closure note: required by a bound in `call` - --> $DIR/fn-traits.rs:14:17 + --> $DIR/fn-traits.rs:12:17 | LL | fn call(f: impl Fn()) { | ^^^^ required by this bound in `call` error[E0277]: expected a `FnMut()` closure, found `#[target_features] fn() {foo}` - --> $DIR/fn-traits.rs:32:14 + --> $DIR/fn-traits.rs:30:14 | LL | call_mut(foo); | -------- ^^^ expected an `FnMut()` closure, found `#[target_features] fn() {foo}` @@ -29,13 +29,13 @@ LL | call_mut(foo); = note: `#[target_feature]` functions do not implement the `Fn` traits = note: try casting the function to a `fn` pointer or wrapping it in a closure note: required by a bound in `call_mut` - --> $DIR/fn-traits.rs:18:25 + --> $DIR/fn-traits.rs:16:25 | LL | fn call_mut(mut f: impl FnMut()) { | ^^^^^^^ required by this bound in `call_mut` error[E0277]: expected a `FnOnce()` closure, found `#[target_features] fn() {foo}` - --> $DIR/fn-traits.rs:33:15 + --> $DIR/fn-traits.rs:31:15 | LL | call_once(foo); | --------- ^^^ expected an `FnOnce()` closure, found `#[target_features] fn() {foo}` @@ -47,13 +47,13 @@ LL | call_once(foo); = note: `#[target_feature]` functions do not implement the `Fn` traits = note: try casting the function to a `fn` pointer or wrapping it in a closure note: required by a bound in `call_once` - --> $DIR/fn-traits.rs:22:22 + --> $DIR/fn-traits.rs:20:22 | LL | fn call_once(f: impl FnOnce()) { | ^^^^^^^^ required by this bound in `call_once` error[E0277]: expected a `FnOnce(i32)` closure, found `#[target_features] fn(i32) {bar}` - --> $DIR/fn-traits.rs:34:19 + --> $DIR/fn-traits.rs:32:19 | LL | call_once_i32(bar); | ------------- ^^^ expected an `FnOnce(i32)` closure, found `#[target_features] fn(i32) {bar}` @@ -64,13 +64,13 @@ LL | call_once_i32(bar); = note: `#[target_feature]` functions do not implement the `Fn` traits = note: try casting the function to a `fn` pointer or wrapping it in a closure note: required by a bound in `call_once_i32` - --> $DIR/fn-traits.rs:26:26 + --> $DIR/fn-traits.rs:24:26 | LL | fn call_once_i32(f: impl FnOnce(i32)) { | ^^^^^^^^^^^ required by this bound in `call_once_i32` error[E0277]: expected a `Fn()` closure, found `unsafe fn() {foo_unsafe}` - --> $DIR/fn-traits.rs:36:10 + --> $DIR/fn-traits.rs:34:10 | LL | call(foo_unsafe); | ---- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` @@ -83,13 +83,13 @@ LL | call(foo_unsafe); = note: `#[target_feature]` functions do not implement the `Fn` traits = note: try casting the function to a `fn` pointer or wrapping it in a closure note: required by a bound in `call` - --> $DIR/fn-traits.rs:14:17 + --> $DIR/fn-traits.rs:12:17 | LL | fn call(f: impl Fn()) { | ^^^^ required by this bound in `call` error[E0277]: expected a `FnMut()` closure, found `unsafe fn() {foo_unsafe}` - --> $DIR/fn-traits.rs:38:14 + --> $DIR/fn-traits.rs:36:14 | LL | call_mut(foo_unsafe); | -------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` @@ -102,13 +102,13 @@ LL | call_mut(foo_unsafe); = note: `#[target_feature]` functions do not implement the `Fn` traits = note: try casting the function to a `fn` pointer or wrapping it in a closure note: required by a bound in `call_mut` - --> $DIR/fn-traits.rs:18:25 + --> $DIR/fn-traits.rs:16:25 | LL | fn call_mut(mut f: impl FnMut()) { | ^^^^^^^ required by this bound in `call_mut` error[E0277]: expected a `FnOnce()` closure, found `unsafe fn() {foo_unsafe}` - --> $DIR/fn-traits.rs:40:15 + --> $DIR/fn-traits.rs:38:15 | LL | call_once(foo_unsafe); | --------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` @@ -121,7 +121,7 @@ LL | call_once(foo_unsafe); = note: `#[target_feature]` functions do not implement the `Fn` traits = note: try casting the function to a `fn` pointer or wrapping it in a closure note: required by a bound in `call_once` - --> $DIR/fn-traits.rs:22:22 + --> $DIR/fn-traits.rs:20:22 | LL | fn call_once(f: impl FnOnce()) { | ^^^^^^^^ required by this bound in `call_once` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs index a1c118478677b..6df89ee97ddf8 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs @@ -1,7 +1,5 @@ //@ only-x86_64 -#![feature(target_feature_11)] - #[target_feature(enable = "avx2")] fn main() {} //~^ ERROR `main` function is not allowed to have `#[target_feature]` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.stderr index 57ad1cc8d0802..15f99512f1747 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.stderr @@ -1,5 +1,5 @@ error: `main` function is not allowed to have `#[target_feature]` - --> $DIR/issue-108645-target-feature-on-main.rs:6:1 + --> $DIR/issue-108645-target-feature-on-main.rs:4:1 | LL | fn main() {} | ^^^^^^^^^ `main` function is not allowed to have `#[target_feature]` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs index 6bd810b0956d8..bf6dba6702c9e 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs @@ -3,8 +3,6 @@ //@ check-pass //@ only-x86_64 -#![feature(target_feature_11)] - #[target_feature(enable = "avx")] pub unsafe fn test() { ({ diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs index 57dac2e4adb76..141d07876d4ca 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(target_feature_11)] - struct S(T) where [T; (|| {}, 1).1]: Copy; diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/return-fn-ptr.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/return-fn-ptr.rs index b49493d66096d..5b306438fb083 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/return-fn-ptr.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/return-fn-ptr.rs @@ -1,8 +1,6 @@ //@ only-x86_64 //@ run-pass -#![feature(target_feature_11)] - #[target_feature(enable = "sse2")] fn foo() -> bool { true diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index fec4e75290fc8..35bf6c110115e 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -2,8 +2,6 @@ // Set the base cpu explicitly, in case the default has been changed. //@ compile-flags: -C target-cpu=x86-64 -#![feature(target_feature_11)] - #[target_feature(enable = "sse2")] const fn sse2() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr index 901bf640845dd..ea4626092340b 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr @@ -1,5 +1,5 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:27:5 + --> $DIR/safe-calls.rs:25:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -8,7 +8,7 @@ LL | sse2(); = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:27:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -16,7 +16,7 @@ LL | avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:31:5 + --> $DIR/safe-calls.rs:29:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -24,7 +24,7 @@ LL | Quux.avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:38:5 + --> $DIR/safe-calls.rs:36:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -32,7 +32,7 @@ LL | avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:40:5 + --> $DIR/safe-calls.rs:38:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -40,7 +40,7 @@ LL | Quux.avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:47:5 + --> $DIR/safe-calls.rs:45:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -48,7 +48,7 @@ LL | avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:49:5 + --> $DIR/safe-calls.rs:47:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -56,7 +56,7 @@ LL | Quux.avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:61:15 + --> $DIR/safe-calls.rs:59:15 | LL | const _: () = sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -65,7 +65,7 @@ LL | const _: () = sse2(); = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:64:15 + --> $DIR/safe-calls.rs:62:15 | LL | const _: () = sse2_and_fxsr(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -74,7 +74,7 @@ LL | const _: () = sse2_and_fxsr(); = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]` error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block - --> $DIR/safe-calls.rs:69:5 + --> $DIR/safe-calls.rs:67:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -83,12 +83,12 @@ LL | sse2(); = help: in order for the call to be safe, the context requires the following additional target feature: sse2 = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` note: an unsafe function restricts its caller, but its body is safe by default - --> $DIR/safe-calls.rs:68:1 + --> $DIR/safe-calls.rs:66:1 | LL | unsafe fn needs_unsafe_block() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: the lint level is defined here - --> $DIR/safe-calls.rs:67:8 + --> $DIR/safe-calls.rs:65:8 | LL | #[deny(unsafe_op_in_unsafe_fn)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs index a2ac6ff45fccf..bb1dd3b503039 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs @@ -1,7 +1,5 @@ //@ only-x86_64 -#![feature(target_feature_11)] - trait Foo { fn foo(&self); unsafe fn unsf_foo(&self); diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr index 1ab1fad64ccf9..f2ef2b2f3b86b 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr @@ -1,5 +1,5 @@ error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/trait-impl.rs:13:5 + --> $DIR/trait-impl.rs:11:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method @@ -8,13 +8,13 @@ LL | fn foo(&self) {} | ------------- not an `unsafe` function error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/trait-impl.rs:15:5 + --> $DIR/trait-impl.rs:13:5 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait - --> $DIR/trait-impl.rs:6:5 + --> $DIR/trait-impl.rs:4:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | fn foo(&self); found signature `#[target_features] fn(&Bar)` error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/trait-impl.rs:23:5 + --> $DIR/trait-impl.rs:21:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method diff --git a/tests/ui/simd-abi-checks.rs b/tests/ui/simd-abi-checks.rs index c97767b27941e..3a344a1f5f8fb 100644 --- a/tests/ui/simd-abi-checks.rs +++ b/tests/ui/simd-abi-checks.rs @@ -4,7 +4,7 @@ #![feature(avx512_target_feature)] #![feature(portable_simd)] -#![feature(target_feature_11, simd_ffi)] +#![feature(simd_ffi)] #![allow(improper_ctypes_definitions)] use std::arch::x86_64::*; diff --git a/tests/ui/target-feature/implied-features.rs b/tests/ui/target-feature/implied-features.rs index 4fdd843e6c289..d0b5dd3c3fb99 100644 --- a/tests/ui/target-feature/implied-features.rs +++ b/tests/ui/target-feature/implied-features.rs @@ -1,6 +1,5 @@ //@ only-x86_64 //@ build-pass -#![feature(target_feature_11)] #![allow(dead_code)] #[target_feature(enable = "ssse3")] diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index c0f5b6b2fb292..9ef7a686d253d 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -28,13 +28,6 @@ extern "Rust" {} //~^ ERROR malformed `target_feature` attribute unsafe fn foo() {} -#[target_feature(enable = "sse2")] -//~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions -//~| NOTE see issue #69098 -//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -fn bar() {} -//~^ NOTE not an `unsafe` function - #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function mod another {} @@ -58,7 +51,7 @@ enum Bar {} #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function union Qux { -//~^ NOTE not a function + //~^ NOTE not a function f1: u16, f2: u16, } @@ -102,9 +95,8 @@ trait Quux { impl Quux for Foo { #[target_feature(enable = "sse2")] - //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions - //~| NOTE see issue #69098 - //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + //~^ ERROR `#[target_feature(..)]` cannot be applied to safe trait method + //~| NOTE cannot be applied to safe trait method fn foo() {} //~^ NOTE not an `unsafe` function //~| ERROR: incompatible type for trait @@ -117,9 +109,8 @@ fn main() { //~^ ERROR attribute should be applied to a function unsafe { foo(); - bar(); } - //~^^^^ NOTE not a function + //~^^^ NOTE not a function #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index 10fcf65bb9a83..dc8a53041640e 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -32,7 +32,7 @@ LL | extern "Rust" {} | ---------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:38:1 + --> $DIR/invalid-attribute.rs:31:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | mod another {} | -------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:43:1 + --> $DIR/invalid-attribute.rs:36:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | const FOO: usize = 7; | --------------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:48:1 + --> $DIR/invalid-attribute.rs:41:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | struct Foo; | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:53:1 + --> $DIR/invalid-attribute.rs:46:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | enum Bar {} | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:58:1 + --> $DIR/invalid-attribute.rs:51:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:66:1 + --> $DIR/invalid-attribute.rs:59:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | type Uwu = (); | -------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:71:1 + --> $DIR/invalid-attribute.rs:64:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | trait Baz {} | ------------ not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:81:1 + --> $DIR/invalid-attribute.rs:74:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | static A: () = (); | ------------------ not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:86:1 + --> $DIR/invalid-attribute.rs:79:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | impl Quux for u8 {} | ------------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:93:1 + --> $DIR/invalid-attribute.rs:86:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -126,19 +126,18 @@ LL | impl Foo {} | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:116:5 + --> $DIR/invalid-attribute.rs:108:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / unsafe { LL | | foo(); -LL | | bar(); LL | | } | |_____- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:124:5 + --> $DIR/invalid-attribute.rs:115:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,27 +163,14 @@ error: malformed `target_feature` attribute input LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:31:1 - | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn bar() {} - | -------- not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:76:1 + --> $DIR/invalid-attribute.rs:69:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/invalid-attribute.rs:88:1 + --> $DIR/invalid-attribute.rs:81:1 | LL | impl Quux for u8 {} | ^^^^^^^^^^^^^^^^ missing `foo` in implementation @@ -192,34 +178,30 @@ LL | impl Quux for u8 {} LL | fn foo(); | --------- `foo` from trait -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:104:5 +error: `#[target_feature(..)]` cannot be applied to safe trait method + --> $DIR/invalid-attribute.rs:97:5 | LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method ... LL | fn foo() {} | -------- not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/invalid-attribute.rs:108:5 + --> $DIR/invalid-attribute.rs:100:5 | LL | fn foo() {} | ^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait - --> $DIR/invalid-attribute.rs:99:5 + --> $DIR/invalid-attribute.rs:92:5 | LL | fn foo(); | ^^^^^^^^^ = note: expected signature `fn()` found signature `#[target_features] fn()` -error: aborting due to 24 previous errors +error: aborting due to 23 previous errors -Some errors have detailed explanations: E0046, E0053, E0658. +Some errors have detailed explanations: E0046, E0053. For more information about an error, try `rustc --explain E0046`. From 93465e6c3106043b8db7089ff7a1a4d610d8f79f Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 29 Jan 2025 06:46:05 +0900 Subject: [PATCH 02/17] Mark condition/carry bit as clobbered in C-SKY inline assembly --- compiler/rustc_codegen_llvm/src/asm.rs | 4 +++- .../asm-experimental-arch.md | 2 ++ tests/codegen/asm/csky-clobbers.rs | 24 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/codegen/asm/csky-clobbers.rs diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 3722d4350a291..be5673eddf93e 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -286,7 +286,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { InlineAsmArch::M68k => { constraints.push("~{ccr}".to_string()); } - InlineAsmArch::CSKY => {} + InlineAsmArch::CSKY => { + constraints.push("~{psr}".to_string()); + } } } if !options.contains(InlineAsmOptions::NOMEM) { diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index c2f4170d7d295..d9566c9f55c5c 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -199,3 +199,5 @@ These flags registers must be restored upon exiting the asm block if the `preser - SPARC - Integer condition codes (`icc` and `xcc`) - Floating-point condition codes (`fcc[0-3]`) +- CSKY + - Condition/carry bit (C) in `PSR`. diff --git a/tests/codegen/asm/csky-clobbers.rs b/tests/codegen/asm/csky-clobbers.rs new file mode 100644 index 0000000000000..4986d0fe56dfe --- /dev/null +++ b/tests/codegen/asm/csky-clobbers.rs @@ -0,0 +1,24 @@ +//@ add-core-stubs +//@ compile-flags: --target csky-unknown-linux-gnuabiv2 +//@ needs-llvm-components: csky + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @flags_clobber +// CHECK: call void asm sideeffect "", "~{psr}"() +#[no_mangle] +pub unsafe fn flags_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} From 415c228f26a144a9f190199cff8fe654e5770530 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Feb 2025 20:08:09 +0000 Subject: [PATCH 03/17] Use core stubs in some CMSE tests --- .../cmse-nonsecure-call/return-via-stack.rs | 10 +++++----- .../cmse-nonsecure-entry/return-via-stack.rs | 11 +++++------ .../return-via-stack.stderr | 18 +++++++++--------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs index e6af1d60e773f..b052aabb499e7 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -1,12 +1,12 @@ //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ add-core-stubs + #![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)] #![no_core] -#[lang = "sized"] -pub trait Sized {} -#[lang = "copy"] -pub trait Copy {} -impl Copy for u32 {} + +extern crate minicore; +use minicore::*; #[repr(C)] pub struct ReprCU64(u64); diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs index 5746d14f9b1a4..23d55526e5781 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs @@ -1,13 +1,12 @@ //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm +//@ add-core-stubs + #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] -#[lang = "sized"] -pub trait Sized {} -#[lang = "copy"] -pub trait Copy {} -impl Copy for u32 {} -impl Copy for u8 {} + +extern crate minicore; +use minicore::*; #[repr(C)] pub struct ReprCU64(u64); diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr index 9c885d9531814..d37d9b5e8ff7d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr @@ -1,5 +1,5 @@ error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:25:48 + --> $DIR/return-via-stack.rs:24:48 | LL | pub extern "C-cmse-nonsecure-entry" fn f1() -> ReprCU64 { | ^^^^^^^^ this type doesn't fit in the available registers @@ -8,7 +8,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn f1() -> ReprCU64 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:30:48 + --> $DIR/return-via-stack.rs:29:48 | LL | pub extern "C-cmse-nonsecure-entry" fn f2() -> ReprCBytes { | ^^^^^^^^^^ this type doesn't fit in the available registers @@ -17,7 +17,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn f2() -> ReprCBytes { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:35:48 + --> $DIR/return-via-stack.rs:34:48 | LL | pub extern "C-cmse-nonsecure-entry" fn f3() -> U64Compound { | ^^^^^^^^^^^ this type doesn't fit in the available registers @@ -26,7 +26,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn f3() -> U64Compound { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:40:48 + --> $DIR/return-via-stack.rs:39:48 | LL | pub extern "C-cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { | ^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -35,7 +35,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:47:48 + --> $DIR/return-via-stack.rs:46:48 | LL | pub extern "C-cmse-nonsecure-entry" fn f5() -> [u8; 5] { | ^^^^^^^ this type doesn't fit in the available registers @@ -44,7 +44,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn f5() -> [u8; 5] { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:53:50 + --> $DIR/return-via-stack.rs:52:50 | LL | pub extern "C-cmse-nonsecure-entry" fn u128() -> u128 { | ^^^^ this type doesn't fit in the available registers @@ -53,7 +53,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn u128() -> u128 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:59:50 + --> $DIR/return-via-stack.rs:58:50 | LL | pub extern "C-cmse-nonsecure-entry" fn i128() -> i128 { | ^^^^ this type doesn't fit in the available registers @@ -62,7 +62,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn i128() -> i128 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:76:56 + --> $DIR/return-via-stack.rs:75:56 | LL | pub extern "C-cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -71,7 +71,7 @@ LL | pub extern "C-cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:81:53 + --> $DIR/return-via-stack.rs:80:53 | LL | pub extern "C-cmse-nonsecure-entry" fn union_c() -> ReprCUnionU64 { | ^^^^^^^^^^^^^ this type doesn't fit in the available registers From 8e203fb0d8da39b39c1367c953e84799c1705a98 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Feb 2025 20:08:29 +0000 Subject: [PATCH 04/17] Implement and use BikeshedGuaranteedNoDrop for union/unsafe field validity --- .../example/mini_core.rs | 3 + .../rustc_codegen_gcc/example/mini_core.rs | 3 + compiler/rustc_hir/src/lang_items.rs | 1 + .../rustc_hir_analysis/src/check/check.rs | 116 ++++++++---------- compiler/rustc_middle/src/traits/select.rs | 2 + compiler/rustc_middle/src/ty/adt.rs | 4 + compiler/rustc_middle/src/ty/context.rs | 1 + .../src/solve/assembly/mod.rs | 8 ++ .../src/solve/effect_goals.rs | 7 ++ .../src/solve/normalizes_to/mod.rs | 7 ++ .../src/solve/trait_goals.rs | 95 ++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/select/candidate_assembly.rs | 49 ++++++++ .../src/traits/select/confirmation.rs | 90 ++++++++++++++ .../src/traits/select/mod.rs | 3 +- compiler/rustc_type_ir/src/inherent.rs | 2 + compiler/rustc_type_ir/src/lang_items.rs | 1 + library/core/src/marker.rs | 17 +++ tests/auxiliary/minicore.rs | 3 + .../layout/malformed-unsized-type-in-union.rs | 1 + .../malformed-unsized-type-in-union.stderr | 17 ++- 21 files changed, 364 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index a0a381638c061..79820232496a5 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -57,6 +57,9 @@ impl LegacyReceiver for Box {} #[lang = "copy"] pub trait Copy {} +#[lang = "bikeshed_guaranteed_no_drop"] +pub trait BikeshedGuaranteedNoDrop {} + impl Copy for bool {} impl Copy for u8 {} impl Copy for u16 {} diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 5a4ee0a198cef..2ff1d757fd4e0 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -54,6 +54,9 @@ impl LegacyReceiver for Box {} #[lang = "copy"] pub trait Copy {} +#[lang = "bikeshed_guaranteed_no_drop"] +pub trait BikeshedGuaranteedNoDrop {} + impl Copy for bool {} impl Copy for u8 {} impl Copy for u16 {} diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b6689c95c4bb2..207bcd9bd0911 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -351,6 +351,7 @@ language_item_table! { PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1); ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct, GenericRequirement::None; + BikeshedGuaranteedNoDrop, sym::bikeshed_guaranteed_no_drop, bikeshed_guaranteed_no_drop, Target::Trait, GenericRequirement::Exact(0); MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 9ed56d7bde51e..71a10ad3a0c10 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; use rustc_hir::def::{CtorKind, DefKind}; -use rustc_hir::{Node, intravisit}; +use rustc_hir::{LangItem, Node, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ @@ -27,6 +27,7 @@ use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_type_ir::fold::TypeFoldable; use tracing::{debug, instrument}; use ty::TypingMode; @@ -87,89 +88,76 @@ fn allowed_union_or_unsafe_field<'tcx>( typing_env: ty::TypingEnv<'tcx>, span: Span, ) -> bool { - // We don't just accept all !needs_drop fields, due to semver concerns. - let allowed = match ty.kind() { - ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) - ty::Tuple(tys) => { - // allow tuples of allowed types - tys.iter().all(|ty| allowed_union_or_unsafe_field(tcx, ty, typing_env, span)) - } - ty::Array(elem, _len) => { - // Like `Copy`, we do *not* special-case length 0. - allowed_union_or_unsafe_field(tcx, *elem, typing_env, span) - } - _ => { - // Fallback case: allow `ManuallyDrop` and things that are `Copy`, - // also no need to report an error if the type is unresolved. - ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) - || tcx.type_is_copy_modulo_regions(typing_env, ty) - || ty.references_error() - } - }; - if allowed && ty.needs_drop(tcx, typing_env) { - // This should never happen. But we can get here e.g. in case of name resolution errors. - tcx.dcx() - .span_delayed_bug(span, "we should never accept maybe-dropping union or unsafe fields"); + // HACK (not that bad of a hack don't worry): Some codegen tests don't even define proper + // impls for `Copy`. Let's short-circuit here for this validity check, since a lot of them + // use unions. We should eventually fix all the tests to define that lang item or use + // minicore stubs. + if ty.is_trivially_pure_clone_copy() { + return true; } - allowed + // If `BikeshedGuaranteedNoDrop` is not defined in a `#[no_core]` test, fall back to `Copy`. + // This is an underapproximation of `BikeshedGuaranteedNoDrop`, + let def_id = tcx + .lang_items() + .get(LangItem::BikeshedGuaranteedNoDrop) + .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, Some(span))); + let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else { + tcx.dcx().span_delayed_bug(span, "could not normalize field type"); + return true; + }; + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + infcx.predicate_must_hold_modulo_regions(&Obligation::new( + tcx, + ObligationCause::dummy_with_span(span), + param_env, + ty::TraitRef::new(tcx, def_id, [ty]), + )) } /// Check that the fields of the `union` do not need dropping. fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { - let item_type = tcx.type_of(item_def_id).instantiate_identity(); - if let ty::Adt(def, args) = item_type.kind() { - assert!(def.is_union()); - - let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); - for field in &def.non_enum_variant().fields { - let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) - else { - tcx.dcx().span_delayed_bug(span, "could not normalize field type"); - continue; - }; + let def = tcx.adt_def(item_def_id); + assert!(def.is_union()); - if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) { - let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { - // We are currently checking the type this field came from, so it must be local. - Some(Node::Field(field)) => (field.span, field.ty.span), - _ => unreachable!("mir field has to correspond to hir field"), - }; - tcx.dcx().emit_err(errors::InvalidUnionField { - field_span, - sugg: errors::InvalidUnionFieldSuggestion { - lo: ty_span.shrink_to_lo(), - hi: ty_span.shrink_to_hi(), - }, - note: (), - }); - return false; - } + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); + let args = ty::GenericArgs::identity_for_item(tcx, item_def_id); + + for field in &def.non_enum_variant().fields { + if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) { + let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { + // We are currently checking the type this field came from, so it must be local. + Some(Node::Field(field)) => (field.span, field.ty.span), + _ => unreachable!("mir field has to correspond to hir field"), + }; + tcx.dcx().emit_err(errors::InvalidUnionField { + field_span, + sugg: errors::InvalidUnionFieldSuggestion { + lo: ty_span.shrink_to_lo(), + hi: ty_span.shrink_to_hi(), + }, + note: (), + }); + return false; } - } else { - span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind()); } + true } /// Check that the unsafe fields do not need dropping. fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) { let span = tcx.def_span(item_def_id); - let item_type = tcx.type_of(item_def_id).instantiate_identity(); - let ty::Adt(def, args) = item_type.kind() else { - span_bug!(span, "structs/enums must be ty::Adt, but got {:?}", item_type.kind()); - }; + let def = tcx.adt_def(item_def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); + let args = ty::GenericArgs::identity_for_item(tcx, item_def_id); + for field in def.all_fields() { if !field.safety.is_unsafe() { continue; } - let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) - else { - tcx.dcx().span_delayed_bug(span, "could not normalize field type"); - continue; - }; - if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) { + if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) { let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.expect_local()) else { unreachable!("field has to correspond to hir field") }; diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index b7cd545d02db4..811bd8fb4588a 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -168,6 +168,8 @@ pub enum SelectionCandidate<'tcx> { BuiltinObjectCandidate, BuiltinUnsizeCandidate, + + BikeshedGuaranteedNoDropCandidate, } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index e28fcc555dcd1..b529d17540a82 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -217,6 +217,10 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { self.is_phantom_data() } + fn is_manually_drop(self) -> bool { + self.is_manually_drop() + } + fn all_field_tys( self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c6fc5f98f56f2..43106e9058f65 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -682,6 +682,7 @@ bidirectional_lang_item_map! { AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, + BikeshedGuaranteedNoDrop, CallOnceFuture, CallRefFuture, Clone, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index d0b01b14d6358..a3274fb401156 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -267,6 +267,11 @@ where goal: Goal, ) -> Result, NoSolution>; + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution>; + /// Consider (possibly several) candidates to upcast or unsize a type to another /// type, excluding the coercion of a sized type into a `dyn Trait`. /// @@ -478,6 +483,9 @@ where Some(TraitSolverLangItem::TransmuteTrait) => { G::consider_builtin_transmute_candidate(self, goal) } + Some(TraitSolverLangItem::BikeshedGuaranteedNoDrop) => { + G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal) + } _ => Err(NoSolution), } }; diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 7669a305d58d1..050a25b0c4427 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -373,6 +373,13 @@ where unreachable!("TransmuteFrom is not const") } + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("BikeshedGuaranteedNoDrop is not const"); + } + fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 76cbe5758b23a..04bf5a33f9ea4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -930,6 +930,13 @@ where ) -> Result, NoSolution> { panic!("`TransmuteFrom` does not have an associated type: {:?}", goal) } + + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + _ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution> { + unreachable!("`BikeshedGuaranteedNoDrop` does not have an associated type: {:?}", goal) + } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 513fc9355c8b5..a95c6c8e63ca1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -622,6 +622,101 @@ where }) } + /// NOTE: This is implemented as a built-in goal and not a set of impls like: + /// + /// ``` + /// impl BikeshedGuaranteedNoDrop for T where T: Copy {} + /// impl BikeshedGuaranteedNoDrop for ManuallyDrop {} + /// ``` + /// + /// because these impls overlap, and I'd rather not build a coherence hack for + /// this harmless overlap. + fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + ) -> Result, NoSolution> { + if goal.predicate.polarity != ty::PredicatePolarity::Positive { + return Err(NoSolution); + } + + let cx = ecx.cx(); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let ty = goal.predicate.self_ty(); + match ty.kind() { + // `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`. + ty::Ref(..) => {} + // `ManuallyDrop` always implements `BikeshedGuaranteedNoDrop`. + ty::Adt(def, _) if def.is_manually_drop() => {} + // Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if + // their constituent types implement `BikeshedGuaranteedNoDrop`. + ty::Tuple(tys) => { + ecx.add_goals( + GoalSource::ImplWhereBound, + tys.iter().map(|elem_ty| { + goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])) + }), + ); + } + ty::Array(elem_ty, _) => { + ecx.add_goal( + GoalSource::ImplWhereBound, + goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])), + ); + } + + // All other types implement `BikeshedGuaranteedNoDrop` only if + // they implement `Copy`. We could be smart here and short-circuit + // some trivially `Copy`/`!Copy` types, but there's no benefit. + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Adt(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) => { + ecx.add_goal( + GoalSource::ImplWhereBound, + goal.with( + cx, + ty::TraitRef::new( + cx, + cx.require_lang_item(TraitSolverLangItem::Copy), + [ty], + ), + ), + ); + } + + ty::Bound(..) + | ty::Infer( + ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), + ) => { + panic!("unexpected type `{ty:?}`") + } + } + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + /// ```ignore (builtin impl example) /// trait Trait { /// fn foo(&self); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c819d43323583..90300503bcea2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -514,6 +514,7 @@ symbols! { bang, begin_panic, bench, + bikeshed_guaranteed_no_drop, bin, binaryheap_iter, bind_by_move_pattern_guards, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 13a6744c2e9b5..8f60bf4c06a6a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -106,6 +106,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidate_for_tuple(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); + } else if tcx.is_lang_item(def_id, LangItem::BikeshedGuaranteedNoDrop) { + self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + obligation, + &mut candidates, + ); } else { if tcx.is_lang_item(def_id, LangItem::Clone) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -1244,4 +1249,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match obligation.predicate.self_ty().skip_binder().kind() { + ty::Ref(..) + | ty::Adt(..) + | ty::Tuple(_) + | ty::Array(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) + | ty::Bound(..) => { + candidates.vec.push(BikeshedGuaranteedNoDropCandidate); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + candidates.ambiguous = true; + } + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 729ae3f2c2a26..d1f11776418ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_type_ir::elaborate; +use thin_vec::thin_vec; use tracing::{debug, instrument}; use super::SelectionCandidate::{self, *}; @@ -130,6 +131,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitUpcastingUnsizeCandidate(idx) => { self.confirm_trait_upcasting_unsize_candidate(obligation, idx)? } + + BikeshedGuaranteedNoDropCandidate => { + self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation) + } }; // The obligations returned by confirmation are recursively evaluated @@ -1336,6 +1341,91 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("source: {source}, target: {target}"), }) } + + fn confirm_bikeshed_guaranteed_no_drop_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> ImplSource<'tcx, PredicateObligation<'tcx>> { + let mut obligations = thin_vec![]; + + let tcx = self.tcx(); + let self_ty = obligation.predicate.self_ty(); + match *self_ty.skip_binder().kind() { + // `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`. + ty::Ref(..) => {} + // `ManuallyDrop` always implements `BikeshedGuaranteedNoDrop`. + ty::Adt(def, _) if def.is_manually_drop() => {} + // Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if + // their constituent types implement `BikeshedGuaranteedNoDrop`. + ty::Tuple(tys) => { + obligations.extend(tys.iter().map(|elem_ty| { + obligation.with( + tcx, + self_ty.rebind(ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ + elem_ty, + ])), + ) + })); + } + ty::Array(elem_ty, _) => { + obligations.push( + obligation.with( + tcx, + self_ty.rebind(ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ + elem_ty, + ])), + ), + ); + } + + // All other types implement `BikeshedGuaranteedNoDrop` only if + // they implement `Copy`. We could be smart here and short-circuit + // some trivially `Copy`/`!Copy` types, but there's no benefit. + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Adt(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) + | ty::Bound(..) => { + obligations.push(obligation.with( + tcx, + self_ty.map_bound(|ty| { + ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)), + [ty], + ) + }), + )); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } + + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) + } } /// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 99ce1fd9fb480..a172322423434 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1949,7 +1949,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitAliasCandidate | TraitUpcastingUnsizeCandidate(_) | BuiltinObjectCandidate - | BuiltinUnsizeCandidate => false, + | BuiltinUnsizeCandidate + | BikeshedGuaranteedNoDropCandidate => false, // Non-global param candidates have already been handled, global // where-bounds get ignored. ParamCandidate(_) | ImplCandidate(_) => true, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 4e6d645e6fae2..6924216bd26e6 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -540,6 +540,8 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { fn is_phantom_data(self) -> bool; + fn is_manually_drop(self) -> bool; + // FIXME: perhaps use `all_fields` and expose `FieldDef`. fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index eeb80bc3ab420..65f7cdf8f922b 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -10,6 +10,7 @@ pub enum TraitSolverLangItem { AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, + BikeshedGuaranteedNoDrop, CallOnceFuture, CallRefFuture, Clone, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1a8ef20dd7b9d..a7fd860b9bfbb 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -453,6 +453,23 @@ impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] impl Copy for &T {} +/// Marker trait for the types that are allowed in union fields, unsafe fields, +/// and unsafe binder types. +/// +/// Implemented for: +/// * `&T`, `&mut T` for all `T`, +/// * `ManuallyDrop` for all `T`, +/// * tuples and arrays whose elements implement `BikeshedGuaranteedNoDrop`, +/// * or otherwise, all types that are `Copy`. +/// +/// Notably, this doesn't include all trivially-destructible types for semver +/// reasons. +/// +/// Bikeshed name for now. +#[unstable(feature = "bikeshed_guaranteed_no_drop", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "bikeshed_guaranteed_no_drop")] +pub trait BikeshedGuaranteedNoDrop {} + /// Types for which it is safe to share references between threads. /// /// This trait is automatically implemented when the compiler determines diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index a68552175c318..1c5f9eeba3c49 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -39,6 +39,9 @@ impl LegacyReceiver for &mut T {} #[lang = "copy"] pub trait Copy: Sized {} +#[lang = "bikeshed_guaranteed_no_drop"] +pub trait BikeshedGuaranteedNoDrop {} + impl_marker_trait!( Copy => [ bool, char, diff --git a/tests/ui/layout/malformed-unsized-type-in-union.rs b/tests/ui/layout/malformed-unsized-type-in-union.rs index 5d8ec576cf01b..e97024ce9d704 100644 --- a/tests/ui/layout/malformed-unsized-type-in-union.rs +++ b/tests/ui/layout/malformed-unsized-type-in-union.rs @@ -2,6 +2,7 @@ union W { s: dyn Iterator } //~^ ERROR cannot find type `Missing` in this scope +//~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union static ONCE: W = todo!(); diff --git a/tests/ui/layout/malformed-unsized-type-in-union.stderr b/tests/ui/layout/malformed-unsized-type-in-union.stderr index ad4f0cda19e5c..bdfabc0b15190 100644 --- a/tests/ui/layout/malformed-unsized-type-in-union.stderr +++ b/tests/ui/layout/malformed-unsized-type-in-union.stderr @@ -4,6 +4,19 @@ error[E0412]: cannot find type `Missing` in this scope LL | union W { s: dyn Iterator } | ^^^^^^^ not found in this scope -error: aborting due to 1 previous error +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/malformed-unsized-type-in-union.rs:3:11 + | +LL | union W { s: dyn Iterator } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | union W { s: std::mem::ManuallyDrop> } + | +++++++++++++++++++++++ + + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0412, E0740. +For more information about an error, try `rustc --explain E0412`. From 5c67cfa71a9f5f48c694abc1c57eb1c4b2099f5c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Feb 2025 21:19:21 +0000 Subject: [PATCH 05/17] Use BikeshedGuaranteedNotDrop in unsafe binder type WF too --- .../src/solve/trait_goals.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 5 +- tests/ui/unsafe-binders/moves.rs | 24 ++--- tests/ui/unsafe-binders/moves.stderr | 93 ++++++------------- 4 files changed, 43 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index a95c6c8e63ca1..c6c45317220b1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -624,7 +624,7 @@ where /// NOTE: This is implemented as a built-in goal and not a set of impls like: /// - /// ``` + /// ```rust,ignore (illustrative) /// impl BikeshedGuaranteedNoDrop for T where T: Copy {} /// impl BikeshedGuaranteedNoDrop for ManuallyDrop {} /// ``` diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 96051ad0aa54f..c861c8af0c871 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -841,7 +841,10 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty.map_bound(|ty| { ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Copy, Some(self.span)), + self.tcx().require_lang_item( + LangItem::BikeshedGuaranteedNoDrop, + Some(self.span), + ), [ty], ) }), diff --git a/tests/ui/unsafe-binders/moves.rs b/tests/ui/unsafe-binders/moves.rs index 5bfcee62402d6..9397c2bc20f97 100644 --- a/tests/ui/unsafe-binders/moves.rs +++ b/tests/ui/unsafe-binders/moves.rs @@ -1,40 +1,40 @@ -//@ known-bug: unknown - #![feature(unsafe_binders)] -// FIXME(unsafe_binders) ~^ WARN the feature `unsafe_binders` is incomplete +//~^ WARN the feature `unsafe_binders` is incomplete -use std::unsafe_binder::{wrap_binder, unwrap_binder}; -use std::mem::{drop, ManuallyDrop}; +use std::mem::{ManuallyDrop, drop}; +use std::unsafe_binder::{unwrap_binder, wrap_binder}; +#[derive(Default)] struct NotCopyInner; type NotCopy = ManuallyDrop; fn use_after_wrap() { unsafe { - let base = NotCopy; + let base = NotCopy::default(); let binder: unsafe<> NotCopy = wrap_binder!(base); drop(base); - // FIXME(unsafe_binders) ~^ ERROR use of moved value: `base` + //~^ ERROR use of moved value: `base` } } fn move_out_of_wrap() { unsafe { - let binder: unsafe<> NotCopy = wrap_binder!(NotCopy); + let binder: unsafe<> NotCopy = wrap_binder!(NotCopy::default()); drop(unwrap_binder!(binder)); drop(unwrap_binder!(binder)); - // FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder` + //~^ ERROR use of moved value: `binder` } } fn not_conflicting() { unsafe { - let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); + let binder: unsafe<> (NotCopy, NotCopy) = + wrap_binder!((NotCopy::default(), NotCopy::default())); drop(unwrap_binder!(binder).0); drop(unwrap_binder!(binder).1); - // ^ NOT a problem. + // ^ NOT a problem, since the moves are disjoint. drop(unwrap_binder!(binder).0); - // FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder.0` + //~^ ERROR use of moved value: `binder.0` } } diff --git a/tests/ui/unsafe-binders/moves.stderr b/tests/ui/unsafe-binders/moves.stderr index ca5079640087f..0f976d9e845a3 100644 --- a/tests/ui/unsafe-binders/moves.stderr +++ b/tests/ui/unsafe-binders/moves.stderr @@ -1,37 +1,5 @@ -error[E0423]: expected value, found type alias `NotCopy` - --> $DIR/moves.rs:14:20 - | -LL | let base = NotCopy; - | ^^^^^^^ - | - = note: can't use a type alias as a constructor - -error[E0423]: expected value, found type alias `NotCopy` - --> $DIR/moves.rs:23:53 - | -LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy); - | ^^^^^^^ - | - = note: can't use a type alias as a constructor - -error[E0423]: expected value, found type alias `NotCopy` - --> $DIR/moves.rs:32:65 - | -LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); - | ^^^^^^^ - | - = note: can't use a type alias as a constructor - -error[E0423]: expected value, found type alias `NotCopy` - --> $DIR/moves.rs:32:74 - | -LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); - | ^^^^^^^ - | - = note: can't use a type alias as a constructor - warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/moves.rs:3:12 + --> $DIR/moves.rs:1:12 | LL | #![feature(unsafe_binders)] | ^^^^^^^^^^^^^^ @@ -39,47 +7,38 @@ LL | #![feature(unsafe_binders)] = note: see issue #130516 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied - --> $DIR/moves.rs:15:21 +error[E0382]: use of moved value: `base` + --> $DIR/moves.rs:15:14 | +LL | let base = NotCopy::default(); + | ---- move occurs because `base` has type `ManuallyDrop`, which does not implement the `Copy` trait LL | let binder: unsafe<> NotCopy = wrap_binder!(base); - | ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner` - | - = note: required for `ManuallyDrop` to implement `Copy` -help: consider annotating `NotCopyInner` with `#[derive(Copy)]` - | -LL + #[derive(Copy)] -LL | struct NotCopyInner; - | + | ---- value moved here +LL | drop(base); + | ^^^^ value used here after move -error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied - --> $DIR/moves.rs:23:21 +error[E0382]: use of moved value: `binder` + --> $DIR/moves.rs:24:14 | -LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy); - | ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner` - | - = note: required for `ManuallyDrop` to implement `Copy` -help: consider annotating `NotCopyInner` with `#[derive(Copy)]` - | -LL + #[derive(Copy)] -LL | struct NotCopyInner; +LL | drop(unwrap_binder!(binder)); + | ---------------------- value moved here +LL | drop(unwrap_binder!(binder)); + | ^^^^^^^^^^^^^^^^^^^^^^ value used here after move | + = note: move occurs because `binder` has type `ManuallyDrop`, which does not implement the `Copy` trait + = note: this error originates in the macro `unwrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied - --> $DIR/moves.rs:32:21 - | -LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner` - | - = note: required for `ManuallyDrop` to implement `Copy` - = note: required because it appears within the type `(ManuallyDrop, ManuallyDrop)` -help: consider annotating `NotCopyInner` with `#[derive(Copy)]` +error[E0382]: use of moved value: `binder.0` + --> $DIR/moves.rs:36:14 | -LL + #[derive(Copy)] -LL | struct NotCopyInner; +LL | drop(unwrap_binder!(binder).0); + | ------------------------ value moved here +... +LL | drop(unwrap_binder!(binder).0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move | + = note: move occurs because `binder.0` has type `ManuallyDrop`, which does not implement the `Copy` trait -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted -Some errors have detailed explanations: E0277, E0423. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0382`. From e11e2b4d091635fad78d25c9ba444627ca094677 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 9 Feb 2025 23:05:51 -0800 Subject: [PATCH 06/17] compiler: internally merge `Conv::PtxKernel` into `GpuKernel` It is speculated that these two can be conceptually merged, and it can start by ripping out rustc's notion of the PtxKernel call convention. Leave the ExternAbi for now, but the nvptx target now should see it as just a different way to spell Conv::GpuKernel. --- compiler/rustc_codegen_llvm/src/abi.rs | 1 - compiler/rustc_smir/src/rustc_smir/convert/abi.rs | 1 - compiler/rustc_target/src/callconv/mod.rs | 6 ++---- compiler/rustc_target/src/json.rs | 1 - compiler/rustc_ty_utils/src/abi.rs | 2 +- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 685b2f37c9c3d..e575e9830acd6 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -687,7 +687,6 @@ impl llvm::CallConv { Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, Conv::ArmAapcs => llvm::ArmAapcsCallConv, Conv::Msp430Intr => llvm::Msp430Intr, - Conv::PtxKernel => llvm::PtxKernel, Conv::X86Fastcall => llvm::X86FastcallCallConv, Conv::X86Intr => llvm::X86_Intr, Conv::X86Stdcall => llvm::X86StdcallCallConv, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 4a03ff4beae89..fb2e838cdc998 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -105,7 +105,6 @@ impl<'tcx> Stable<'tcx> for callconv::Conv { Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, Conv::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, Conv::Msp430Intr => CallConvention::Msp430Intr, - Conv::PtxKernel => CallConvention::PtxKernel, Conv::X86Fastcall => CallConvention::X86Fastcall, Conv::X86Intr => CallConvention::X86Intr, Conv::X86Stdcall => CallConvention::X86Stdcall, diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 50ac6c8fcde16..ffc35f9a3be34 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -543,8 +543,6 @@ pub enum Conv { Msp430Intr, - PtxKernel, - GpuKernel, X86Fastcall, @@ -701,7 +699,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), "nvptx64" => { - if cx.target_spec().adjust_abi(abi, self.c_variadic) == ExternAbi::PtxKernel { + let abi = cx.target_spec().adjust_abi(abi, self.c_variadic); + if abi == ExternAbi::PtxKernel || abi == ExternAbi::GpuKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) } else { nvptx64::compute_abi_info(self) @@ -860,7 +859,6 @@ impl FromStr for Conv { "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall), "CCmseNonSecureEntry" => Ok(Conv::CCmseNonSecureEntry), "Msp430Intr" => Ok(Conv::Msp430Intr), - "PtxKernel" => Ok(Conv::PtxKernel), "X86Fastcall" => Ok(Conv::X86Fastcall), "X86Intr" => Ok(Conv::X86Intr), "X86Stdcall" => Ok(Conv::X86Stdcall), diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 15cf7e195dbe5..8d6f8f4c6f67b 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -105,7 +105,6 @@ impl ToJson for crate::callconv::Conv { Self::CCmseNonSecureCall => "CCmseNonSecureCall", Self::CCmseNonSecureEntry => "CCmseNonSecureEntry", Self::Msp430Intr => "Msp430Intr", - Self::PtxKernel => "PtxKernel", Self::X86Fastcall => "X86Fastcall", Self::X86Intr => "X86Intr", Self::X86Stdcall => "X86Stdcall", diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 169f3a78c26a7..25926c871dd33 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -290,7 +290,7 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv Aapcs { .. } => Conv::ArmAapcs, CCmseNonSecureCall => Conv::CCmseNonSecureCall, CCmseNonSecureEntry => Conv::CCmseNonSecureEntry, - PtxKernel => Conv::PtxKernel, + PtxKernel => Conv::GpuKernel, Msp430Interrupt => Conv::Msp430Intr, X86Interrupt => Conv::X86Intr, GpuKernel => Conv::GpuKernel, From be1d6dfbfd841ed48b4b4fc8c3e42f6327723c90 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 9 Feb 2025 23:10:29 -0800 Subject: [PATCH 07/17] cg_clif: stop worrying about `Conv::PtxKernel` --- compiler/rustc_codegen_cranelift/src/abi/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index fdcd9caf4ac87..756a2226753f6 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -65,11 +65,7 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented"); } - Conv::Msp430Intr - | Conv::PtxKernel - | Conv::GpuKernel - | Conv::AvrInterrupt - | Conv::AvrNonBlockingInterrupt => { + Conv::Msp430Intr | Conv::GpuKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); } } From 321fab4337324a66fd79a69ef1bd322062ae374e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 10 Feb 2025 13:43:12 +0100 Subject: [PATCH 08/17] Implement `read*_exact` for `std:io::repeat` cc #136756 --- library/std/src/io/util.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index b4c4dffc371c1..424f862090f09 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -188,6 +188,13 @@ impl Read for Repeat { Ok(buf.len()) } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + for slot in &mut *buf { + *slot = self.byte; + } + Ok(()) + } + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { // SAFETY: No uninit bytes are being written for slot in unsafe { buf.as_mut() } { @@ -204,6 +211,10 @@ impl Read for Repeat { Ok(()) } + fn read_buf_exact(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.read_buf(buf) + } + /// This function is not supported by `io::Repeat`, because there's no end of its data fn read_to_end(&mut self, _: &mut Vec) -> io::Result { Err(io::Error::from(io::ErrorKind::OutOfMemory)) From cde7e805ad48e8766a07c95c2046693c6a6e236c Mon Sep 17 00:00:00 2001 From: Flakebi Date: Mon, 10 Feb 2025 21:38:44 +0100 Subject: [PATCH 09/17] Cast allocas to default address space Pointers for variables all need to be in the same address space for correct compilation. Therefore ensure that even if an `alloca` is created in a different address space, it is casted to the default address space before its value is used. This is necessary for the amdgpu target and others where the default address space for `alloca`s is not 0. For example the following code compiles incorrectly when not casting the address space to the default one: ```rust fn f(p: *const i8 /* addrspace(0) */) -> *const i8 /* addrspace(0) */ { let local = 0i8; /* addrspace(5) */ let res = if cond { p } else { &raw const local }; res } ``` results in ```llvm %local = alloca addrspace(5) i8 %res = alloca addrspace(5) ptr if: ; Store 64-bit flat pointer store ptr %p, ptr addrspace(5) %res else: ; Store 32-bit scratch pointer store ptr addrspace(5) %local, ptr addrspace(5) %res ret: ; Load and return 64-bit flat pointer %res.load = load ptr, ptr addrspace(5) %res ret ptr %res.load ``` For amdgpu, `addrspace(0)` are 64-bit pointers, `addrspace(5)` are 32-bit pointers. The above code may store a 32-bit pointer and read it back as a 64-bit pointer, which is obviously wrong and cannot work. Instead, we need to `addrspacecast %local to ptr addrspace(0)`, then we store and load the correct type. --- compiler/rustc_codegen_llvm/src/builder.rs | 6 ++++-- tests/codegen/amdgpu-addrspacecast.rs | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/codegen/amdgpu-addrspacecast.rs diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index ab0e43e60a4f5..fbeedef314dfb 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -421,7 +421,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let alloca = llvm::LLVMBuildAlloca(bx.llbuilder, ty, UNNAMED); llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); - alloca + // Cast to default addrspace if necessary + llvm::LLVMBuildPointerCast(bx.llbuilder, alloca, self.cx().type_ptr(), UNNAMED) } } @@ -430,7 +431,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let alloca = llvm::LLVMBuildArrayAlloca(self.llbuilder, self.cx().type_i8(), size, UNNAMED); llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); - alloca + // Cast to default addrspace if necessary + llvm::LLVMBuildPointerCast(self.llbuilder, alloca, self.cx().type_ptr(), UNNAMED) } } diff --git a/tests/codegen/amdgpu-addrspacecast.rs b/tests/codegen/amdgpu-addrspacecast.rs new file mode 100644 index 0000000000000..7fe630a7efa0e --- /dev/null +++ b/tests/codegen/amdgpu-addrspacecast.rs @@ -0,0 +1,18 @@ +// Check that pointers are casted to addrspace(0) before they are used + +//@ compile-flags: --crate-type=rlib --target=amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 +//@ needs-llvm-components: amdgpu +//@ add-core-stubs +#![feature(no_core)] +#![no_core] + +extern crate minicore; + +// CHECK-LABEL: @ref_of_local +// CHECK: [[alloca:%[0-9]]] = alloca +// CHECK: %i = addrspacecast ptr addrspace(5) [[alloca]] to ptr +#[no_mangle] +pub fn ref_of_local(f: fn(&i32)) { + let i = 0; + f(&i); +} From a634246b66a8a37dd25a026a6c8cafd0b84ca91b Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 10 Feb 2025 14:43:22 +0800 Subject: [PATCH 10/17] reduce query calls in pretty printing when finding bounds of associated types --- .../src/collect/item_bounds.rs | 88 ++++++++++--------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index e37a11b684453..06c51c27a9a84 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -30,53 +30,55 @@ fn associated_type_bounds<'tcx>( span: Span, filter: PredicateFilter, ) -> &'tcx [(ty::Clause<'tcx>, Span)] { - let item_ty = Ty::new_projection_from_args( - tcx, - assoc_item_def_id.to_def_id(), - GenericArgs::identity_for_item(tcx, assoc_item_def_id), - ); - - let icx = ItemCtxt::new(tcx, assoc_item_def_id); - let mut bounds = Bounds::default(); - icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); - // Associated types are implicitly sized unless a `?Sized` bound is found - match filter { - PredicateFilter::All - | PredicateFilter::SelfOnly - | PredicateFilter::SelfTraitThatDefines(_) - | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + ty::print::with_reduced_queries!({ + let item_ty = Ty::new_projection_from_args( + tcx, + assoc_item_def_id.to_def_id(), + GenericArgs::identity_for_item(tcx, assoc_item_def_id), + ); + + let icx = ItemCtxt::new(tcx, assoc_item_def_id); + let mut bounds = Bounds::default(); + icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); + // Associated types are implicitly sized unless a `?Sized` bound is found + match filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfTraitThatDefines(_) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + } + // `ConstIfConst` is only interested in `~const` bounds. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} } - // `ConstIfConst` is only interested in `~const` bounds. - PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} - } - let trait_def_id = tcx.local_parent(assoc_item_def_id); - let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - - let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); - let bounds_from_parent = - trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| { - remap_gat_vars_and_recurse_into_nested_projections( - tcx, - filter, - item_trait_ref, - assoc_item_def_id, - span, - clause, - ) - }); - - let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); - debug!( - "associated_type_bounds({}) = {:?}", - tcx.def_path_str(assoc_item_def_id.to_def_id()), - all_bounds - ); + let trait_def_id = tcx.local_parent(assoc_item_def_id); + let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); + + let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); + let bounds_from_parent = + trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| { + remap_gat_vars_and_recurse_into_nested_projections( + tcx, + filter, + item_trait_ref, + assoc_item_def_id, + span, + clause, + ) + }); + + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); + debug!( + "associated_type_bounds({}) = {:?}", + tcx.def_path_str(assoc_item_def_id.to_def_id()), + all_bounds + ); - assert_only_contains_predicates_from(filter, all_bounds, item_ty); + assert_only_contains_predicates_from(filter, all_bounds, item_ty); - all_bounds + all_bounds + }) } /// The code below is quite involved, so let me explain. From c294da3310301027dfa304b270c5d0ab78c2b851 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Jan 2025 09:17:40 +0000 Subject: [PATCH 11/17] Reject `impl Trait` bounds in various places where we unconditionally warned since 1.0 --- .../src/hir_ty_lowering/bounds.rs | 4 ++-- .../diagnostic-flags/allow-non-lint-warnings.rs | 11 +++++------ .../allow-non-lint-warnings.without_flag.stderr | 8 ++++---- .../feature-gate-more-maybe-bounds.rs | 8 ++++---- .../feature-gate-more-maybe-bounds.stderr | 10 +++++----- .../ui/impl-trait/opt-out-bound-not-satisfied.rs | 11 +++++++++++ .../opt-out-bound-not-satisfied.stderr | 16 ++++++++++++++++ tests/ui/issues/issue-37534.rs | 2 +- tests/ui/issues/issue-37534.stderr | 4 ++-- tests/ui/issues/issue-87199.rs | 8 ++++---- tests/ui/issues/issue-87199.stderr | 10 +++++----- .../ui/trait-bounds/maybe-bound-has-path-args.rs | 2 +- .../maybe-bound-has-path-args.stderr | 4 ++-- tests/ui/trait-bounds/maybe-bound-with-assoc.rs | 4 ++-- .../trait-bounds/maybe-bound-with-assoc.stderr | 6 +++--- tests/ui/traits/maybe-polarity-pass.rs | 8 +++----- tests/ui/traits/maybe-polarity-pass.stderr | 14 +++++++------- tests/ui/traits/maybe-polarity-repeated.rs | 4 ++-- tests/ui/traits/maybe-polarity-repeated.stderr | 6 +++--- tests/ui/unsized/maybe-bounds-where.rs | 4 ++-- tests/ui/unsized/maybe-bounds-where.stderr | 6 +++--- 21 files changed, 87 insertions(+), 63 deletions(-) create mode 100644 tests/ui/impl-trait/opt-out-bound-not-satisfied.rs create mode 100644 tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 2834d49769452..ef6167907b5b2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -102,8 +102,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { seen_sized_unbound = true; continue; } - // There was a `?Trait` bound, but it was not `?Sized`; warn. - self.dcx().span_warn( + // There was a `?Trait` bound, but it was not `?Sized` + self.dcx().span_err( unbound.span, "relaxing a default bound only does something for `?Sized`; \ all other traits are not bound by default", diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs index 40b9e6536f500..8980ef9c4220f 100644 --- a/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs +++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs @@ -1,8 +1,7 @@ // ignore-tidy-linelength //! Check that `-A warnings` cli flag applies to non-lint warnings as well. //! -//! This test tries to exercise that by checking that the "relaxing a default bound only does -//! something for `?Sized`; all other traits are not bound by default" non-lint warning (normally +//! This test tries to exercise that by checking that a non-lint warning (normally //! warn-by-default) is suppressed if the `-A warnings` cli flag is passed. //! //! Take special note that `warnings` is a special pseudo lint group in relationship to non-lint @@ -14,7 +13,7 @@ //! - Original impl PR: . //! - RFC 507 "Release channels": //! . -#![crate_type = "lib"] +#![feature(rustc_attrs)] //@ revisions: without_flag with_flag @@ -22,6 +21,6 @@ //@ check-pass -pub trait Trait {} -pub fn f() {} -//[without_flag]~^ WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +#[rustc_error(warn)] +fn main() {} +//[without_flag]~^ WARN unexpected annotation used with `#[rustc_error(...)]`! diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr index b037847c70f1b..3f33ccbd1c9f9 100644 --- a/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr +++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr @@ -1,8 +1,8 @@ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/allow-non-lint-warnings.rs:26:13 +warning: unexpected annotation used with `#[rustc_error(...)]`! + --> $DIR/allow-non-lint-warnings.rs:25:1 | -LL | pub fn f() {} - | ^^^^^^ +LL | fn main() {} + | ^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs index debe143b09172..6a832744e3ee9 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -11,14 +11,14 @@ fn foo(_: Box) {} //~^ ERROR `?Trait` is not permitted in trait object types fn bar(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default trait Trait {} // Do not suggest `#![feature(more_maybe_bounds)]` for repetitions fn baz(_ : T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index e6d65e059977a..729df4eb37cac 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -35,13 +35,13 @@ LL | fn bar(_: T) {} = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/feature-gate-more-maybe-bounds.rs:12:11 | LL | fn bar(_: T) {} | ^^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/feature-gate-more-maybe-bounds.rs:12:21 | LL | fn bar(_: T) {} @@ -53,19 +53,19 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i LL | fn baz(_ : T) {} | ^^^^^^ ^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/feature-gate-more-maybe-bounds.rs:19:11 | LL | fn baz(_ : T) {} | ^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/feature-gate-more-maybe-bounds.rs:19:20 | LL | fn baz(_ : T) {} | ^^^^^^ -error: aborting due to 5 previous errors; 4 warnings emitted +error: aborting due to 9 previous errors Some errors have detailed explanations: E0203, E0658. For more information about an error, try `rustc --explain E0203`. diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs new file mode 100644 index 0000000000000..27c493a13bf91 --- /dev/null +++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs @@ -0,0 +1,11 @@ +//! Regression test for ICE https://github.com/rust-lang/rust/issues/135730 +//! This used + +use std::future::Future; +fn foo() -> impl ?Future { + //~^ ERROR: relaxing a default bound only does something for `?Sized` + //~| ERROR: relaxing a default bound only does something for `?Sized` + () +} + +pub fn main() {} diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr new file mode 100644 index 0000000000000..dc4314c58ad2f --- /dev/null +++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr @@ -0,0 +1,16 @@ +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/opt-out-bound-not-satisfied.rs:5:18 + | +LL | fn foo() -> impl ?Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/opt-out-bound-not-satisfied.rs:5:18 + | +LL | fn foo() -> impl ?Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/issues/issue-37534.rs index dff89d3888d0c..09d60b7786b99 100644 --- a/tests/ui/issues/issue-37534.rs +++ b/tests/ui/issues/issue-37534.rs @@ -1,5 +1,5 @@ struct Foo {} //~^ ERROR expected trait, found derive macro `Hash` -//~| WARN relaxing a default bound only does something for `?Sized` +//~| ERROR relaxing a default bound only does something for `?Sized` fn main() {} diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index 8747bd5ac6fad..3219854bc70ce 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -9,12 +9,12 @@ help: consider importing this trait instead LL + use std::hash::Hash; | -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/issue-37534.rs:1:15 | LL | struct Foo {} | ^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0404`. diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs index 34879c5a7ca3b..6664119e57981 100644 --- a/tests/ui/issues/issue-87199.rs +++ b/tests/ui/issues/issue-87199.rs @@ -6,12 +6,12 @@ // Check that these function definitions only emit warnings, not errors fn arg(_: T) {} -//~^ warning: relaxing a default bound only does something for `?Sized` +//~^ ERROR: relaxing a default bound only does something for `?Sized` fn ref_arg(_: &T) {} -//~^ warning: relaxing a default bound only does something for `?Sized` +//~^ ERROR: relaxing a default bound only does something for `?Sized` fn ret() -> impl Iterator + ?Send { std::iter::empty() } -//~^ warning: relaxing a default bound only does something for `?Sized` -//~| warning: relaxing a default bound only does something for `?Sized` +//~^ ERROR: relaxing a default bound only does something for `?Sized` +//~| ERROR: relaxing a default bound only does something for `?Sized` // Check that there's no `?Sized` relaxation! fn main() { diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr index a0ed2946fb4af..acc4e84779c9c 100644 --- a/tests/ui/issues/issue-87199.stderr +++ b/tests/ui/issues/issue-87199.stderr @@ -1,22 +1,22 @@ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/issue-87199.rs:8:11 | LL | fn arg(_: T) {} | ^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/issue-87199.rs:10:15 | LL | fn ref_arg(_: &T) {} | ^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/issue-87199.rs:12:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } | ^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/issue-87199.rs:12:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } @@ -41,6 +41,6 @@ help: consider relaxing the implicit `Sized` restriction LL | fn ref_arg(_: &T) {} | ++++++++ -error: aborting due to 1 previous error; 4 warnings emitted +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs index fd0e96917004d..e5abcae5d219b 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs @@ -2,6 +2,6 @@ trait Trait {} fn test::Trait>() {} //~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args` -//~| WARN relaxing a default bound only does something for `?Sized` +//~| ERROR relaxing a default bound only does something for `?Sized` fn main() {} diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr index 0c167fff94012..dc55b26c9183c 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr @@ -1,4 +1,4 @@ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-bound-has-path-args.rs:3:12 | LL | fn test::Trait>() {} @@ -12,6 +12,6 @@ LL | fn test::Trait>() {} | | | not allowed on module `maybe_bound_has_path_args` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0109`. diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs index b6b2551e4638e..9127c2de16d5e 100644 --- a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs +++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs @@ -2,11 +2,11 @@ trait HasAssoc { type Assoc; } fn hasassoc>() {} -//~^ WARN relaxing a default bound +//~^ ERROR relaxing a default bound trait NoAssoc {} fn noassoc>() {} -//~^ WARN relaxing a default bound +//~^ ERROR relaxing a default bound //~| ERROR associated type `Missing` not found for `NoAssoc` fn main() {} diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr index 91d78e59cd5a7..36a1e0ade2063 100644 --- a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr +++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr @@ -1,10 +1,10 @@ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-bound-with-assoc.rs:4:16 | LL | fn hasassoc>() {} | ^^^^^^^^^^^^^^^^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-bound-with-assoc.rs:8:15 | LL | fn noassoc>() {} @@ -16,6 +16,6 @@ error[E0220]: associated type `Missing` not found for `NoAssoc` LL | fn noassoc>() {} | ^^^^^^^ associated type `Missing` not found -error: aborting due to 1 previous error; 2 warnings emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/traits/maybe-polarity-pass.rs b/tests/ui/traits/maybe-polarity-pass.rs index 075a0d8dcac4d..1ccd52bc1694a 100644 --- a/tests/ui/traits/maybe-polarity-pass.rs +++ b/tests/ui/traits/maybe-polarity-pass.rs @@ -1,5 +1,3 @@ -//@ check-pass - #![feature(auto_traits)] #![feature(more_maybe_bounds)] #![feature(negative_impls)] @@ -12,9 +10,9 @@ trait Trait4 where Self: Trait1 {} fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {} fn bar(_: &T) {} -//~^ WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default struct S; impl !Trait2 for S {} diff --git a/tests/ui/traits/maybe-polarity-pass.stderr b/tests/ui/traits/maybe-polarity-pass.stderr index 09ed52f5b0dd7..1f378dd665ae6 100644 --- a/tests/ui/traits/maybe-polarity-pass.stderr +++ b/tests/ui/traits/maybe-polarity-pass.stderr @@ -1,20 +1,20 @@ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:14:20 +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/maybe-polarity-pass.rs:12:20 | LL | fn bar(_: &T) {} | ^^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:14:30 +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/maybe-polarity-pass.rs:12:30 | LL | fn bar(_: &T) {} | ^^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:14:40 +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/maybe-polarity-pass.rs:12:40 | LL | fn bar(_: &T) {} | ^^^^^^^ -warning: 3 warnings emitted +error: aborting due to 3 previous errors diff --git a/tests/ui/traits/maybe-polarity-repeated.rs b/tests/ui/traits/maybe-polarity-repeated.rs index 4b5ec83fffab0..fd1ef567b3eab 100644 --- a/tests/ui/traits/maybe-polarity-repeated.rs +++ b/tests/ui/traits/maybe-polarity-repeated.rs @@ -3,7 +3,7 @@ trait Trait {} fn foo(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default fn main() {} diff --git a/tests/ui/traits/maybe-polarity-repeated.stderr b/tests/ui/traits/maybe-polarity-repeated.stderr index 610c484fbec59..4fa1dc45bda85 100644 --- a/tests/ui/traits/maybe-polarity-repeated.stderr +++ b/tests/ui/traits/maybe-polarity-repeated.stderr @@ -4,18 +4,18 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i LL | fn foo(_: T) {} | ^^^^^^ ^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-polarity-repeated.rs:4:11 | LL | fn foo(_: T) {} | ^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-polarity-repeated.rs:4:20 | LL | fn foo(_: T) {} | ^^^^^^ -error: aborting due to 1 previous error; 2 warnings emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0203`. diff --git a/tests/ui/unsized/maybe-bounds-where.rs b/tests/ui/unsized/maybe-bounds-where.rs index 7e82a3eb449cb..4c4141631a7c5 100644 --- a/tests/ui/unsized/maybe-bounds-where.rs +++ b/tests/ui/unsized/maybe-bounds-where.rs @@ -11,11 +11,11 @@ trait Trait<'a> {} struct S4(T) where for<'a> T: ?Trait<'a>; //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared -//~| WARN relaxing a default bound only does something for `?Sized` +//~| ERROR relaxing a default bound only does something for `?Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; //~^ ERROR type parameter has more than one relaxed default bound -//~| WARN relaxing a default bound only does something for `?Sized` +//~| ERROR relaxing a default bound only does something for `?Sized` impl S1 { fn f() where T: ?Sized {} diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/maybe-bounds-where.stderr index f785126166781..fb6d37c29660a 100644 --- a/tests/ui/unsized/maybe-bounds-where.stderr +++ b/tests/ui/unsized/maybe-bounds-where.stderr @@ -43,7 +43,7 @@ LL | fn f() where T: ?Sized {} = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-bounds-where.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; @@ -58,13 +58,13 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default --> $DIR/maybe-bounds-where.rs:16:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 8 previous errors Some errors have detailed explanations: E0203, E0658. For more information about an error, try `rustc --explain E0203`. From 80c60fe78375cb10a2fed6540dc2b29751fc4263 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 7 Feb 2025 18:34:09 +0100 Subject: [PATCH 12/17] std: replace the `FromInner` implementation for addresses with private conversion functions Having these implementation available crate-wide means that platforms not using sockets for their networking code have to stub out the libc definitions required to support them. This PR moves the conversions to private helper functions that are only available where actually needed. I also fixed the signature of the function converting from a C socket address to a Rust one: taking a reference to a `sockaddr_storage` resulted in unsound usage inside `LookupHost::next`, which could create a reference to a structure smaller than `sockaddr_storage`. Thus I've replaced the argument type with a pointer and made the function `unsafe`. --- library/std/src/net/ip_addr.rs | 29 --- library/std/src/net/socket_addr.rs | 46 +---- library/std/src/os/solid/io.rs | 4 +- library/std/src/sys/net/connection/sgx.rs | 35 ---- library/std/src/sys/net/connection/socket.rs | 188 +++++++++++------- .../src/sys/net/connection/socket/hermit.rs | 10 +- .../src/sys/net/connection/socket/solid.rs | 8 +- .../std/src/sys/net/connection/socket/unix.rs | 11 +- .../src/sys/net/connection/socket/wasip2.rs | 9 +- .../src/sys/net/connection/socket/windows.rs | 23 ++- .../std/src/sys/net/connection/uefi/mod.rs | 35 ---- .../std/src/sys/net/connection/unsupported.rs | 35 ---- library/std/src/sys/net/connection/wasip1.rs | 35 ---- .../std/src/sys/net/connection/xous/mod.rs | 35 ---- 14 files changed, 155 insertions(+), 348 deletions(-) diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs index 4d673a1d66db6..7262899b3bbbe 100644 --- a/library/std/src/net/ip_addr.rs +++ b/library/std/src/net/ip_addr.rs @@ -8,32 +8,3 @@ pub use core::net::IpAddr; pub use core::net::Ipv6MulticastScope; #[stable(feature = "rust1", since = "1.0.0")] pub use core::net::{Ipv4Addr, Ipv6Addr}; - -use crate::sys::net::netc as c; -use crate::sys_common::{FromInner, IntoInner}; - -impl IntoInner for Ipv4Addr { - #[inline] - fn into_inner(self) -> c::in_addr { - // `s_addr` is stored as BE on all machines and the array is in BE order. - // So the native endian conversion method is used so that it's never swapped. - c::in_addr { s_addr: u32::from_ne_bytes(self.octets()) } - } -} -impl FromInner for Ipv4Addr { - fn from_inner(addr: c::in_addr) -> Ipv4Addr { - Ipv4Addr::from(addr.s_addr.to_ne_bytes()) - } -} - -impl IntoInner for Ipv6Addr { - fn into_inner(self) -> c::in6_addr { - c::in6_addr { s6_addr: self.octets() } - } -} -impl FromInner for Ipv6Addr { - #[inline] - fn from_inner(addr: c::in6_addr) -> Ipv6Addr { - Ipv6Addr::from(addr.s6_addr) - } -} diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs index e8355cc31d7a5..4c8905c0d4609 100644 --- a/library/std/src/net/socket_addr.rs +++ b/library/std/src/net/socket_addr.rs @@ -6,50 +6,8 @@ mod tests; pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use crate::sys::net::{LookupHost, netc as c}; -use crate::sys_common::{FromInner, IntoInner}; -use crate::{io, iter, mem, option, slice, vec}; - -impl FromInner for SocketAddrV4 { - fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 { - SocketAddrV4::new(Ipv4Addr::from_inner(addr.sin_addr), u16::from_be(addr.sin_port)) - } -} - -impl FromInner for SocketAddrV6 { - fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 { - SocketAddrV6::new( - Ipv6Addr::from_inner(addr.sin6_addr), - u16::from_be(addr.sin6_port), - addr.sin6_flowinfo, - addr.sin6_scope_id, - ) - } -} - -impl IntoInner for SocketAddrV4 { - fn into_inner(self) -> c::sockaddr_in { - c::sockaddr_in { - sin_family: c::AF_INET as c::sa_family_t, - sin_port: self.port().to_be(), - sin_addr: self.ip().into_inner(), - ..unsafe { mem::zeroed() } - } - } -} - -impl IntoInner for SocketAddrV6 { - fn into_inner(self) -> c::sockaddr_in6 { - c::sockaddr_in6 { - sin6_family: c::AF_INET6 as c::sa_family_t, - sin6_port: self.port().to_be(), - sin6_addr: self.ip().into_inner(), - sin6_flowinfo: self.flowinfo(), - sin6_scope_id: self.scope_id(), - ..unsafe { mem::zeroed() } - } - } -} +use crate::sys::net::LookupHost; +use crate::{io, iter, option, slice, vec}; /// A trait for objects which can be converted or resolved to one or more /// [`SocketAddr`] values. diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index b8c3440542d00..ca58a900c4451 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -122,7 +122,7 @@ impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. pub fn try_clone_to_owned(&self) -> crate::io::Result { - let fd = sys::net::cvt(unsafe { sys::net::netc::dup(self.as_raw_fd()) })?; + let fd = sys::net::cvt(unsafe { crate::sys::abi::sockets::dup(self.as_raw_fd()) })?; Ok(unsafe { OwnedFd::from_raw_fd(fd) }) } } @@ -168,7 +168,7 @@ impl FromRawFd for OwnedFd { impl Drop for OwnedFd { #[inline] fn drop(&mut self) { - unsafe { sys::net::netc::close(self.fd.as_inner()) }; + unsafe { crate::sys::abi::sockets::close(self.fd.as_inner()) }; } } diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index b390a5eac5f74..242df10bc3270 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -499,38 +499,3 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost { LookupHost::new(format!("{host}:{port}")) } } - -#[allow(bad_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/connection/socket.rs b/library/std/src/sys/net/connection/socket.rs index 6fe3430b53f79..b4f0a7836803e 100644 --- a/library/std/src/sys/net/connection/socket.rs +++ b/library/std/src/sys/net/connection/socket.rs @@ -3,9 +3,9 @@ mod tests; use crate::ffi::{c_int, c_void}; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::sys::common::small_c_string::run_with_cstr; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner}; use crate::time::Duration; use crate::{cmp, fmt, mem, ptr}; @@ -79,6 +79,111 @@ cfg_if::cfg_if! { } } +//////////////////////////////////////////////////////////////////////////////// +// address conversions +//////////////////////////////////////////////////////////////////////////////// + +fn ip_v4_addr_to_c(addr: &Ipv4Addr) -> c::in_addr { + // `s_addr` is stored as BE on all machines and the array is in BE order. + // So the native endian conversion method is used so that it's never swapped. + c::in_addr { s_addr: u32::from_ne_bytes(addr.octets()) } +} + +fn ip_v6_addr_to_c(addr: &Ipv6Addr) -> c::in6_addr { + c::in6_addr { s6_addr: addr.octets() } +} + +fn ip_v4_addr_from_c(addr: c::in_addr) -> Ipv4Addr { + Ipv4Addr::from(addr.s_addr.to_ne_bytes()) +} + +fn ip_v6_addr_from_c(addr: c::in6_addr) -> Ipv6Addr { + Ipv6Addr::from(addr.s6_addr) +} + +fn socket_addr_v4_to_c(addr: &SocketAddrV4) -> c::sockaddr_in { + c::sockaddr_in { + sin_family: c::AF_INET as c::sa_family_t, + sin_port: addr.port().to_be(), + sin_addr: ip_v4_addr_to_c(addr.ip()), + ..unsafe { mem::zeroed() } + } +} + +fn socket_addr_v6_to_c(addr: &SocketAddrV6) -> c::sockaddr_in6 { + c::sockaddr_in6 { + sin6_family: c::AF_INET6 as c::sa_family_t, + sin6_port: addr.port().to_be(), + sin6_addr: ip_v6_addr_to_c(addr.ip()), + sin6_flowinfo: addr.flowinfo(), + sin6_scope_id: addr.scope_id(), + ..unsafe { mem::zeroed() } + } +} + +fn socket_addr_v4_from_c(addr: c::sockaddr_in) -> SocketAddrV4 { + SocketAddrV4::new(ip_v4_addr_from_c(addr.sin_addr), u16::from_be(addr.sin_port)) +} + +fn socket_addr_v6_from_c(addr: c::sockaddr_in6) -> SocketAddrV6 { + SocketAddrV6::new( + ip_v6_addr_from_c(addr.sin6_addr), + u16::from_be(addr.sin6_port), + addr.sin6_flowinfo, + addr.sin6_scope_id, + ) +} + +/// A type with the same memory layout as `c::sockaddr`. Used in converting Rust level +/// SocketAddr* types into their system representation. The benefit of this specific +/// type over using `c::sockaddr_storage` is that this type is exactly as large as it +/// needs to be and not a lot larger. And it can be initialized more cleanly from Rust. +#[repr(C)] +union SocketAddrCRepr { + v4: c::sockaddr_in, + v6: c::sockaddr_in6, +} + +impl SocketAddrCRepr { + fn as_ptr(&self) -> *const c::sockaddr { + self as *const _ as *const c::sockaddr + } +} + +fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) { + match addr { + SocketAddr::V4(a) => { + let sockaddr = SocketAddrCRepr { v4: socket_addr_v4_to_c(a) }; + (sockaddr, mem::size_of::() as c::socklen_t) + } + SocketAddr::V6(a) => { + let sockaddr = SocketAddrCRepr { v6: socket_addr_v6_to_c(a) }; + (sockaddr, mem::size_of::() as c::socklen_t) + } + } +} + +unsafe fn socket_addr_from_c( + storage: *const c::sockaddr_storage, + len: usize, +) -> io::Result { + match (*storage).ss_family as c_int { + c::AF_INET => { + assert!(len >= mem::size_of::()); + Ok(SocketAddr::V4(socket_addr_v4_from_c(unsafe { + *(storage as *const _ as *const c::sockaddr_in) + }))) + } + c::AF_INET6 => { + assert!(len >= mem::size_of::()); + Ok(SocketAddr::V6(socket_addr_v6_from_c(unsafe { + *(storage as *const _ as *const c::sockaddr_in6) + }))) + } + _ => Err(io::const_error!(ErrorKind::InvalidInput, "invalid argument")), + } +} + //////////////////////////////////////////////////////////////////////////////// // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// @@ -124,25 +229,7 @@ where let mut storage: c::sockaddr_storage = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c::socklen_t; cvt(f((&raw mut storage) as *mut _, &mut len))?; - sockaddr_to_addr(&storage, len as usize) - } -} - -pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result { - match storage.ss_family as c_int { - c::AF_INET => { - assert!(len >= mem::size_of::()); - Ok(SocketAddr::V4(FromInner::from_inner(unsafe { - *(storage as *const _ as *const c::sockaddr_in) - }))) - } - c::AF_INET6 => { - assert!(len >= mem::size_of::()); - Ok(SocketAddr::V6(FromInner::from_inner(unsafe { - *(storage as *const _ as *const c::sockaddr_in6) - }))) - } - _ => Err(io::const_error!(ErrorKind::InvalidInput, "invalid argument")), + socket_addr_from_c(&storage, len as usize) } } @@ -179,7 +266,7 @@ impl Iterator for LookupHost { unsafe { let cur = self.cur.as_ref()?; self.cur = cur.ai_next; - match sockaddr_to_addr(mem::transmute(cur.ai_addr), cur.ai_addrlen as usize) { + match socket_addr_from_c(cur.ai_addr.cast(), cur.ai_addrlen as usize) { Ok(addr) => return Some(addr), Err(_) => continue, } @@ -432,7 +519,7 @@ impl TcpListener { setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; // Bind our new socket - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; cfg_if::cfg_if! { @@ -473,7 +560,7 @@ impl TcpListener { let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as c::socklen_t; let sock = self.inner.accept((&raw mut storage) as *mut _, &mut len)?; - let addr = sockaddr_to_addr(&storage, len as usize)?; + let addr = unsafe { socket_addr_from_c(&storage, len as usize)? }; Ok((TcpStream { inner: sock }, addr)) } @@ -542,7 +629,7 @@ impl UdpSocket { init(); let sock = Socket::new(addr, c::SOCK_DGRAM)?; - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; Ok(UdpSocket { inner: sock }) } @@ -574,7 +661,7 @@ impl UdpSocket { pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result { let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; - let (dst, dstlen) = dst.into_inner(); + let (dst, dstlen) = socket_addr_to_c(dst); let ret = cvt(unsafe { c::sendto( self.inner.as_raw(), @@ -656,15 +743,15 @@ impl UdpSocket { pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { let mreq = c::ip_mreq { - imr_multiaddr: multiaddr.into_inner(), - imr_interface: interface.into_inner(), + imr_multiaddr: ip_v4_addr_to_c(multiaddr), + imr_interface: ip_v4_addr_to_c(interface), }; setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) } pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { let mreq = c::ipv6_mreq { - ipv6mr_multiaddr: multiaddr.into_inner(), + ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr), ipv6mr_interface: to_ipv6mr_interface(interface), }; setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) @@ -672,15 +759,15 @@ impl UdpSocket { pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { let mreq = c::ip_mreq { - imr_multiaddr: multiaddr.into_inner(), - imr_interface: interface.into_inner(), + imr_multiaddr: ip_v4_addr_to_c(multiaddr), + imr_interface: ip_v4_addr_to_c(interface), }; setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) } pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { let mreq = c::ipv6_mreq { - ipv6mr_multiaddr: multiaddr.into_inner(), + ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr), ipv6mr_interface: to_ipv6mr_interface(interface), }; setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) @@ -720,7 +807,7 @@ impl UdpSocket { } pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { - let (addr, len) = addr?.into_inner(); + let (addr, len) = socket_addr_to_c(addr?); cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop) } } @@ -743,38 +830,3 @@ impl fmt::Debug for UdpSocket { res.field(name, &self.inner.as_raw()).finish() } } - -//////////////////////////////////////////////////////////////////////////////// -// Converting SocketAddr to libc representation -//////////////////////////////////////////////////////////////////////////////// - -/// A type with the same memory layout as `c::sockaddr`. Used in converting Rust level -/// SocketAddr* types into their system representation. The benefit of this specific -/// type over using `c::sockaddr_storage` is that this type is exactly as large as it -/// needs to be and not a lot larger. And it can be initialized more cleanly from Rust. -#[repr(C)] -pub(crate) union SocketAddrCRepr { - v4: c::sockaddr_in, - v6: c::sockaddr_in6, -} - -impl SocketAddrCRepr { - pub fn as_ptr(&self) -> *const c::sockaddr { - self as *const _ as *const c::sockaddr - } -} - -impl<'a> IntoInner<(SocketAddrCRepr, c::socklen_t)> for &'a SocketAddr { - fn into_inner(self) -> (SocketAddrCRepr, c::socklen_t) { - match *self { - SocketAddr::V4(ref a) => { - let sockaddr = SocketAddrCRepr { v4: a.into_inner() }; - (sockaddr, mem::size_of::() as c::socklen_t) - } - SocketAddr::V6(ref a) => { - let sockaddr = SocketAddrCRepr { v6: a.into_inner() }; - (sockaddr, mem::size_of::() as c::socklen_t) - } - } - } -} diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index 42179dcc9156d..e393342ced9da 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -2,13 +2,13 @@ use core::ffi::c_int; -pub(crate) use hermit_abi as netc; +pub(super) use hermit_abi as netc; +use super::{getsockopt, setsockopt, socket_addr_from_c, socket_addr_to_c}; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; use crate::sys::fd::FileDesc; -use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys::time::Instant; pub use crate::sys::{cvt, cvt_r}; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -55,7 +55,7 @@ impl Socket { } pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?; Ok(()) } @@ -63,7 +63,7 @@ impl Socket { pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = unsafe { - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len)) }; self.set_nonblocking(false)?; @@ -195,7 +195,7 @@ impl Socket { &mut addrlen, ) })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + Ok((n as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index f85ecbb883ee7..906bef267b6f0 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -1,17 +1,17 @@ use libc::{c_int, c_void, size_t}; use self::netc::{MSG_PEEK, sockaddr, socklen_t}; +use super::{getsockopt, setsockopt, socket_addr_from_c, socket_addr_to_c}; use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}; use crate::sys::abi; -use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys_common::{FromInner, IntoInner}; use crate::time::Duration; use crate::{cmp, mem, ptr, str}; -pub mod netc { +pub(super) mod netc { pub use crate::sys::abi::sockets::*; } @@ -131,7 +131,7 @@ impl Socket { } pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); cvt(unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?; Ok(()) } @@ -256,7 +256,7 @@ impl Socket { &mut addrlen, ) })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + Ok((n as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index da6316055273f..34ab26bc117af 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -5,7 +5,7 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; -use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; +use crate::sys::net::{getsockopt, setsockopt}; use crate::sys::pal::IsMinusOne; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; @@ -19,8 +19,9 @@ cfg_if::cfg_if! { } } -pub(crate) use libc as netc; +pub(super) use libc as netc; +use super::{socket_addr_from_c, socket_addr_to_c}; pub use crate::sys::{cvt, cvt_r}; #[expect(non_camel_case_types)] @@ -150,7 +151,7 @@ impl Socket { } pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); loop { let result = unsafe { libc::connect(self.as_raw_fd(), addr.as_ptr(), len) }; if result.is_minus_one() { @@ -168,7 +169,7 @@ impl Socket { pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = unsafe { - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); cvt(libc::connect(self.as_raw_fd(), addr.as_ptr(), len)) }; self.set_nonblocking(false)?; @@ -334,7 +335,7 @@ impl Socket { &mut addrlen, ) })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + Ok((n as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index 9d1c05a473e4d..c5034e73dd704 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -1,19 +1,18 @@ #![deny(unsafe_op_in_unsafe_fn)] +pub(super) use libc as netc; use libc::{c_int, c_void, size_t}; +use super::{getsockopt, setsockopt, socket_addr_from_c, socket_addr_to_c}; use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys::unsupported; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; use crate::{cmp, mem, str}; -pub extern crate libc as netc; - #[allow(non_camel_case_types)] pub type wrlen_t = size_t; @@ -89,7 +88,7 @@ impl Socket { } pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?; Ok(()) } @@ -224,7 +223,7 @@ impl Socket { &mut addrlen, ) })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + Ok((n as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 80cf37eaf0580..428f142dabe20 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -2,6 +2,7 @@ use core::ffi::{c_int, c_long, c_ulong, c_ushort}; +use super::{getsockopt, setsockopt, socket_addr_from_c, socket_addr_to_c}; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ @@ -16,7 +17,7 @@ use crate::{cmp, mem, ptr, sys}; #[allow(non_camel_case_types)] pub type wrlen_t = i32; -pub mod netc { +pub(super) mod netc { //! BSD socket compatibility shim //! //! Some Windows API types are not quite what's expected by our cross-platform @@ -225,7 +226,7 @@ impl Socket { } pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { - let (addr, len) = addr.into_inner(); + let (addr, len) = socket_addr_to_c(addr); let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) }; cvt(result).map(drop) } @@ -401,12 +402,12 @@ impl Socket { let error = unsafe { c::WSAGetLastError() }; if error == c::WSAESHUTDOWN { - Ok((0, super::sockaddr_to_addr(&storage, addrlen as usize)?)) + Ok((0, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) } else { Err(io::Error::from_raw_os_error(error)) } } - _ => Ok((result as usize, super::sockaddr_to_addr(&storage, addrlen as usize)?)), + _ => Ok((result as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })), } } @@ -451,11 +452,11 @@ impl Socket { } None => 0, }; - super::setsockopt(self, c::SOL_SOCKET, kind, timeout) + setsockopt(self, c::SOL_SOCKET, kind, timeout) } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: u32 = super::getsockopt(self, c::SOL_SOCKET, kind)?; + let raw: u32 = getsockopt(self, c::SOL_SOCKET, kind)?; if raw == 0 { Ok(None) } else { @@ -488,26 +489,26 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as c_ushort, }; - super::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) + setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) } pub fn linger(&self) -> io::Result> { - let val: c::LINGER = super::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + let val: c::LINGER = getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - super::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) + setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) } pub fn nodelay(&self) -> io::Result { - let raw: c::BOOL = super::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; + let raw: c::BOOL = getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; Ok(raw != 0) } pub fn take_error(&self) -> io::Result> { - let raw: c_int = super::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; + let raw: c_int = getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 87e6106468fdb..da2174396266f 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -332,38 +332,3 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost { 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/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index 87e6106468fdb..da2174396266f 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -332,38 +332,3 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost { 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/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index 27e3a528af497..951dc65e5b47d 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -505,38 +505,3 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost { 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/connection/xous/mod.rs b/library/std/src/sys/net/connection/xous/mod.rs index 3e18ed24208d3..e44a375b9e3c5 100644 --- a/library/std/src/sys/net/connection/xous/mod.rs +++ b/library/std/src/sys/net/connection/xous/mod.rs @@ -46,38 +46,3 @@ pub struct GetAddress { } pub use dns::LookupHost; - -#[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, - } -} From d3e0d5cc8a37fb401b7c8bd95c9bac27f6ec53fa Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:24:48 +0100 Subject: [PATCH 13/17] Update books --- src/doc/book | 2 +- src/doc/reference | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book b/src/doc/book index e2fa4316c5a7c..d4d2c18cbd208 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit e2fa4316c5a7c0d2499c5d6b799adcfad6ef7a45 +Subproject commit d4d2c18cbd20876b2130a546e790446a8444cb32 diff --git a/src/doc/reference b/src/doc/reference index de2d5289e4550..6195dbd70fc6f 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit de2d5289e45506b11dd652bef4f99de64be70e1c +Subproject commit 6195dbd70fc6f0980c314b4d23875ac570d8253a From 54f59c6ddaafa1b6eb285af0957afa88e2d8e9e8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Feb 2025 15:47:18 +0100 Subject: [PATCH 14/17] Correctly escape hashtags when running `invalid_rust_codeblocks` lint --- src/librustdoc/doctest.rs | 1 + src/librustdoc/html/markdown.rs | 8 +++++--- src/librustdoc/passes/lint/check_code_block_syntax.rs | 7 ++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 8b522e614b813..4a379b4235ff0 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -786,6 +786,7 @@ impl IndividualTestOptions { /// [`clean`]: crate::clean /// [`run_merged_tests`]: crate::doctest::runner::DocTestRunner::run_merged_tests /// [`generate_unique_doctest`]: crate::doctest::make::DocTestBuilder::generate_unique_doctest +#[derive(Debug)] pub(crate) struct ScrapedDocTest { filename: FileName, line: usize, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7e835585b73e8..cb4896f167ab3 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -140,7 +140,7 @@ impl ErrorCodes { /// Controls whether a line will be hidden or shown in HTML output. /// /// All lines are used in documentation tests. -enum Line<'a> { +pub(crate) enum Line<'a> { Hidden(&'a str), Shown(Cow<'a, str>), } @@ -153,7 +153,7 @@ impl<'a> Line<'a> { } } - fn for_code(self) -> Cow<'a, str> { + pub(crate) fn for_code(self) -> Cow<'a, str> { match self { Line::Shown(l) => l, Line::Hidden(l) => Cow::Borrowed(l), @@ -161,12 +161,14 @@ impl<'a> Line<'a> { } } +/// This function is used to handle the "hidden lines" (ie starting with `#`) in +/// doctests. It also transforms `##` back into `#`. // FIXME: There is a minor inconsistency here. For lines that start with ##, we // have no easy way of removing a potential single space after the hashes, which // is done in the single # case. This inconsistency seems okay, if non-ideal. In // order to fix it we'd have to iterate to find the first non-# character, and // then reallocate to remove it; which would make us return a String. -fn map_line(s: &str) -> Line<'_> { +pub(crate) fn map_line(s: &str) -> Line<'_> { let trimmed = s.trim(); if trimmed.starts_with("##") { Line::Shown(Cow::Owned(s.replacen("##", "#", 1))) diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 459bdd991db46..9662dd85d678b 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -1,5 +1,6 @@ //! Validates syntax inside Rust code blocks (\`\`\`rust). +use std::borrow::Cow; use std::sync::Arc; use rustc_data_structures::sync::Lock; @@ -43,7 +44,11 @@ fn check_rust_syntax( let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); - let source = dox[code_block.code].to_owned(); + let source = dox[code_block.code] + .lines() + .map(|line| crate::html::markdown::map_line(line).for_code()) + .intersperse(Cow::Borrowed("\n")) + .collect::(); let psess = ParseSess::with_dcx(dcx, sm); let edition = code_block.lang_string.edition.unwrap_or_else(|| cx.tcx.sess.edition()); From 17cf100f11bc8e952d2d70f0953b83c971cd5873 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Feb 2025 15:58:07 +0100 Subject: [PATCH 15/17] Add regression test for #136899 --- tests/rustdoc-ui/hashtag-doctest.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/rustdoc-ui/hashtag-doctest.rs diff --git a/tests/rustdoc-ui/hashtag-doctest.rs b/tests/rustdoc-ui/hashtag-doctest.rs new file mode 100644 index 0000000000000..5f7456115305f --- /dev/null +++ b/tests/rustdoc-ui/hashtag-doctest.rs @@ -0,0 +1,17 @@ +// This test ensures that `##` are not emitting a warning when generating +// docs with the 2024 edition (or any edition). +// Regression test for . + +//@ check-pass +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +#![deny(warnings)] + +//! Test +//! +//! ``` +//! ##[allow(dead_code)] +//! println!("hello world"); +//! ``` From f8930b44a582d93f083b9da3f61f8f8b989999f2 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 12 Feb 2025 22:18:27 +0100 Subject: [PATCH 16/17] Add diagnostic item for `std::io::BufRead` This will be used in Clippy to detect unbuffered calls to `Read::bytes()`. --- compiler/rustc_span/src/symbol.rs | 1 + library/std/src/io/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bb59b4c40bd7f..9734926810ab2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -250,6 +250,7 @@ symbols! { Into, IntoFuture, IntoIterator, + IoBufRead, IoLines, IoRead, IoSeek, diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 0ffad2c27a4d5..980ea1478e084 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2249,6 +2249,7 @@ fn skip_until(r: &mut R, delim: u8) -> Result { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoBufRead")] pub trait BufRead: Read { /// Returns the contents of the internal buffer, filling it with more data /// from the inner reader if it is empty. From 8ccc33f18160cf67cbd87bf368d86331a368a8f2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 13 Feb 2025 08:42:36 +1100 Subject: [PATCH 17/17] Reinstate nnethercote in the review rotation. I'm back from vacation. --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index efd694994f9f7..cae504b55c0b4 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1041,7 +1041,6 @@ warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "jyn514", - "nnethercote", "workingjubilee", "kobzol", ]