From d411a0865556dfc154841c8c2e084f7d464998f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 26 Jul 2022 17:38:13 +0200 Subject: [PATCH 01/11] Htmldocck: Substitute the doc channel when blessing --- src/etc/htmldocck.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 70b6af717cd38..d02ac9d9c0ab7 100644 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -440,6 +440,7 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text): if bless: with open(snapshot_path, 'w') as snapshot_file: + actual_str = actual_str.replace(channel, "{{channel}}") snapshot_file.write(actual_str) else: print('--- expected ---\n') From 79e05430600dca42571ba38703af2969bab48760 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 26 Jul 2022 13:26:05 -0700 Subject: [PATCH 02/11] Use String::from_utf8_lossy in CStr demo --- library/core/src/ffi/c_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index ee9baf811e29c..1deb41593d97b 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -66,7 +66,7 @@ use crate::str; /// /// fn my_string_safe() -> String { /// unsafe { -/// CStr::from_ptr(my_string()).to_string_lossy().into_owned() +/// String::from_utf8_lossy(CStr::from_ptr(my_string())) /// } /// } /// From d48a869b9db1196214e19d1330cb290fc8543683 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 26 Jul 2022 14:10:26 -0700 Subject: [PATCH 03/11] Force the Cow into a String --- library/core/src/ffi/c_str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 1deb41593d97b..59066a33c965e 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -65,9 +65,9 @@ use crate::str; /// extern "C" { fn my_string() -> *const c_char; } /// /// fn my_string_safe() -> String { -/// unsafe { -/// String::from_utf8_lossy(CStr::from_ptr(my_string())) -/// } +/// let cstr = unsafe { CStr::from_ptr(my_string()) }; +/// // Get copy-on-write Cow<'_, str>, then guarantee a freshly-owned String allocation +/// String::from_utf8_lossy(cstr.to_bytes()).to_string() /// } /// /// println!("string: {}", my_string_safe()); From 645a88374a8b9e9eb9a5d69b404b91d6e9bfb620 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 27 Jul 2022 20:09:46 +0900 Subject: [PATCH 04/11] Update mentions to `rustc_metadata::rmeta::Lazy` Signed-off-by: Yuki Okushi --- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 18 +++++++++--------- compiler/rustc_metadata/src/rmeta/table.rs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8fa703a776075..6b0b5ac7da9a1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -83,7 +83,7 @@ pub(crate) struct CrateMetadata { // --- Some data pre-decoded from the metadata blob, usually for performance --- /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this - /// lifetime is only used behind `Lazy`, and therefore acts like a + /// lifetime is only used behind `LazyValue`, `LazyArray`, or `LazyTable`, and therefore acts like a /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt` /// is being used to decode those values. root: CrateRoot, diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0f291f9264777..23198a8536933 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -66,13 +66,13 @@ pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_V /// /// Metadata is effective a tree, encoded in post-order, /// and with the root's position written next to the header. -/// That means every single `Lazy` points to some previous +/// That means every single `LazyValue` points to some previous /// location in the metadata and is part of a larger node. /// -/// The first `Lazy` in a node is encoded as the backwards +/// The first `LazyValue` in a node is encoded as the backwards /// distance from the position where the containing node -/// starts and where the `Lazy` points to, while the rest -/// use the forward distance from the previous `Lazy`. +/// starts and where the `LazyValue` points to, while the rest +/// use the forward distance from the previous `LazyValue`. /// Distances start at 1, as 0-byte nodes are invalid. /// Also invalid are nodes being referred in a different /// order than they were encoded in. @@ -94,12 +94,12 @@ impl LazyValue { /// A list of lazily-decoded values. /// -/// Unlike `Lazy>`, the length is encoded next to the +/// Unlike `LazyValue>`, the length is encoded next to the /// position, not at the position, which means that the length /// doesn't need to be known before encoding all the elements. /// /// If the length is 0, no position is encoded, but otherwise, -/// the encoding is that of `Lazy`, with the distinction that +/// the encoding is that of `LazyArray`, with the distinction that /// the minimal distance the length of the sequence, i.e. /// it's assumed there's no 0-byte element in the sequence. struct LazyArray { @@ -167,17 +167,17 @@ impl Clone for LazyTable { } } -/// Encoding / decoding state for `Lazy`. +/// Encoding / decoding state for `Lazy`s (`LazyValue`, `LazyArray`, and `LazyTable`). #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum LazyState { /// Outside of a metadata node. NoNode, - /// Inside a metadata node, and before any `Lazy`. + /// Inside a metadata node, and before any `Lazy`s. /// The position is that of the node itself. NodeStart(NonZeroUsize), - /// Inside a metadata node, with a previous `Lazy`. + /// Inside a metadata node, with a previous `Lazy`s. /// The position is where that previous `Lazy` would start. Previous(NonZeroUsize), } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 42759f0a652b3..21841ae2532a7 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -141,7 +141,7 @@ fixed_size_enum! { } } -// We directly encode `DefPathHash` because a `Lazy` would encur a 25% cost. +// We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost. impl FixedSizeEncoding for Option { type ByteArray = [u8; 16]; @@ -159,7 +159,7 @@ impl FixedSizeEncoding for Option { } } -// We directly encode RawDefId because using a `Lazy` would incur a 50% overhead in the worst case. +// We directly encode RawDefId because using a `LazyValue` would incur a 50% overhead in the worst case. impl FixedSizeEncoding for Option { type ByteArray = [u8; 8]; From e849f9be59d7c21a65af7d5f655b1691f5da3870 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 26 Jul 2022 14:39:01 +0200 Subject: [PATCH 05/11] doc/rustc: describe the uefi target platforms Add a `platform-support` entry to the rustc-docs for the different `*-unknown-uefi` targets. This describes in detail how this platform works, a few basic examples, and how to compile for the platform. Red Hat is sponsoring my work on this platform, so I am putting myself down as target maintainer. Co-maintainers are more than welcome to join me in the effort. Communication is going on off-list to coordinate the different efforts. Note that the ultimate goal is to move the UEFI targets to Tier-2 so bootloaders can be more easily supported in commercial products. This documentation is the first step towards that goal, but should be a viable documentation even for the current Tier-3 status of the targets. I also want to point out that there is an ongoing GSoC-effort to port the rust standard library to UEFI (by Ayush Singh). While this work is not necessarily required to get to Tier-2, we definitely should coordinate the efforts and update the documentation as soon as any such ports are merged. Note that the targets are already used by multiple commercial and non commercial production systems, including, but not limited to: * Tianocore-EDK2 (Official UEFI SDK by Intel) comes with rust support in its staging repository (not part of any release, yet). (https://github.com/tianocore/edk2-staging/tree) * Intel's research program "Project Mu" uses the rust UEFI targets to show possible future replacements for Tianocore-EDK2. * The Rust OS "Redox" uses the UEFI targets for its bootloader. (https://www.redox-os.org/) * The hugely popular in-depth documentation of OS development in Rust by Philipp Oppermann uses the UEFI targets. (https://os.phil-opp.com/) Signed-off-by: David Rheinsberg --- src/doc/rustc/src/SUMMARY.md | 1 + .../src/platform-support/unknown-uefi.md | 254 ++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 src/doc/rustc/src/platform-support/unknown-uefi.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index f6348b2bddc88..736c30694cddb 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -28,6 +28,7 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [*-unknown-openbsd](platform-support/openbsd.md) + - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [Targets](targets/index.md) diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md new file mode 100644 index 0000000000000..8f90d9c7453d0 --- /dev/null +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -0,0 +1,254 @@ +# `*-unknown-uefi` + +**Tier: 3** + +Unified Extensible Firmware Interface (UEFI) targets for application, driver, +and core UEFI binaries. + +Available targets: + +- `aarch64-unknown-uefi` +- `i686-unknown-uefi` +- `x86_64-unknown-uefi` + +## Target maintainers + +- David Rheinsberg ([@dvdhrm](https://github.com/dvdhrm)) +- Nicholas Bishop ([@nicholasbishop](https://github.com/nicholasbishop)) + +## Requirements + +All UEFI targets can be used as `no-std` environments via cross-compilation. +Support for `std` is missing, but actively worked on. `alloc` is supported if +an allocator is provided by the user. No host tools are supported. + +The UEFI environment resembles the environment for Microsoft Windows, with some +minor differences. Therefore, cross-compiling for UEFI works with the same +tools as cross-compiling for Windows. The target binaries are PE32+ encoded, +the calling convention is different for each architecture, but matches what +Windows uses (if the architecture is supported by Windows). The special +`efiapi` Rust calling-convention chooses the right ABI for the target platform +(`extern "C"` is incorrect on Intel targets at least). The specification has an +elaborate section on the different supported calling-conventions, if more +details are desired. + +MMX, SSE, and other FP-units are disabled by default, to allow for compilation +of core UEFI code that runs before they are set up. This can be overridden for +individual compilations via rustc command-line flags. Not all firmwares +correctly configure those units, though, so careful inspection is required. + +As native to PE32+, binaries are position-dependent, but can be relocated at +runtime if their desired location is unavailable. The code must be statically +linked. Dynamic linking is not supported. Code is shared via UEFI interfaces, +rather than dynamic linking. Additionally, UEFI forbids running code on +anything but the boot CPU/thread, nor is interrupt-usage allowed (apart from +the timer interrupt). Device drivers are required to use polling methods. + +UEFI uses a single address-space to run all code in. Multiple applications can +be loaded simultaneously and are dispatched via cooperative multitasking on a +single stack. + +By default, the UEFI targets use the `link`-flavor of the LLVM linker `lld` to +link binaries into the final PE32+ file suffixed with `*.efi`. The PE subsystem +is set to `EFI_APPLICATION`, but can be modified by passing `/subsystem:<...>` +to the linker. Similarly, the entry-point is to to `efi_main` but can be +changed via `/entry:<...>`. The panic-strategy is set to `abort`, + +The UEFI specification is available online for free: +[UEFI Specification Directory](https://uefi.org/specifications) + +## Building rust for UEFI targets + +Rust can be built for the UEFI targets by enabling them in the `rustc` build +configuration. Note that you can only build the standard libraries. The +compiler and host tools currently cannot be compiled for UEFI targets. A sample +configuration would be: + +```toml +[build] +build-stage = 1 +target = ["x86_64-unknown-uefi"] +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building rust for UEFI targets" above), or build your own copy of `core` by +using `build-std`, `cargo-buildx`, or similar. + +A native build with the unstable `build-std`-feature can be achieved via: + +```sh +cargo +nightly build \ + -Zbuild-std=core,compiler_builtins \ + -Zbuild-std-features=compiler-builtins-mem \ + --target x86_64-unknown-uefi +``` + +Alternatively, you can install `cargo-xbuild` via +`cargo install --force cargo-xbuild` and build for the UEFI targets via: + +```sh +cargo \ + +nightly \ + xbuild \ + --target x86_64-unknown-uefi +``` + +## Testing + +UEFI applications can be copied into the ESP on any UEFI system and executed +via the firmware boot menu. The qemu suite allows emulating UEFI systems and +executing UEFI applications as well. See its documentation for details. + +The [uefi-run](https://github.com/Richard-W/uefi-run) rust tool is a simple +wrapper around `qemu` that can spawn UEFI applications in qemu. You can install +it via `cargo install uefi-run` and execute qemu applications as +`uefi-run ./application.efi`. + +## Cross-compilation toolchains and C code + +There are 3 common ways to compile native C code for UEFI targets: + +- Use the official SDK by Intel: + [Tianocore/EDK2](https://github.com/tianocore/edk2). This supports a + multitude of platforms, comes with the full specification transposed into C, + lots of examples and build-system integrations. This is also the only + officially supported platform by Intel, and is used by many major firmware + implementations. Any code compiled via the SDK is compatible to rust binaries + compiled for the UEFI targets. You can link them directly into your rust + binaries, or call into each other via UEFI protocols. +- Use the **GNU-EFI** suite. This approach is used by many UEFI applications + in the Linux/OSS ecosystem. The GCC compiler is used to compile ELF binaries, + and linked with a pre-loader that converts the ELF binary to PE32+ + **at runtime**. You can combine such binaries with the rust UEFI targets only + via UEFI protocols. Linking both into the same executable will fail, since + one is an ELF executable, and one a PE32+. If linking to **GNU-EFI** + executables is desired, you must compile your rust code natively for the same + GNU target as **GNU-EFI** and use their pre-loader. This requires careful + consideration about which calling-convention to use when calling into native + UEFI protocols, or calling into linked **GNU-EFI** code (similar to how these + differences need to be accounted for when writing **GNU-EFI** C code). +- Use native Windows targets. This means compiling your C code for the Windows + platform as if it was the UEFI platform. This works for static libraries, but + needs adjustments when linking into an UEFI executable. You can, however, + link such static libraries seemlessly into rust code compiled for UEFI + targets. Be wary of any includes that are not specifically suitable for UEFI + targets (especially the C standard library includes are not always + compatible). Freestanding compilations are recommended to avoid + incompatibilites. + +## Ecosystem + +The rust language has a long history of supporting UEFI targets. Many crates +have been developed to provide access to UEFI protocols and make UEFI +programming more ergonomic in rust. The following list is a short overview (in +alphabetical ordering): + +- **efi**: *Ergonomic Rust bindings for writing UEFI applications*. Provides + _rustified_ access to UEFI protocols, implements allocators and a safe + environment to write UEFI applications. +- **r-efi**: *UEFI Reference Specification Protocol Constants and Definitions*. + A pure transpose of the UEFI specification into rust. This provides the raw + definitions from the specification, without any extended helpers or + _rustification_. It serves as baseline to implement any more elaborate rust + UEFI layers. +- **uefi-rs**: *Safe and easy-to-use wrapper for building UEFI apps*. An + elaborate library providing safe abstractions for UEFI protocols and + features. It implements allocators and provides an execution environment to + UEFI applications written in rust. +- **uefi-run**: *Run UEFI applications*. A small wrapper around _qemu_ to spawn + UEFI applications in an emulated `x86_64` machine. + +## Example: Freestanding + +The following code is a valid UEFI application returning immediately upon +execution with an exit code of 0. A panic handler is provided. This is executed +by rust on panic. For simplicity, we simply end up in an infinite loop. + +Note that as of rust-1.31.0, all features used here are stabilized. No unstable +features are required, nor do we rely on nightly compilers. However, if you do +not compile rustc for the UEFI targets, you need a nightly compiler to support +the `-Z build-std` flag. + +This example can be compiled as binary crate via `cargo`: + +```sh +cargo +nightly build \ + -Zbuild-std=core,compiler_builtins \ + -Zbuild-std-features=compiler-builtins-mem \ + --target x86_64-unknown-uefi +``` + +```rust,ignore (platform-specific,eh-personality-is-unstable) +#![no_main] +#![no_std] + +#[panic_handler] +fn panic_handler(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[export_name = "efi_main"] +pub extern "C" fn main(_h: *mut core::ffi::c_void, _st: *mut core::ffi::c_void) -> usize { + 0 +} +``` + +## Example: Hello World + +This is an example UEFI application that prints "Hello World!", then waits for +key input before it exits. It serves as base example how to write UEFI +applications without any helper modules other than the standalone UEFI protocol +definitions provided by the `r-efi` crate. + +This extends the "Freestanding" example and builds upon its setup. See there +for instruction how to compile this as binary crate. + +Note that UEFI uses UTF-16 strings. Since rust literals are UTF-8, we have to +use an open-coded, zero-terminated, UTF-16 array as argument to +`output_string()`. Similarly to the panic handler, real applications should +rather use UTF-16 modules. + +```rust,ignore (platform-specific,eh-personality-is-unstable) +#![no_main] +#![no_std] + +use r_efi::efi; + +#[panic_handler] +fn panic_handler(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[export_name = "efi_main"] +pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status { + let s = [ + 0x0048u16, 0x0065u16, 0x006cu16, 0x006cu16, 0x006fu16, // "Hello" + 0x0020u16, // " " + 0x0057u16, 0x006fu16, 0x0072u16, 0x006cu16, 0x0064u16, // "World" + 0x0021u16, // "!" + 0x000au16, // "\n" + 0x0000u16, // NUL + ]; + + // Print "Hello World!". + let r = + unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16) }; + if r.is_error() { + return r; + } + + // Wait for key input, by waiting on the `wait_for_key` event hook. + let r = unsafe { + let mut x: usize = 0; + ((*(*st).boot_services).wait_for_event)(1, &mut (*(*st).con_in).wait_for_key, &mut x) + }; + if r.is_error() { + return r; + } + + efi::Status::SUCCESS +} +``` From 1e584d2d6dee2bc72509574974bf7be11a5924f0 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Sun, 24 Jul 2022 17:45:21 +0000 Subject: [PATCH 06/11] add suggestion when there is a impl of external trait on pointer Signed-off-by: Vincenzo Palazzo --- compiler/rustc_typeck/src/coherence/orphan.rs | 37 ++++++++++++++++++- .../issue-99572-impl-trait-on-pointer.rs | 25 +++++++++++++ .../issue-99572-impl-trait-on-pointer.stderr | 31 ++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/errors/issue-99572-impl-trait-on-pointer.rs create mode 100644 src/test/ui/errors/issue-99572-impl-trait-on-pointer.stderr diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 697ef7bc02237..1608550aa6ae4 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::subst::GenericArgKind; @@ -107,6 +107,7 @@ fn do_orphan_check_impl<'tcx>( Err(err) => emit_orphan_check_error( tcx, sp, + item.span, tr.path.span, trait_ref.self_ty(), impl_.self_ty.span, @@ -207,6 +208,7 @@ fn do_orphan_check_impl<'tcx>( fn emit_orphan_check_error<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, + full_impl_span: Span, trait_span: Span, self_ty: Ty<'tcx>, self_ty_span: Span, @@ -247,8 +249,20 @@ fn emit_orphan_check_error<'tcx>( ty::Slice(_) => (this, " because slices are always foreign"), ty::Array(..) => (this, " because arrays are always foreign"), ty::Tuple(..) => (this, " because tuples are always foreign"), + ty::RawPtr(ptr_ty) => { + emit_newtype_suggestion_for_raw_ptr( + full_impl_span, + self_ty, + self_ty_span, + ptr_ty, + &mut err, + ); + + (format!("`{}`", ty), " because raw pointers are always foreign") + } _ => (format!("`{}`", ty), ""), }; + let msg = format!("{} is not defined in the current crate{}", ty, postfix); if *is_target_ty { // Point at `D` in `impl for C in D` @@ -330,6 +344,27 @@ fn emit_orphan_check_error<'tcx>( }) } +fn emit_newtype_suggestion_for_raw_ptr( + full_impl_span: Span, + self_ty: Ty<'_>, + self_ty_span: Span, + ptr_ty: &ty::TypeAndMut<'_>, + diag: &mut Diagnostic, +) { + if !self_ty.needs_subst() { + let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" }; + let msg_sugg = "consider introducing a new wrapper type".to_owned(); + let sugg = vec![ + ( + full_impl_span.shrink_to_lo(), + format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty), + ), + (self_ty_span, "WrapperType".to_owned()), + ]; + diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect); + } +} + /// Lint impls of auto traits if they are likely to have /// unsound or surprising effects on auto impls. fn lint_auto_trait_impl<'tcx>( diff --git a/src/test/ui/errors/issue-99572-impl-trait-on-pointer.rs b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.rs new file mode 100644 index 0000000000000..272c6bd3fb782 --- /dev/null +++ b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.rs @@ -0,0 +1,25 @@ +// Emit additional suggestion to correct the trait implementation +// on a pointer +use std::{fmt, marker}; + +struct LocalType; + +impl fmt::Display for *mut LocalType { +//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types +//~| NOTE impl doesn't use only types from inside the current crate +//~| NOTE `*mut LocalType` is not defined in the current crate because raw pointers are always foreign +//~| NOTE define and implement a trait or new type instead +//~| HELP consider introducing a new wrapper type + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "This not compile") + } +} + +impl marker::Copy for *mut T { +//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types +//~| NOTE impl doesn't use only types from inside the current crate +//~| NOTE `*mut T` is not defined in the current crate because raw pointers are always foreign +//~| NOTE define and implement a trait or new type instead +} + +fn main() {} diff --git a/src/test/ui/errors/issue-99572-impl-trait-on-pointer.stderr b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.stderr new file mode 100644 index 0000000000000..78d7a47deaac3 --- /dev/null +++ b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.stderr @@ -0,0 +1,31 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/issue-99572-impl-trait-on-pointer.rs:7:1 + | +LL | impl fmt::Display for *mut LocalType { + | ^^^^^^^^^^^^^^^^^^^^^^-------------- + | | | + | | `*mut LocalType` is not defined in the current crate because raw pointers are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead +help: consider introducing a new wrapper type + | +LL + struct WrapperType(*mut LocalType); +LL + +LL ~ impl fmt::Display for WrapperType { + | + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/issue-99572-impl-trait-on-pointer.rs:18:1 + | +LL | impl marker::Copy for *mut T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^------ + | | | + | | `*mut T` is not defined in the current crate because raw pointers are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. From 957fe0ba61761bce555ccc2870fc46e79349d825 Mon Sep 17 00:00:00 2001 From: xtexChooser Date: Thu, 28 Jul 2022 17:21:04 +0800 Subject: [PATCH 07/11] Update custom.md --- src/doc/rustc/src/targets/custom.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md index 98e113a663b53..27ef2f49eee58 100644 --- a/src/doc/rustc/src/targets/custom.md +++ b/src/doc/rustc/src/targets/custom.md @@ -5,13 +5,13 @@ If you'd like to build for a target that is not yet supported by `rustc`, you ca are JSON. To see the JSON for the host target, you can run: ```bash -$ rustc +nightly -Z unstable-options --print target-spec-json +rustc +nightly -Z unstable-options --print target-spec-json ``` To see it for a different target, add the `--target` flag: ```bash -$ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json +rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json ``` To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) of `cargo`. From c2c70e20bcb03c15fb090d81cf8c19b52d4dec9b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Jul 2022 11:52:59 +0200 Subject: [PATCH 08/11] Remove Clean trait implementation for ty::Visibility --- src/librustdoc/clean/inline.rs | 7 ++++--- src/librustdoc/clean/mod.rs | 24 +++++++++++------------- src/librustdoc/clean/types.rs | 4 ++-- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4b91f7ba096cb..731d8766686c8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -17,7 +17,8 @@ use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, clean_ty, - clean_ty_generics, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility, + clean_ty_generics, clean_visibility, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, + Type, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -134,7 +135,7 @@ pub(crate) fn try_inline( ); if let Some(import_def_id) = import_def_id { // The visibility needs to reflect the one from the reexport and not from the "source" DefId. - item.visibility = cx.tcx.visibility(import_def_id).clean(cx); + item.visibility = clean_visibility(cx.tcx.visibility(import_def_id)); } ret.push(item); Some(ret) @@ -599,7 +600,7 @@ fn build_macro( match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) { LoadedMacro::MacroDef(item_def, _) => { if let ast::ItemKind::MacroDef(ref def) = item_def.kind { - let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id)).clean(cx); + let vis = clean_visibility(cx.tcx.visibility(import_def_id.unwrap_or(def_id))); clean::MacroItem(clean::Macro { source: utils::display_macro_source(cx, name, def, def_id, vis), }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2f3ca41723d85..43d424316ff6c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1817,17 +1817,15 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -impl<'tcx> Clean<'tcx, Visibility> for ty::Visibility { - fn clean(&self, _cx: &mut DocContext<'_>) -> Visibility { - match *self { - ty::Visibility::Public => Visibility::Public, - // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private', - // while rustdoc really does mean inherited. That means that for enum variants, such as - // `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc. - // Various parts of clean override `tcx.visibility` explicitly to make sure this distinction is captured. - ty::Visibility::Invisible => Visibility::Inherited, - ty::Visibility::Restricted(module) => Visibility::Restricted(module), - } +pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { + match vis { + ty::Visibility::Public => Visibility::Public, + // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private', + // while rustdoc really does mean inherited. That means that for enum variants, such as + // `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc. + // Various parts of clean override `tcx.visibility` explicitly to make sure this distinction is captured. + ty::Visibility::Invisible => Visibility::Inherited, + ty::Visibility::Restricted(module) => Visibility::Restricted(module), } } @@ -1988,7 +1986,7 @@ fn clean_maybe_renamed_item<'tcx>( clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } ItemKind::Macro(ref macro_def, _) => { - let ty_vis = cx.tcx.visibility(def_id).clean(cx); + let ty_vis = clean_visibility(cx.tcx.visibility(def_id)); MacroItem(Macro { source: display_macro_source(cx, name, macro_def, def_id, ty_vis), }) @@ -2117,7 +2115,7 @@ fn clean_extern_crate<'tcx>( name: Some(name), attrs: Box::new(attrs.clean(cx)), item_id: crate_def_id.into(), - visibility: ty_vis.clean(cx), + visibility: clean_visibility(ty_vis), kind: box ExternCrateItem { src: orig_name }, cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), }] diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 83d8ed3fc87fb..a5d27a940341a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -37,7 +37,7 @@ use crate::clean::cfg::Cfg; use crate::clean::external_path; use crate::clean::inline::{self, print_inlined_const}; use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const}; -use crate::clean::Clean; +use crate::clean::{clean_visibility, Clean}; use crate::core::DocContext; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -499,7 +499,7 @@ impl Item { let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) { Visibility::Public } else { - cx.tcx.visibility(def_id).clean(cx) + clean_visibility(cx.tcx.visibility(def_id)) }; Item { item_id: def_id.into(), kind: box kind, name, attrs, visibility, cfg } From 961dce44a9ee17fc931389dbc7a4b1ac6358be9e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Jul 2022 13:05:19 +0200 Subject: [PATCH 09/11] Remove Clean trait implementation for VariantStruct --- src/librustdoc/clean/mod.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 43d424316ff6c..fc795e12bbada 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1829,12 +1829,13 @@ pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { } } -impl<'tcx> Clean<'tcx, VariantStruct> for rustc_hir::VariantData<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> VariantStruct { - VariantStruct { - struct_type: CtorKind::from_hir(self), - fields: self.fields().iter().map(|x| clean_field(x, cx)).collect(), - } +fn clean_variant_data<'tcx>( + variant: &hir::VariantData<'tcx>, + cx: &mut DocContext<'tcx>, +) -> VariantStruct { + VariantStruct { + struct_type: CtorKind::from_hir(variant), + fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(), } } @@ -1866,7 +1867,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::VariantDef { impl<'tcx> Clean<'tcx, Variant> for hir::VariantData<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Variant { match self { - hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)), + hir::VariantData::Struct(..) => Variant::Struct(clean_variant_data(self, cx)), hir::VariantData::Tuple(..) => Variant::Tuple(self.clean(cx)), hir::VariantData::Unit(..) => Variant::CLike, } From 660dc6f393ed64b0fd007ac11a2dab445a28b9ed Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Jul 2022 13:08:08 +0200 Subject: [PATCH 10/11] Remove Clean trait implementation for VariantData fields --- src/librustdoc/clean/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fc795e12bbada..051f176294723 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1839,12 +1839,6 @@ fn clean_variant_data<'tcx>( } } -impl<'tcx> Clean<'tcx, Vec> for hir::VariantData<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Vec { - self.fields().iter().map(|x| clean_field(x, cx)).collect() - } -} - impl<'tcx> Clean<'tcx, Item> for ty::VariantDef { fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { let kind = match self.ctor_kind { @@ -1868,7 +1862,9 @@ impl<'tcx> Clean<'tcx, Variant> for hir::VariantData<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Variant { match self { hir::VariantData::Struct(..) => Variant::Struct(clean_variant_data(self, cx)), - hir::VariantData::Tuple(..) => Variant::Tuple(self.clean(cx)), + hir::VariantData::Tuple(..) => { + Variant::Tuple(self.fields().iter().map(|x| clean_field(x, cx)).collect()) + } hir::VariantData::Unit(..) => Variant::CLike, } } From e1e736b2a3fb1322a34387d251aa1a78f81be78b Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Jul 2022 21:40:33 +0200 Subject: [PATCH 11/11] Clone the `src/llvm-project` submodule if profiling is enabled To compile rustc with profiling information, `compiler-rt` from LLVM is required. Building it requires the `src/llvm-project` submodule to be initialized and updated. --- src/bootstrap/compile.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index aa7cda46bda69..dd2b9d59366ea 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -111,6 +111,11 @@ impl Step for Std { builder.update_submodule(&Path::new("library").join("stdarch")); + // Profiler information requires LLVM's compiler-rt + if builder.config.profiler { + builder.update_submodule(&Path::new("src/llvm-project")); + } + let mut target_deps = builder.ensure(StartupObjects { compiler, target }); let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);