about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs5
-rw-r--r--compiler/rustc_metadata/src/locator.rs91
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs4
-rw-r--r--library/Cargo.lock16
-rw-r--r--library/core/src/macros/mod.rs2
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/os/xous/ffi.rs2
-rw-r--r--library/std/src/sys/alloc/xous.rs3
-rw-r--r--library/std/src/sys/pal/xous/args.rs53
-rw-r--r--library/std/src/sys/pal/xous/mod.rs1
-rw-r--r--library/std/src/sys/pal/xous/net/dns.rs1
-rw-r--r--library/std/src/sys/pal/xous/net/mod.rs2
-rw-r--r--library/std/src/sys/pal/xous/os.rs136
-rw-r--r--library/std/src/sys/pal/xous/os/params.rs271
-rw-r--r--library/std/src/sys/pal/xous/os/params/tests.rs75
-rw-r--r--library/unwind/Cargo.toml2
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.rs51
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.stdout4
-rw-r--r--tests/ui/impl-trait/unsized_coercion5.next.stderr14
-rw-r--r--tests/ui/impl-trait/unsized_coercion5.old.stderr18
-rw-r--r--tests/ui/impl-trait/unsized_coercion5.rs2
-rw-r--r--tests/ui/traits/dyn-drop-principal.rs68
-rw-r--r--tests/ui/traits/dyn-drop-principal.run.stdout4
-rw-r--r--tests/ui/traits/dyn-star-drop-principal.rs12
-rw-r--r--tests/ui/traits/dyn-star-drop-principal.stderr11
28 files changed, 738 insertions, 121 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 5c297ebfadb..336934354e1 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -34,7 +34,9 @@ pub(crate) fn unsized_info<'tcx>(
         {
             let old_info =
                 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
-            if data_a.principal_def_id() == data_b.principal_def_id() {
+            let b_principal_def_id = data_b.principal_def_id();
+            if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
+                // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
                 debug_assert!(
                     validate_trivial_unsize(fx.tcx, data_a, data_b),
                     "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index d91c0f0790d..f3d9a7d37e6 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -147,7 +147,7 @@ pub fn validate_trivial_unsize<'tcx>(
                 infcx.leak_check(universe, None).is_ok()
             })
         }
-        (None, None) => true,
+        (_, None) => true,
         _ => false,
     }
 }
@@ -175,7 +175,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         {
             let old_info =
                 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
-            if data_a.principal_def_id() == data_b.principal_def_id() {
+            let b_principal_def_id = data_b.principal_def_id();
+            if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
                 // Codegen takes advantage of the additional assumption, where if the
                 // principal trait def id of what's being casted doesn't change,
                 // then we don't need to adjust the vtable at all. This
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 99c673b021a..a4a69ae9514 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -499,8 +499,11 @@ impl<'a> CrateLocator<'a> {
         dylibs: FxIndexMap<PathBuf, PathKind>,
     ) -> Result<Option<(Svh, Library)>, CrateError> {
         let mut slot = None;
-        // Order here matters, rmeta should come first. See comment in
-        // `extract_one` below.
+        // Order here matters, rmeta should come first.
+        //
+        // Make sure there's at most one rlib and at most one dylib.
+        //
+        // See comment in `extract_one` below.
         let source = CrateSource {
             rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
             rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
@@ -706,54 +709,58 @@ impl<'a> CrateLocator<'a> {
         let mut rmetas = FxIndexMap::default();
         let mut dylibs = FxIndexMap::default();
         for loc in &self.exact_paths {
-            if !loc.canonicalized().exists() {
-                return Err(CrateError::ExternLocationNotExist(
-                    self.crate_name,
-                    loc.original().clone(),
-                ));
+            let loc_canon = loc.canonicalized();
+            let loc_orig = loc.original();
+            if !loc_canon.exists() {
+                return Err(CrateError::ExternLocationNotExist(self.crate_name, loc_orig.clone()));
             }
-            if !loc.original().is_file() {
-                return Err(CrateError::ExternLocationNotFile(
-                    self.crate_name,
-                    loc.original().clone(),
-                ));
+            if !loc_orig.is_file() {
+                return Err(CrateError::ExternLocationNotFile(self.crate_name, loc_orig.clone()));
             }
-            let Some(file) = loc.original().file_name().and_then(|s| s.to_str()) else {
-                return Err(CrateError::ExternLocationNotFile(
-                    self.crate_name,
-                    loc.original().clone(),
-                ));
+            // Note to take care and match against the non-canonicalized name:
+            // some systems save build artifacts into content-addressed stores
+            // that do not preserve extensions, and then link to them using
+            // e.g. symbolic links. If we canonicalize too early, we resolve
+            // the symlink, the file type is lost and we might treat rlibs and
+            // rmetas as dylibs.
+            let Some(file) = loc_orig.file_name().and_then(|s| s.to_str()) else {
+                return Err(CrateError::ExternLocationNotFile(self.crate_name, loc_orig.clone()));
             };
-
-            if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
-                || file.starts_with(self.target.dll_prefix.as_ref())
-                    && file.ends_with(self.target.dll_suffix.as_ref())
-            {
-                // Make sure there's at most one rlib and at most one dylib.
-                // Note to take care and match against the non-canonicalized name:
-                // some systems save build artifacts into content-addressed stores
-                // that do not preserve extensions, and then link to them using
-                // e.g. symbolic links. If we canonicalize too early, we resolve
-                // the symlink, the file type is lost and we might treat rlibs and
-                // rmetas as dylibs.
-                let loc_canon = loc.canonicalized().clone();
-                let loc = loc.original();
-                if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
-                    rlibs.insert(loc_canon, PathKind::ExternFlag);
-                } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
-                    rmetas.insert(loc_canon, PathKind::ExternFlag);
-                } else {
-                    dylibs.insert(loc_canon, PathKind::ExternFlag);
+            // FnMut cannot return reference to captured value, so references
+            // must be taken outside the closure.
+            let rlibs = &mut rlibs;
+            let rmetas = &mut rmetas;
+            let dylibs = &mut dylibs;
+            let type_via_filename = (|| {
+                if file.starts_with("lib") {
+                    if file.ends_with(".rlib") {
+                        return Some(rlibs);
+                    }
+                    if file.ends_with(".rmeta") {
+                        return Some(rmetas);
+                    }
+                }
+                let dll_prefix = self.target.dll_prefix.as_ref();
+                let dll_suffix = self.target.dll_suffix.as_ref();
+                if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) {
+                    return Some(dylibs);
+                }
+                None
+            })();
+            match type_via_filename {
+                Some(type_via_filename) => {
+                    type_via_filename.insert(loc_canon.clone(), PathKind::ExternFlag);
+                }
+                None => {
+                    self.crate_rejections
+                        .via_filename
+                        .push(CrateMismatch { path: loc_orig.clone(), got: String::new() });
                 }
-            } else {
-                self.crate_rejections
-                    .via_filename
-                    .push(CrateMismatch { path: loc.original().clone(), got: String::new() });
             }
         }
 
         // Extract the dylib/rlib/rmeta triple.
-        Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib))
+        self.extract_lib(rlibs, rmetas, dylibs).map(|opt| opt.map(|(_, lib)| lib))
     }
 
     pub(crate) fn into_error(self, root: Option<CratePaths>) -> CrateError {
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 5828b2ecf34..2cbed0bceb2 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -785,7 +785,8 @@ where
         let mut responses = vec![];
         // If the principal def ids match (or are both none), then we're not doing
         // trait upcasting. We're just removing auto traits (or shortening the lifetime).
-        if a_data.principal_def_id() == b_data.principal_def_id() {
+        let b_principal_def_id = b_data.principal_def_id();
+        if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
             responses.extend(self.consider_builtin_upcast_to_principal(
                 goal,
                 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
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 52048ca79f9..aa313a526c1 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -1018,7 +1018,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // #2 (region bounds).
                 let principal_def_id_a = a_data.principal_def_id();
                 let principal_def_id_b = b_data.principal_def_id();
-                if principal_def_id_a == principal_def_id_b {
+                if principal_def_id_a == principal_def_id_b || principal_def_id_b.is_none() {
                     // We may upcast to auto traits that are either explicitly listed in
                     // the object type's bounds, or implied by the principal trait ref's
                     // supertraits.
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index cc5c7532b50..0ba3b4e6e55 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1153,6 +1153,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
                 let iter = data_a
                     .principal()
+                    .filter(|_| {
+                        // optionally drop the principal, if we're unsizing to no principal
+                        data_b.principal().is_some()
+                    })
                     .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
                     .into_iter()
                     .chain(
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 59b76d8d442..ed9e7dddf52 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
@@ -124,9 +124,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.30.0"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -158,9 +158,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.159"
+version = "0.2.161"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -406,12 +406,12 @@ dependencies = [
 
 [[package]]
 name = "unwinding"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882"
+checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987"
 dependencies = [
  "compiler_builtins",
- "gimli 0.30.0",
+ "gimli 0.31.1",
  "rustc-std-workspace-core",
 ]
 
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 6a4f2af10ef..771c2d31b60 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1550,7 +1550,7 @@ pub(crate) mod builtin {
     /// MODE is any of Forward, Reverse, ForwardFirst, ReverseFirst.
     /// INPUT_ACTIVITIES consists of one valid activity for each input parameter.
     /// OUTPUT_ACTIVITY must not be set if we implicitely return nothing (or explicitely return
-    /// `-> ()`. Otherwise it must be set to one of the allowed activities.
+    /// `-> ()`). Otherwise it must be set to one of the allowed activities.
     #[unstable(feature = "autodiff", issue = "124509")]
     #[allow_internal_unstable(rustc_attrs)]
     #[rustc_builtin_macro]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 358bd25ff1b..5f8dcde189b 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -39,7 +39,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
 addr2line = { version = "0.22.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.159", default-features = false, features = [
+libc = { version = "0.2.161", default-features = false, features = [
     'rustc-dep-of-std',
 ], public = true }
 
diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs
index 1a4a940bf35..1db314e9dda 100644
--- a/library/std/src/os/xous/ffi.rs
+++ b/library/std/src/os/xous/ffi.rs
@@ -615,7 +615,7 @@ pub(crate) fn thread_id() -> Result<ThreadId, Error> {
 /// An error is generated if the `knob` is not a valid limit, or if the call
 /// would not succeed.
 pub(crate) fn adjust_limit(knob: Limits, current: usize, new: usize) -> Result<usize, Error> {
-    let mut a0 = Syscall::JoinThread as usize;
+    let mut a0 = Syscall::AdjustProcessLimit as usize;
     let mut a1 = knob as usize;
     let a2 = current;
     let a3 = new;
diff --git a/library/std/src/sys/alloc/xous.rs b/library/std/src/sys/alloc/xous.rs
index 9ea43445d02..321d30e0b11 100644
--- a/library/std/src/sys/alloc/xous.rs
+++ b/library/std/src/sys/alloc/xous.rs
@@ -1,3 +1,6 @@
+// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
+#![allow(static_mut_refs)]
+
 use crate::alloc::{GlobalAlloc, Layout, System};
 
 #[cfg(not(test))]
diff --git a/library/std/src/sys/pal/xous/args.rs b/library/std/src/sys/pal/xous/args.rs
new file mode 100644
index 00000000000..00c44ca220a
--- /dev/null
+++ b/library/std/src/sys/pal/xous/args.rs
@@ -0,0 +1,53 @@
+use crate::ffi::OsString;
+use crate::sys::pal::xous::os::get_application_parameters;
+use crate::sys::pal::xous::os::params::ArgumentList;
+use crate::{fmt, vec};
+
+pub struct Args {
+    parsed_args_list: vec::IntoIter<OsString>,
+}
+
+pub fn args() -> Args {
+    let Some(params) = get_application_parameters() else {
+        return Args { parsed_args_list: vec![].into_iter() };
+    };
+
+    for param in params {
+        if let Ok(args) = ArgumentList::try_from(&param) {
+            let mut parsed_args = vec![];
+            for arg in args {
+                parsed_args.push(arg.into());
+            }
+            return Args { parsed_args_list: parsed_args.into_iter() };
+        }
+    }
+    Args { parsed_args_list: vec![].into_iter() }
+}
+
+impl fmt::Debug for Args {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.parsed_args_list.as_slice().fmt(f)
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        self.parsed_args_list.next()
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.parsed_args_list.size_hint()
+    }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        self.parsed_args_list.next_back()
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize {
+        self.parsed_args_list.len()
+    }
+}
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index b211e94db65..a64cd068560 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -1,6 +1,5 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-#[path = "../unsupported/args.rs"]
 pub mod args;
 #[path = "../unsupported/env.rs"]
 pub mod env;
diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/pal/xous/net/dns.rs
index d0083c61837..1a2b56b4da5 100644
--- a/library/std/src/sys/pal/xous/net/dns.rs
+++ b/library/std/src/sys/pal/xous/net/dns.rs
@@ -6,6 +6,7 @@ use crate::os::xous::ffi::lend_mut;
 use crate::os::xous::services::{DnsLendMut, dns_server};
 
 pub struct DnsError {
+    #[allow(dead_code)]
     pub code: u8,
 }
 
diff --git a/library/std/src/sys/pal/xous/net/mod.rs b/library/std/src/sys/pal/xous/net/mod.rs
index dd8b765aa74..3e18ed24208 100644
--- a/library/std/src/sys/pal/xous/net/mod.rs
+++ b/library/std/src/sys/pal/xous/net/mod.rs
@@ -60,6 +60,7 @@ pub mod netc {
 
     #[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,
@@ -72,6 +73,7 @@ pub mod netc {
 
     #[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,
diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs
index 8f8f35428c4..b0ab01a6383 100644
--- a/library/std/src/sys/pal/xous/os.rs
+++ b/library/std/src/sys/pal/xous/os.rs
@@ -1,29 +1,35 @@
 use super::unsupported;
+use crate::collections::HashMap;
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::os::xous::ffi::Error as XousError;
 use crate::path::{self, PathBuf};
-use crate::{fmt, io};
+use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
+use crate::sync::{Mutex, Once};
+use crate::{fmt, io, vec};
+
+pub(crate) mod params;
+
+static PARAMS_ADDRESS: AtomicPtr<u8> = AtomicPtr::new(core::ptr::null_mut());
 
 #[cfg(not(test))]
 #[cfg(feature = "panic_unwind")]
 mod eh_unwinding {
-    pub(crate) struct EhFrameFinder(usize /* eh_frame */);
-    pub(crate) static mut EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder(0);
-    impl EhFrameFinder {
-        pub(crate) unsafe fn init(&mut self, eh_frame: usize) {
-            unsafe {
-                EH_FRAME_SETTINGS.0 = eh_frame;
-            }
-        }
-    }
+    pub(crate) struct EhFrameFinder;
+    pub(crate) static mut EH_FRAME_ADDRESS: usize = 0;
+    pub(crate) static EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder;
+
     unsafe impl unwind::EhFrameFinder for EhFrameFinder {
         fn find(&self, _pc: usize) -> Option<unwind::FrameInfo> {
-            Some(unwind::FrameInfo {
-                text_base: None,
-                kind: unwind::FrameInfoKind::EhFrame(self.0),
-            })
+            if unsafe { EH_FRAME_ADDRESS == 0 } {
+                None
+            } else {
+                Some(unwind::FrameInfo {
+                    text_base: None,
+                    kind: unwind::FrameInfoKind::EhFrame(unsafe { EH_FRAME_ADDRESS }),
+                })
+            }
         }
     }
 }
@@ -41,12 +47,21 @@ mod c_compat {
     }
 
     #[no_mangle]
-    pub extern "C" fn _start(eh_frame: usize) {
+    pub extern "C" fn _start(eh_frame: usize, params_address: usize) {
         #[cfg(feature = "panic_unwind")]
-        unsafe {
-            super::eh_unwinding::EH_FRAME_SETTINGS.init(eh_frame);
+        {
+            unsafe { super::eh_unwinding::EH_FRAME_ADDRESS = eh_frame };
             unwind::set_custom_eh_frame_finder(&super::eh_unwinding::EH_FRAME_SETTINGS).ok();
         }
+
+        if params_address != 0 {
+            let params_address = crate::ptr::with_exposed_provenance_mut::<u8>(params_address);
+            if unsafe {
+                super::params::ApplicationParameters::new_from_ptr(params_address).is_some()
+            } {
+                super::PARAMS_ADDRESS.store(params_address, core::sync::atomic::Ordering::Relaxed);
+            }
+        }
         exit(unsafe { main() });
     }
 
@@ -116,44 +131,103 @@ pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
 }
 
-pub struct Env(!);
+pub(crate) fn get_application_parameters() -> Option<params::ApplicationParameters> {
+    let params_address = PARAMS_ADDRESS.load(Ordering::Relaxed);
+    unsafe { params::ApplicationParameters::new_from_ptr(params_address) }
+}
+
+// ---------- Environment handling ---------- //
+static ENV: AtomicUsize = AtomicUsize::new(0);
+static ENV_INIT: Once = Once::new();
+type EnvStore = Mutex<HashMap<OsString, OsString>>;
+
+fn get_env_store() -> &'static EnvStore {
+    ENV_INIT.call_once(|| {
+        let env_store = EnvStore::default();
+        if let Some(params) = get_application_parameters() {
+            for param in params {
+                if let Ok(envs) = params::EnvironmentBlock::try_from(&param) {
+                    let mut env_store = env_store.lock().unwrap();
+                    for env in envs {
+                        env_store.insert(env.key.into(), env.value.into());
+                    }
+                    break;
+                }
+            }
+        }
+        ENV.store(Box::into_raw(Box::new(env_store)) as _, Ordering::Relaxed)
+    });
+    unsafe { &*core::ptr::with_exposed_provenance::<EnvStore>(ENV.load(Ordering::Relaxed)) }
+}
+
+pub struct Env {
+    iter: vec::IntoIter<(OsString, OsString)>,
+}
+
+// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
+pub struct EnvStrDebug<'a> {
+    slice: &'a [(OsString, OsString)],
+}
+
+impl fmt::Debug for EnvStrDebug<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self { slice } = self;
+        f.debug_list()
+            .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
+            .finish()
+    }
+}
 
 impl Env {
     // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
     pub fn str_debug(&self) -> impl fmt::Debug + '_ {
-        let Self(inner) = self;
-        match *inner {}
+        let Self { iter } = self;
+        EnvStrDebug { slice: iter.as_slice() }
     }
 }
 
 impl fmt::Debug for Env {
-    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let Self(inner) = self;
-        match *inner {}
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self { iter } = self;
+        f.debug_list().entries(iter.as_slice()).finish()
     }
 }
 
+impl !Send for Env {}
+impl !Sync for Env {}
+
 impl Iterator for Env {
     type Item = (OsString, OsString);
     fn next(&mut self) -> Option<(OsString, OsString)> {
-        self.0
+        self.iter.next()
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
     }
 }
 
 pub fn env() -> Env {
-    panic!("not supported on this platform")
+    let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> {
+        map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
+    };
+
+    let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter();
+    Env { iter }
 }
 
-pub fn getenv(_: &OsStr) -> Option<OsString> {
-    None
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    get_env_store().lock().unwrap().get(k).cloned()
 }
 
-pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
-    Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
+pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+    let (k, v) = (k.to_owned(), v.to_owned());
+    get_env_store().lock().unwrap().insert(k, v);
+    Ok(())
 }
 
-pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> {
-    Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
+pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> {
+    get_env_store().lock().unwrap().remove(k);
+    Ok(())
 }
 
 pub fn temp_dir() -> PathBuf {
diff --git a/library/std/src/sys/pal/xous/os/params.rs b/library/std/src/sys/pal/xous/os/params.rs
new file mode 100644
index 00000000000..0d02cf35477
--- /dev/null
+++ b/library/std/src/sys/pal/xous/os/params.rs
@@ -0,0 +1,271 @@
+/// Xous passes a pointer to the parameter block as the second argument.
+/// This is used for passing flags such as environment variables. The
+/// format of the argument block is:
+///
+/// #[repr(C)]
+/// struct BlockHeader {
+///     /// Magic number that identifies this block. Must be printable ASCII.
+///     magic: [u8; 4],
+///
+///     /// The size of the data block. Does not include this header. May be 0.
+///     size: u32,
+///
+///     /// The contents of this block. Varies depending on the block type.
+///     data: [u8; 0],
+/// }
+///
+/// There is a BlockHeader at the start that has magic `AppP`, and the data
+/// that follows is the number of blocks present:
+///
+/// #[repr(C)]
+/// struct ApplicationParameters {
+///     magic: b"AppP",
+///     size: 4u32,
+///
+///     /// The size of the entire application slice, in bytes, including all headers
+///     length: u32,
+///
+///     /// Number of application parameters present. Must be at least 1 (this block)
+///     entries: (parameter_count as u32).to_bytes_le(),
+/// }
+///
+/// #[repr(C)]
+/// struct EnvironmentBlock {
+///     magic: b"EnvB",
+///
+///     /// Total number of bytes, excluding this header
+///     size: 2+data.len(),
+///
+///     /// The number of environment variables
+///     count: u16,
+///
+///     /// Environment variable iteration
+///     data: [u8; 0],
+/// }
+///
+/// Environment variables are present in an `EnvB` block. The `data` section is
+/// a sequence of bytes of the form:
+///
+///      (u16 /* key_len */; [0u8; key_len as usize] /* key */,
+///       u16 /* val_len */ [0u8; val_len as usize])
+///
+/// #[repr(C)]
+/// struct ArgumentList {
+///     magic: b"ArgL",
+///
+///     /// Total number of bytes, excluding this header
+///     size: 2+data.len(),
+///
+///     /// The number of arguments variables
+///     count: u16,
+///
+///     /// Argument variable iteration
+///     data: [u8; 0],
+/// }
+///
+/// Args are just an array of strings that represent command line arguments.
+/// They are a sequence of the form:
+///
+///      (u16 /* val_len */ [0u8; val_len as usize])
+use core::slice;
+
+use crate::ffi::OsString;
+
+/// Magic number indicating we have an environment block
+const ENV_MAGIC: [u8; 4] = *b"EnvB";
+
+/// Command line arguments list
+const ARGS_MAGIC: [u8; 4] = *b"ArgL";
+
+/// Magic number indicating the loader has passed application parameters
+const PARAMS_MAGIC: [u8; 4] = *b"AppP";
+
+#[cfg(test)]
+mod tests;
+
+pub(crate) struct ApplicationParameters {
+    data: &'static [u8],
+    offset: usize,
+    _entries: usize,
+}
+
+impl ApplicationParameters {
+    pub(crate) unsafe fn new_from_ptr(data: *const u8) -> Option<ApplicationParameters> {
+        if data.is_null() {
+            return None;
+        }
+
+        let magic = unsafe { core::slice::from_raw_parts(data, 4) };
+        let block_length = unsafe {
+            u32::from_le_bytes(slice::from_raw_parts(data.add(4), 4).try_into().ok()?) as usize
+        };
+        let data_length = unsafe {
+            u32::from_le_bytes(slice::from_raw_parts(data.add(8), 4).try_into().ok()?) as usize
+        };
+        let entries = unsafe {
+            u32::from_le_bytes(slice::from_raw_parts(data.add(12), 4).try_into().ok()?) as usize
+        };
+
+        // Check for the main header
+        if data_length < 16 || magic != PARAMS_MAGIC || block_length != 8 {
+            return None;
+        }
+
+        let data = unsafe { slice::from_raw_parts(data, data_length) };
+
+        Some(ApplicationParameters { data, offset: 0, _entries: entries })
+    }
+}
+
+impl Iterator for ApplicationParameters {
+    type Item = ApplicationParameter;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // Fetch magic, ensuring we don't run off the end
+        if self.offset + 4 > self.data.len() {
+            return None;
+        }
+        let magic = &self.data[self.offset..self.offset + 4];
+        self.offset += 4;
+
+        // Fetch header size
+        if self.offset + 4 > self.data.len() {
+            return None;
+        }
+        let size = u32::from_le_bytes(self.data[self.offset..self.offset + 4].try_into().unwrap())
+            as usize;
+        self.offset += 4;
+
+        // Fetch data contents
+        if self.offset + size > self.data.len() {
+            return None;
+        }
+        let data = &self.data[self.offset..self.offset + size];
+        self.offset += size;
+
+        Some(ApplicationParameter { data, magic: magic.try_into().unwrap() })
+    }
+}
+
+pub(crate) struct ApplicationParameter {
+    data: &'static [u8],
+    magic: [u8; 4],
+}
+
+pub(crate) struct ApplicationParameterError;
+
+pub(crate) struct EnvironmentBlock {
+    _count: usize,
+    data: &'static [u8],
+    offset: usize,
+}
+
+impl TryFrom<&ApplicationParameter> for EnvironmentBlock {
+    type Error = ApplicationParameterError;
+
+    fn try_from(value: &ApplicationParameter) -> Result<Self, Self::Error> {
+        if value.data.len() < 2 || value.magic != ENV_MAGIC {
+            return Err(ApplicationParameterError);
+        }
+
+        let count = u16::from_le_bytes(value.data[0..2].try_into().unwrap()) as usize;
+
+        Ok(EnvironmentBlock { data: &value.data[2..], offset: 0, _count: count })
+    }
+}
+
+pub(crate) struct EnvironmentEntry {
+    pub key: &'static str,
+    pub value: &'static str,
+}
+
+impl Iterator for EnvironmentBlock {
+    type Item = EnvironmentEntry;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.offset + 2 > self.data.len() {
+            return None;
+        }
+        let key_len =
+            u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize;
+        self.offset += 2;
+
+        if self.offset + key_len > self.data.len() {
+            return None;
+        }
+        let key = core::str::from_utf8(&self.data[self.offset..self.offset + key_len]).ok()?;
+        self.offset += key_len;
+
+        if self.offset + 2 > self.data.len() {
+            return None;
+        }
+        let value_len =
+            u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize;
+        self.offset += 2;
+
+        if self.offset + value_len > self.data.len() {
+            return None;
+        }
+        let value = core::str::from_utf8(&self.data[self.offset..self.offset + value_len]).ok()?;
+        self.offset += value_len;
+
+        Some(EnvironmentEntry { key, value })
+    }
+}
+
+pub(crate) struct ArgumentList {
+    data: &'static [u8],
+    _count: usize,
+    offset: usize,
+}
+
+impl TryFrom<&ApplicationParameter> for ArgumentList {
+    type Error = ApplicationParameterError;
+
+    fn try_from(value: &ApplicationParameter) -> Result<Self, Self::Error> {
+        if value.data.len() < 2 || value.magic != ARGS_MAGIC {
+            return Err(ApplicationParameterError);
+        }
+        let count =
+            u16::from_le_bytes(value.data[0..2].try_into().or(Err(ApplicationParameterError))?)
+                as usize;
+        Ok(ArgumentList { data: &value.data[2..], _count: count, offset: 0 })
+    }
+}
+
+pub(crate) struct ArgumentEntry {
+    value: &'static str,
+}
+
+impl Into<&str> for ArgumentEntry {
+    fn into(self) -> &'static str {
+        self.value
+    }
+}
+
+impl Into<OsString> for ArgumentEntry {
+    fn into(self) -> OsString {
+        self.value.into()
+    }
+}
+
+impl Iterator for ArgumentList {
+    type Item = ArgumentEntry;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.offset + 2 > self.data.len() {
+            return None;
+        }
+        let value_len =
+            u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize;
+        self.offset += 2;
+
+        if self.offset + value_len > self.data.len() {
+            return None;
+        }
+        let value = core::str::from_utf8(&self.data[self.offset..self.offset + value_len]).ok()?;
+        self.offset += value_len;
+
+        Some(ArgumentEntry { value })
+    }
+}
diff --git a/library/std/src/sys/pal/xous/os/params/tests.rs b/library/std/src/sys/pal/xous/os/params/tests.rs
new file mode 100644
index 00000000000..0ef04ee3091
--- /dev/null
+++ b/library/std/src/sys/pal/xous/os/params/tests.rs
@@ -0,0 +1,75 @@
+use super::*;
+use crate::collections::HashMap;
+use crate::io::Write;
+
+fn create_args_test() -> std::io::Result<Vec<u8>> {
+    let mut sample_data = vec![];
+    let mut h = HashMap::new();
+
+    h.insert("foo", "bar");
+    h.insert("baz", "qux");
+    h.insert("some", "val");
+
+    // Magic number
+    sample_data.write_all(&PARAMS_MAGIC)?;
+    // Size of the AppP block
+    sample_data.write_all(&4u32.to_le_bytes())?;
+    // Number of blocks
+    sample_data.write_all(&2u32.to_le_bytes())?;
+
+    // Magic number
+    sample_data.write_all(&ENV_MAGIC)?;
+    let mut data = vec![];
+    for (key, value) in h.iter() {
+        data.extend_from_slice(&(key.len() as u16).to_le_bytes());
+        data.extend_from_slice(key.as_bytes());
+        data.extend_from_slice(&(value.len() as u16).to_le_bytes());
+        data.extend_from_slice(value.as_bytes());
+    }
+    // Size of the EnvB block
+    sample_data.write_all(&(data.len() as u32 + 2).to_le_bytes())?;
+
+    // Number of environment variables
+    sample_data.write_all(&(h.len() as u16).to_le_bytes())?;
+
+    // Environment variables
+    sample_data.write_all(&data)?;
+
+    // Write command line arguments
+    let args = vec!["some", "command", "line variable", "entries"];
+    sample_data.write_all(&ARGS_MAGIC)?;
+    let mut args_size = 0;
+    for entry in args.iter() {
+        args_size += entry.len() + 2;
+    }
+    sample_data.write_all(&(args_size as u32 + 2).to_le_bytes())?;
+    sample_data.write_all(&(args.len() as u16).to_le_bytes())?;
+    for entry in args {
+        sample_data.write_all(&(entry.len() as u16).to_le_bytes())?;
+        sample_data.write_all(entry.as_bytes())?;
+    }
+
+    Ok(sample_data)
+}
+
+#[test]
+fn basic_arg_parsing() {
+    let arg_data = create_args_test().expect("couldn't create test data");
+    for byte in &arg_data {
+        print!("{:02x} ", byte);
+    }
+    println!();
+
+    let args = ApplicationParameters::new(&arg_data).expect("Unable to parse arguments");
+    for arg in args {
+        if let Ok(env) = EnvironmentBlock::try_from(&arg) {
+            for env in env {
+                println!("{}={}", env.key, env.value);
+            }
+        } else if let Ok(args) = ArgumentList::try_from(&arg) {
+            for arg in args {
+                println!("Arg: {}", arg.value);
+            }
+        }
+    }
+}
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index 590de31a678..569a1b3299e 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -22,7 +22,7 @@ cfg-if = "1.0"
 libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false }
 
 [target.'cfg(target_os = "xous")'.dependencies]
-unwinding = { version = "0.2.1", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }
+unwinding = { version = "0.2.3", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }
 
 [features]
 
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index ff995f38196..306e9ab9c67 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -9,6 +9,7 @@ fn main() {
     struct_();
     replace_vptr();
     vtable_nop_cast();
+    drop_principal();
 }
 
 fn vtable_nop_cast() {
@@ -430,3 +431,53 @@ fn replace_vptr() {
     let s = S(42);
     invoke_outer(&s);
 }
+
+fn drop_principal() {
+    use std::{alloc::Layout, any::Any};
+
+    const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
+        x
+    }
+
+    trait Bar: Send + Sync {}
+
+    impl<T: Send + Sync> Bar for T {}
+
+    const fn yeet_principal_2(x: Box<dyn Bar>) -> Box<dyn Send> {
+        x
+    }
+
+    struct CallMe<F: FnOnce()>(Option<F>);
+
+    impl<F: FnOnce()> CallMe<F> {
+        fn new(f: F) -> Self {
+            CallMe(Some(f))
+        }
+    }
+
+    impl<F: FnOnce()> Drop for CallMe<F> {
+        fn drop(&mut self) {
+            (self.0.take().unwrap())();
+        }
+    }
+
+    fn goodbye() {
+        println!("goodbye");
+    }
+
+    let x = Box::new(CallMe::new(goodbye)) as Box<dyn Any + Send>;
+    let x_layout = Layout::for_value(&*x);
+    let y = yeet_principal(x);
+    let y_layout = Layout::for_value(&*y);
+    assert_eq!(x_layout, y_layout);
+    println!("before");
+    drop(y);
+
+    let x = Box::new(CallMe::new(goodbye)) as Box<dyn Bar>;
+    let x_layout = Layout::for_value(&*x);
+    let y = yeet_principal_2(x);
+    let y_layout = Layout::for_value(&*y);
+    assert_eq!(x_layout, y_layout);
+    println!("before");
+    drop(y);
+}
diff --git a/src/tools/miri/tests/pass/dyn-upcast.stdout b/src/tools/miri/tests/pass/dyn-upcast.stdout
new file mode 100644
index 00000000000..edd99a114a1
--- /dev/null
+++ b/src/tools/miri/tests/pass/dyn-upcast.stdout
@@ -0,0 +1,4 @@
+before
+goodbye
+before
+goodbye
diff --git a/tests/ui/impl-trait/unsized_coercion5.next.stderr b/tests/ui/impl-trait/unsized_coercion5.next.stderr
deleted file mode 100644
index 5644ac7ab04..00000000000
--- a/tests/ui/impl-trait/unsized_coercion5.next.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/unsized_coercion5.rs:16:32
-   |
-LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
-   |                -------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Send`, found trait `Trait + Send`
-   |                |
-   |                expected due to this
-   |
-   = note: expected struct `Box<dyn Send>`
-              found struct `Box<dyn Trait + Send>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/unsized_coercion5.old.stderr b/tests/ui/impl-trait/unsized_coercion5.old.stderr
index 06ad54b1f1d..e56c026b037 100644
--- a/tests/ui/impl-trait/unsized_coercion5.old.stderr
+++ b/tests/ui/impl-trait/unsized_coercion5.old.stderr
@@ -1,16 +1,5 @@
-error[E0308]: mismatched types
-  --> $DIR/unsized_coercion5.rs:16:32
-   |
-LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
-   |                -------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Send`, found trait `Trait + Send`
-   |                |
-   |                expected due to this
-   |
-   = note: expected struct `Box<dyn Send>`
-              found struct `Box<dyn Trait + Send>`
-
 error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
-  --> $DIR/unsized_coercion5.rs:16:32
+  --> $DIR/unsized_coercion5.rs:17:32
    |
 LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
    |                                ^ doesn't have a size known at compile-time
@@ -18,7 +7,6 @@ LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
    = help: the trait `Sized` is not implemented for `impl Trait + ?Sized`
    = note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Trait + Send>`
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/unsized_coercion5.rs b/tests/ui/impl-trait/unsized_coercion5.rs
index 85d313caa13..81f8a6afe9a 100644
--- a/tests/ui/impl-trait/unsized_coercion5.rs
+++ b/tests/ui/impl-trait/unsized_coercion5.rs
@@ -3,6 +3,7 @@
 
 //@ revisions: next old
 //@[next] compile-flags: -Znext-solver
+//@[next] check-pass
 
 #![feature(trait_upcasting)]
 
@@ -15,7 +16,6 @@ fn hello() -> Box<impl Trait + ?Sized> {
         let x = hello();
         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
         //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know
-        //~^^ ERROR: mismatched types
     }
     Box::new(1u32)
 }
diff --git a/tests/ui/traits/dyn-drop-principal.rs b/tests/ui/traits/dyn-drop-principal.rs
new file mode 100644
index 00000000000..c233127e43d
--- /dev/null
+++ b/tests/ui/traits/dyn-drop-principal.rs
@@ -0,0 +1,68 @@
+//@ run-pass
+//@ check-run-results
+
+use std::{alloc::Layout, any::Any};
+
+const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
+    x
+}
+
+trait Bar: Send + Sync {}
+
+impl<T: Send + Sync> Bar for T {}
+
+const fn yeet_principal_2(x: Box<dyn Bar>) -> Box<dyn Send> {
+    x
+}
+
+struct CallMe<F: FnOnce()>(Option<F>);
+
+impl<F: FnOnce()> CallMe<F> {
+    fn new(f: F) -> Self {
+        CallMe(Some(f))
+    }
+}
+
+impl<F: FnOnce()> Drop for CallMe<F> {
+    fn drop(&mut self) {
+        (self.0.take().unwrap())();
+    }
+}
+
+fn goodbye() {
+    println!("goodbye");
+}
+
+fn main() {
+    let x = Box::new(CallMe::new(goodbye)) as Box<dyn Any + Send>;
+    let x_layout = Layout::for_value(&*x);
+    let y = yeet_principal(x);
+    let y_layout = Layout::for_value(&*y);
+    assert_eq!(x_layout, y_layout);
+    println!("before");
+    drop(y);
+
+    let x = Box::new(CallMe::new(goodbye)) as Box<dyn Bar>;
+    let x_layout = Layout::for_value(&*x);
+    let y = yeet_principal_2(x);
+    let y_layout = Layout::for_value(&*y);
+    assert_eq!(x_layout, y_layout);
+    println!("before");
+    drop(y);
+}
+
+// Test that upcast works in `const`
+
+const fn yeet_principal_3(x: &(dyn Any + Send + Sync)) -> &(dyn Send + Sync) {
+    x
+}
+
+#[used]
+pub static FOO: &(dyn Send + Sync) = yeet_principal_3(&false);
+
+const fn yeet_principal_4(x: &dyn Bar) -> &(dyn Send + Sync) {
+    x
+}
+
+#[used]
+pub static BAR: &(dyn Send + Sync) = yeet_principal_4(&false);
diff --git a/tests/ui/traits/dyn-drop-principal.run.stdout b/tests/ui/traits/dyn-drop-principal.run.stdout
new file mode 100644
index 00000000000..edd99a114a1
--- /dev/null
+++ b/tests/ui/traits/dyn-drop-principal.run.stdout
@@ -0,0 +1,4 @@
+before
+goodbye
+before
+goodbye
diff --git a/tests/ui/traits/dyn-star-drop-principal.rs b/tests/ui/traits/dyn-star-drop-principal.rs
new file mode 100644
index 00000000000..1ad99070339
--- /dev/null
+++ b/tests/ui/traits/dyn-star-drop-principal.rs
@@ -0,0 +1,12 @@
+#![feature(dyn_star)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+impl Trait for usize {}
+
+fn main() {
+    // We allow &dyn Trait + Send -> &dyn Send (i.e. dropping principal),
+    // but we don't (currently?) allow the same for dyn*
+    let x: dyn* Trait + Send = 1usize;
+    x as dyn* Send; //~ error: `dyn* Trait + Send` needs to have the same ABI as a pointer
+}
diff --git a/tests/ui/traits/dyn-star-drop-principal.stderr b/tests/ui/traits/dyn-star-drop-principal.stderr
new file mode 100644
index 00000000000..721ae7e191e
--- /dev/null
+++ b/tests/ui/traits/dyn-star-drop-principal.stderr
@@ -0,0 +1,11 @@
+error[E0277]: `dyn* Trait + Send` needs to have the same ABI as a pointer
+  --> $DIR/dyn-star-drop-principal.rs:11:5
+   |
+LL |     x as dyn* Send;
+   |     ^ `dyn* Trait + Send` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `dyn* Trait + Send`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.