about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_attr_parsing/src/interface.rs9
-rw-r--r--compiler/rustc_attr_parsing/src/target_checking.rs37
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs7
-rw-r--r--compiler/rustc_data_structures/Cargo.toml4
-rw-r--r--compiler/rustc_lexer/Cargo.toml6
-rw-r--r--compiler/rustc_target/Cargo.toml7
-rw-r--r--library/std/src/sys/fs/mod.rs13
-rw-r--r--tests/assembly-llvm/reg-struct-return.rs143
8 files changed, 179 insertions, 47 deletions
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index a3558850ef3..0fe3c209421 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -273,14 +273,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
                             (accept.accept_fn)(&mut cx, args);
                             if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
                                 Self::check_type(accept.attribute_type, target, &mut cx);
-                                self.check_target(
-                                    path.get_attribute_path(),
-                                    attr.span,
-                                    &accept.allowed_targets,
-                                    target,
-                                    target_id,
-                                    &mut emit_lint,
-                                );
+                                Self::check_target(&accept.allowed_targets, target, &mut cx);
                             }
                         }
                     } else {
diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs
index 6f4dd76fa81..edc496b460c 100644
--- a/compiler/rustc_attr_parsing/src/target_checking.rs
+++ b/compiler/rustc_attr_parsing/src/target_checking.rs
@@ -3,9 +3,8 @@ use std::borrow::Cow;
 use rustc_ast::AttrStyle;
 use rustc_errors::DiagArgValue;
 use rustc_feature::{AttributeType, Features};
-use rustc_hir::lints::{AttributeLint, AttributeLintKind};
-use rustc_hir::{AttrPath, MethodKind, Target};
-use rustc_span::Span;
+use rustc_hir::lints::AttributeLintKind;
+use rustc_hir::{MethodKind, Target};
 
 use crate::AttributeParser;
 use crate::context::{AcceptContext, Stage};
@@ -71,38 +70,34 @@ pub(crate) enum Policy {
 
 impl<'sess, S: Stage> AttributeParser<'sess, S> {
     pub(crate) fn check_target(
-        &self,
-        attr_name: AttrPath,
-        attr_span: Span,
         allowed_targets: &AllowedTargets,
         target: Target,
-        target_id: S::Id,
-        mut emit_lint: impl FnMut(AttributeLint<S::Id>),
+        cx: &mut AcceptContext<'_, 'sess, S>,
     ) {
         match allowed_targets.is_allowed(target) {
             AllowedResult::Allowed => {}
             AllowedResult::Warn => {
                 let allowed_targets = allowed_targets.allowed_targets();
-                let (applied, only) =
-                    allowed_targets_applied(allowed_targets, target, self.features);
-                emit_lint(AttributeLint {
-                    id: target_id,
-                    span: attr_span,
-                    kind: AttributeLintKind::InvalidTarget {
-                        name: attr_name,
+                let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
+                let name = cx.attr_path.clone();
+                let attr_span = cx.attr_span;
+                cx.emit_lint(
+                    AttributeLintKind::InvalidTarget {
+                        name,
                         target,
                         only: if only { "only " } else { "" },
                         applied,
                     },
-                });
+                    attr_span,
+                );
             }
             AllowedResult::Error => {
                 let allowed_targets = allowed_targets.allowed_targets();
-                let (applied, only) =
-                    allowed_targets_applied(allowed_targets, target, self.features);
-                self.dcx().emit_err(InvalidTarget {
-                    span: attr_span,
-                    name: attr_name,
+                let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
+                let name = cx.attr_path.clone();
+                cx.dcx().emit_err(InvalidTarget {
+                    span: cx.attr_span.clone(),
+                    name,
                     target: target.plural_name(),
                     only: if only { "only " } else { "" },
                     applied: DiagArgValue::StrListSepByAnd(
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 9f22859ba81..8586615f7c7 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1957,10 +1957,13 @@ impl<B: ExtraBackendMethods> Drop for Coordinator<B> {
 pub struct OngoingCodegen<B: ExtraBackendMethods> {
     pub backend: B,
     pub crate_info: CrateInfo,
-    pub codegen_worker_receive: Receiver<CguMessage>,
-    pub shared_emitter_main: SharedEmitterMain,
     pub output_filenames: Arc<OutputFilenames>,
+    // Field order below is intended to terminate the coordinator thread before two fields below
+    // drop and prematurely close channels used by coordinator thread. See `Coordinator`'s
+    // `Drop` implementation for more info.
     pub coordinator: Coordinator<B>,
+    pub codegen_worker_receive: Receiver<CguMessage>,
+    pub shared_emitter_main: SharedEmitterMain,
 }
 
 impl<B: ExtraBackendMethods> OngoingCodegen<B> {
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index aa964806a87..0ac9e02508a 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -13,6 +13,7 @@ ena = "0.14.3"
 indexmap = "2.4.0"
 jobserver_crate = { version = "0.1.28", package = "jobserver" }
 measureme = "12.0.1"
+parking_lot = "0.12"
 rustc-hash = "2.0.0"
 rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
 rustc_arena = { path = "../rustc_arena" }
@@ -34,9 +35,6 @@ version = "0.15.2"
 default-features = false
 features = ["nightly"] # for may_dangle
 
-[dependencies.parking_lot]
-version = "0.12"
-
 [target.'cfg(windows)'.dependencies.windows]
 version = "0.61.0"
 features = [
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index b46f395a132..e0019fb1821 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -15,12 +15,8 @@ Rust lexer used by rustc. No stability guarantees are provided.
 # Note that this crate purposefully does not depend on other rustc crates
 [dependencies]
 memchr.workspace = true
+unicode-properties = { version = "0.1.0", default-features = false, features = ["emoji"] }
 unicode-xid = "0.2.0"
 
-[dependencies.unicode-properties]
-version = "0.1.0"
-default-features = false
-features = ["emoji"]
-
 [dev-dependencies]
 expect-test = "1.4.0"
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 7ad2a332761..3c257bf38a5 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags.workspace = true
+object = { version = "0.37.0", default-features = false, features = ["elf", "macho"] }
 rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" }
@@ -20,9 +21,3 @@ serde_path_to_error = "0.1.17"
 tracing.workspace = true
 # tidy-alphabetical-end
 
-[dependencies.object]
-# tidy-alphabetical-start
-default-features = false
-features = ["elf", "macho"]
-version = "0.37.0"
-# tidy-alphabetical-end
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index dbd782f5018..0276bf6e64c 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -117,9 +117,18 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> {
 #[cfg(unix)]
 pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> {
     use crate::fs::OpenOptions;
-    use crate::os::unix::fs::OpenOptionsExt;
 
-    OpenOptions::new().custom_flags(libc::O_NOFOLLOW).open(path)?.set_permissions(perm)
+    let mut options = OpenOptions::new();
+
+    // ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it.
+    // Their filesystems do not have symbolic links, so no special handling is required.
+    #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
+    {
+        use crate::os::unix::fs::OpenOptionsExt;
+        options.custom_flags(libc::O_NOFOLLOW);
+    }
+
+    options.open(path)?.set_permissions(perm)
 }
 
 #[cfg(not(unix))]
diff --git a/tests/assembly-llvm/reg-struct-return.rs b/tests/assembly-llvm/reg-struct-return.rs
new file mode 100644
index 00000000000..b251d791d51
--- /dev/null
+++ b/tests/assembly-llvm/reg-struct-return.rs
@@ -0,0 +1,143 @@
+//! Tests that -Zreg-struct-return changes ABI for small struct returns
+//! from hidden-pointer convention to register-return on x86_32.
+//! This test covers:
+//! * Callee side, verifying that the structs are correctly loaded into registers when
+//!   `-Zreg-struct-return` is activated
+//! * Caller side, verifying callers do receive returned structs in registers when
+//!   `-Zreg-struct-return` is activated
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ compile-flags: -O --target=i686-unknown-linux-gnu -Crelocation-model=static
+//@ revisions: WITH WITHOUT
+//@[WITH] compile-flags: -Zreg-struct-return
+//@ needs-llvm-components: x86
+
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+// Verifies ABI changes for small structs, where both fields fit into one register.
+// WITH is expected to use register return, WITHOUT should use hidden pointer.
+mod Small {
+    struct SmallStruct {
+        a: i8,
+        b: i8,
+    }
+
+    unsafe extern "C" {
+        fn small() -> SmallStruct;
+    }
+
+    #[unsafe(no_mangle)]
+    pub unsafe extern "C" fn small_callee() -> SmallStruct {
+        // (42 << 8) | 42 = 10794
+
+        // WITH-LABEL: small_callee
+        // WITH: movw $10794, %ax
+        // WITH: retl
+
+        // WITHOUT-LABEL: small_callee
+        // WITHOUT: movl 4(%esp), %e{{.*}}
+        // WITHOUT: movw $10794, (%e{{.*}})
+        // WITHOUT: retl $4
+        SmallStruct { a: 42, b: 42 }
+    }
+
+    #[unsafe(no_mangle)]
+    pub unsafe extern "C" fn small_caller(dst: &mut SmallStruct) {
+        // WITH-LABEL: small_caller
+        // WITH: calll small
+        // WITH: movw %ax, (%e{{.*}})
+
+        // WITHOUT-LABEL: small_caller
+        // WITHOUT: calll small
+        // WITHOUT: movzwl {{.*}}(%esp), %e[[TMP:..]]
+        // WITHOUT: movw %[[TMP]], (%e{{..}})
+        *dst = small();
+    }
+}
+
+// Verifies ABI changes for a struct of size 8, which is the maximum size
+// for reg-struct-return.
+// WITH is expected to still use register return, WITHOUT should use hidden
+// pointer.
+mod Pivot {
+    struct PivotStruct {
+        a: i32,
+        b: i32,
+    }
+
+    unsafe extern "C" {
+        fn pivot() -> PivotStruct;
+    }
+
+    #[unsafe(no_mangle)]
+    pub unsafe extern "C" fn pivot_callee() -> PivotStruct {
+        // WITH-LABEL: pivot_callee
+        // WITH: movl $42, %e{{.*}}
+        // WITH: movl $42, %e{{.*}}
+        // WITH: retl
+
+        // WITHOUT-LABEL: pivot_callee
+        // WITHOUT: movl 4(%esp), %e{{.*}}
+        // WITHOUT-DAG: movl $42, (%e{{.*}})
+        // WITHOUT-DAG: movl $42, 4(%e{{.*}})
+        // WITHOUT: retl $4
+        PivotStruct { a: 42, b: 42 }
+    }
+
+    #[unsafe(no_mangle)]
+    pub unsafe extern "C" fn pivot_caller(dst: &mut PivotStruct) {
+        // WITH-LABEL: pivot_caller
+        // WITH: calll pivot
+        // WITH-DAG: movl %e{{.*}}, 4(%e{{.*}})
+        // WITH-DAG: movl %e{{.*}}, (%e{{.*}})
+
+        // WITHOUT-LABEL: pivot_caller
+        // WITHOUT: calll pivot
+        // WITHOUT: movsd {{.*}}(%esp), %[[TMP:xmm.]]
+        // WITHOUT: movsd %[[TMP]], (%e{{..}})
+        *dst = pivot();
+    }
+}
+
+// Verifies ABI changes for a struct of size 12, which is larger than the
+// maximum size for reg-struct-return (8 bytes).
+// Here, the hidden pointer convention should be used even when `-Zreg-struct-return` is set.
+mod Large {
+    struct LargeStruct {
+        a: i32,
+        b: i32,
+        c: i32,
+    }
+
+    unsafe extern "C" {
+        fn large() -> LargeStruct;
+    }
+
+    #[unsafe(no_mangle)]
+    pub unsafe extern "C" fn large_callee() -> LargeStruct {
+        // CHECK-LABEL: large_callee
+        // CHECK: movl 4(%esp), %e{{.*}}
+        // CHECK-DAG: movl $42, (%e{{.*}})
+        // CHECK-DAG: movl $42, 4(%e{{.*}})
+        // CHECK-DAG: movl $42, 8(%e{{.*}})
+        // CHECK: retl $4
+        LargeStruct { a: 42, b: 42, c: 42 }
+    }
+
+    #[unsafe(no_mangle)]
+    pub unsafe extern "C" fn large_caller(dst: &mut LargeStruct) {
+        // CHECK-LABEL: large_caller
+        // CHECK: calll large
+        // CHECK-DAG: movl   {{.*}}(%esp), %[[TMP1:e..]]
+        // CHECK-DAG: movl  %[[TMP1]], {{.*}}(%e{{..}})
+        // CHECK-DAG: movsd  {{.*}}(%esp), %[[TMP2:xmm.]]
+        // CHECK-DAG: movsd  %[[TMP2]], {{.*}}(%e{{..}})
+        *dst = large();
+    }
+}