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]; 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/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index ee9baf811e29c..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 { -/// CStr::from_ptr(my_string()).to_string_lossy().into_owned() -/// } +/// 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()); 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); 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 +} +``` 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`. 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') 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 2f2fbc9d4ba8d..624eec57e8324 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1812,32 +1812,25 @@ 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), - } - } -} - -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(), - } +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), } } -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() +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(), } } @@ -1863,8 +1856,10 @@ 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::Tuple(..) => Variant::Tuple(self.clean(cx)), + hir::VariantData::Struct(..) => Variant::Struct(clean_variant_data(self, cx)), + hir::VariantData::Tuple(..) => { + Variant::Tuple(self.fields().iter().map(|x| clean_field(x, cx)).collect()) + } hir::VariantData::Unit(..) => Variant::CLike, } } @@ -1983,7 +1978,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), }) @@ -2112,7 +2107,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 } 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`.