From ac76882bf3ea97bc32f0381ab962782f5740074c Mon Sep 17 00:00:00 2001 From: Georgii Rylov Date: Wed, 23 Aug 2023 14:49:35 +0100 Subject: MCP661: Move wasm32-wasi-preview1-threads to Tier2 --- .../dist-various-2/build-wasi-threads-toolchain.sh | 2 +- .../dist-various-2/build-wasi-toolchain.sh | 2 +- src/doc/rustc/src/platform-support.md | 2 +- .../wasm32-wasi-preview1-threads.md | 33 ++++++++++++++-------- 4 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh index 7dae90f4403..689fe52863e 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh @@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 7018e24d8fe248596819d2e884761676f3542a04 +git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087 make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh index 45174e708dc..4b0d360686f 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh @@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 7018e24d8fe248596819d2e884761676f3542a04 +git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087 make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7cc17e11bdb..9684060498a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -179,6 +179,7 @@ target | std | notes `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI +[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads `x86_64-apple-ios` | ✓ | 64-bit x86 iOS [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia` @@ -321,7 +322,6 @@ target | std | host | notes `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL -[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS diff --git a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md index b3eb34de638..23b99924899 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md @@ -1,6 +1,6 @@ # `wasm32-wasi-preview1-threads` -**Tier: 3** +**Tier: 2** The `wasm32-wasi-preview1-threads` target is a new and still (as of July 2023) an experimental target. This target is an extension to `wasm32-wasi-preview1` target, @@ -70,12 +70,6 @@ compile `wasm32-wasi-preview1-threads` binaries straight out of the box. You can reliably interoperate with C code in this mode (yet). -This target is not a stable target. This means that there are not many engines -which implement the `wasi-threads` feature and if they do they're likely behind a -flag, for example: - -* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads` - Also note that at this time the `wasm32-wasi-preview1-threads` target assumes the presence of other merged wasm proposals such as (with their LLVM feature flags): @@ -94,6 +88,17 @@ The target intends to match the corresponding Clang target for its `"C"` ABI. > found it's recommended to open an issue either with rust-lang/rust or ideally > with LLVM itself. +## Platform requirements + +The runtime should support the same set of APIs as any other supported wasi target for interacting with the host environment through the WASI standard. The runtime also should have implemetation of [wasi-threads proposal](https://github.com/WebAssembly/wasi-threads). + +This target is not a stable target. This means that there are a few engines +which implement the `wasi-threads` feature and if they do they're likely behind a +flag, for example: + +* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads` +* [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) - needs to be built with WAMR_BUILD_LIB_WASI_THREADS=1 + ## Building the target Users need to install or built wasi-sdk since release 20.0 @@ -110,12 +115,16 @@ After that users can build this by adding it to the `target` list in ## Building Rust programs -Since it is Tier 3, rust doesn't ship pre-compiled artifacts for this target. +From Rust Nightly 1.71.1 (2023-08-03) on the artifacts are shipped pre-compiled: + +```text +rustup target add wasm32-wasi-preview1-threads --toolchain nightly +``` + +Rust programs can be built for that target: -Specify `wasi-root` as explained in the previous section and then use the `build-std` -nightly cargo feature to build the standard library: -```shell -cargo +nightly build --target=wasm32-wasi-preview1-threads -Zbuild-std +```text +rustc --target wasm32-wasi-preview1-threads your-code.rs ``` ## Cross-compilation -- cgit 1.4.1-3-g733a5 From 08cdb40219cc8ac2c60e24f1242ac5157c1436ee Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 16 Aug 2023 12:58:58 +0200 Subject: rustdoc: extract logic for printing enum fields and struct variants --- src/librustdoc/html/render/print_item.rs | 326 ++++++++++++++++++------------- 1 file changed, 195 insertions(+), 131 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cb78f903462..007c1cf1ef9 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1332,7 +1332,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { let tcx = cx.tcx(); let count_variants = e.variants().count(); - wrap_item(w, |mut w| { + wrap_item(w, |w| { render_attributes_in_code(w, it, tcx); write!( w, @@ -1341,148 +1341,179 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: it.name.unwrap(), e.generics.print(cx), ); - if !print_where_clause_and_check(w, &e.generics, cx) { - // If there wasn't a `where` clause, we add a whitespace. - w.write_str(" "); - } + render_enum_fields( + w, + cx, + Some(&e.generics), + e.variants(), + count_variants, + e.has_stripped_entries(), + it.is_non_exhaustive(), + ); + }); - let variants_stripped = e.has_stripped_entries(); - if count_variants == 0 && !variants_stripped { - w.write_str("{}"); - } else { - w.write_str("{\n"); - let toggle = should_hide_fields(count_variants); - if toggle { - toggle_open(&mut w, format_args!("{count_variants} variants")); - } - for v in e.variants() { - w.write_str(" "); - let name = v.name.unwrap(); - match *v.kind { - // FIXME(#101337): Show discriminant - clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => w.write_str(name.as_str()), - clean::VariantKind::Tuple(ref s) => { - write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); - } - clean::VariantKind::Struct(ref s) => { - render_struct(w, v, None, None, &s.fields, " ", false, cx); - } - }, - _ => unreachable!(), - } - w.write_str(",\n"); - } + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - if variants_stripped && !it.is_non_exhaustive() { - w.write_str(" // some variants omitted\n"); - } - if toggle { - toggle_close(&mut w); + if count_variants != 0 { + item_variants(w, cx, it, e.variants()); + } + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn render_enum_fields<'a>( + mut w: &mut Buffer, + cx: &mut Context<'_>, + g: Option<&clean::Generics>, + variants: impl Iterator, + count_variants: usize, + has_stripped_entries: bool, + is_non_exhaustive: bool, +) { + if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { + // If there wasn't a `where` clause, we add a whitespace. + w.write_str(" "); + } + + let variants_stripped = has_stripped_entries; + if count_variants == 0 && !variants_stripped { + w.write_str("{}"); + } else { + w.write_str("{\n"); + let toggle = should_hide_fields(count_variants); + if toggle { + toggle_open(&mut w, format_args!("{count_variants} variants")); + } + const TAB: &str = " "; + for v in variants { + w.write_str(TAB); + let name = v.name.unwrap(); + match *v.kind { + // FIXME(#101337): Show discriminant + clean::VariantItem(ref var) => match var.kind { + clean::VariantKind::CLike => w.write_str(name.as_str()), + clean::VariantKind::Tuple(ref s) => { + write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); + } + clean::VariantKind::Struct(ref s) => { + render_struct(w, v, None, None, &s.fields, TAB, false, cx); + } + }, + _ => unreachable!(), } - w.write_str("}"); + w.write_str(",\n"); } - }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + if variants_stripped && !is_non_exhaustive { + w.write_str(" // some variants omitted\n"); + } + if toggle { + toggle_close(&mut w); + } + w.write_str("}"); + } +} - if count_variants != 0 { +fn item_variants<'a>( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + variants: impl Iterator, +) { + let tcx = cx.tcx(); + write!( + w, + "

\ + Variants{}§\ +

\ + {}\ +
", + document_non_exhaustive_header(it), + document_non_exhaustive(it) + ); + for variant in variants { + let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); write!( w, - "

\ - Variants{}§\ -

\ - {}\ -
", - document_non_exhaustive_header(it), - document_non_exhaustive(it) + "
\ + §", ); - for variant in e.variants() { - let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "
\ - §", - ); - render_stability_since_raw_with_extra( - w, - variant.stable_since(tcx), - variant.const_stability(tcx), - it.stable_since(tcx), - it.const_stable_since(tcx), - " rightside", - ); - write!(w, "

{name}", name = variant.name.unwrap()); + render_stability_since_raw_with_extra( + w, + variant.stable_since(tcx), + variant.const_stability(tcx), + it.stable_since(tcx), + it.const_stable_since(tcx), + " rightside", + ); + write!(w, "

{name}", name = variant.name.unwrap()); - let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; + let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; - if let clean::VariantKind::Tuple(ref s) = variant_data.kind { - write!(w, "({})", print_tuple_struct_fields(cx, s)); - } - w.write_str("

"); - - let heading_and_fields = match &variant_data.kind { - clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), - clean::VariantKind::Tuple(fields) => { - // Documentation on tuple variant fields is rare, so to reduce noise we only emit - // the section if at least one field is documented. - if fields.iter().any(|f| !f.doc_value().is_empty()) { - Some(("Tuple Fields", fields)) - } else { - None - } + if let clean::VariantKind::Tuple(ref s) = variant_data.kind { + write!(w, "({})", print_tuple_struct_fields(cx, s)); + } + w.write_str("
"); + + let heading_and_fields = match &variant_data.kind { + clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), + clean::VariantKind::Tuple(fields) => { + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + if fields.iter().any(|f| !f.doc_value().is_empty()) { + Some(("Tuple Fields", fields)) + } else { + None } - clean::VariantKind::CLike => None, - }; + } + clean::VariantKind::CLike => None, + }; - if let Some((heading, fields)) = heading_and_fields { - let variant_id = - cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "
\ -

{heading}

\ - {}", - document_non_exhaustive(variant) - ); - for field in fields { - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(_)) => {} - clean::StructFieldItem(ref ty) => { - let id = cx.derive_id(format!( - "variant.{}.field.{}", - variant.name.unwrap(), - field.name.unwrap() - )); - write!( - w, - "
\ + if let Some((heading, fields)) = heading_and_fields { + let variant_id = + cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); + write!( + w, + "
\ +

{heading}

\ + {}", + document_non_exhaustive(variant) + ); + for field in fields { + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => {} + clean::StructFieldItem(ref ty) => { + let id = cx.derive_id(format!( + "variant.{}.field.{}", + variant.name.unwrap(), + field.name.unwrap() + )); + write!( + w, + "
\ \ §\ {f}: {t}\ ", - f = field.name.unwrap(), - t = ty.print(cx), - ); - write!( - w, - "{}
", - document(cx, field, Some(variant), HeadingOffset::H5) - ); - } - _ => unreachable!(), + f = field.name.unwrap(), + t = ty.print(cx), + ); + write!( + w, + "{}
", + document(cx, field, Some(variant), HeadingOffset::H5) + ); } + _ => unreachable!(), } - w.write_str("
"); } - - write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); + w.write_str("
"); } - write!(w, "
"); + + write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); + write!(w, "
"); } fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { @@ -1593,15 +1624,28 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - let mut fields = s - .fields + item_fields(w, cx, it, &s.fields, s.ctor_kind); + + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn item_fields( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + fields: &Vec, + ctor_kind: Option, +) { + let mut fields = fields .iter() .filter_map(|f| match *f.kind { clean::StructFieldItem(ref ty) => Some((f, ty)), _ => None, }) .peekable(); - if let None | Some(CtorKind::Fn) = s.ctor_kind { + if let None | Some(CtorKind::Fn) = ctor_kind { if fields.peek().is_some() { write!( w, @@ -1609,7 +1653,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean {}{}§\ \ {}", - if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, + if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, document_non_exhaustive_header(it), document_non_exhaustive(it) ); @@ -1630,9 +1674,6 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean } } } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); } fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { @@ -1871,7 +1912,7 @@ fn render_union<'a, 'cx: 'a>( } fn render_struct( - mut w: &mut Buffer, + w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, ty: Option, @@ -1891,6 +1932,29 @@ fn render_struct( if let Some(g) = g { write!(w, "{}", g.print(cx)) } + render_struct_fields( + w, + g, + ty, + fields, + tab, + structhead, + it.has_stripped_entries().unwrap_or(false), + cx, + ) +} + +fn render_struct_fields( + mut w: &mut Buffer, + g: Option<&clean::Generics>, + ty: Option, + fields: &[clean::Item], + tab: &str, + structhead: bool, + has_stripped_entries: bool, + cx: &Context<'_>, +) { + let tcx = cx.tcx(); match ty { None => { let where_displayed = @@ -1922,11 +1986,11 @@ fn render_struct( } if has_visible_fields { - if it.has_stripped_entries().unwrap() { + if has_stripped_entries { write!(w, "\n{tab} /* private fields */"); } write!(w, "\n{tab}"); - } else if it.has_stripped_entries().unwrap() { + } else if has_stripped_entries { write!(w, " /* private fields */ "); } if toggle { -- cgit 1.4.1-3-g733a5 From 19edb3ce808ee2b1190026b9d56cc6187e1ad9b1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 24 Aug 2023 20:44:32 -0700 Subject: rustdoc: list matching impls on type aliases Remake of "List matching impls on type aliases" * 4b1d13d9841c815915433ca2a3088a8e3e97ad96 * 6f552c800b38b3e71c5e33a295e8b490d2018c71 * 2ce7cd906bde70d8cbd9b07b31c6a7bf1131c345 Partially reverts "Fix infinite loop when retrieving impls for type alias", but keeps the test case. This version of the PR avoids the infinite loop by structurally matching types instead of using full unification. This version does not support type alias trait bounds, but the compiler does not enforce those anyway (https://github.com/rust-lang/rust/issues/21903). --- src/librustdoc/html/render/mod.rs | 47 +++++++++++++++++++-- tests/rustdoc/issue-32077-type-alias-impls.rs | 59 +++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc/issue-32077-type-alias-impls.rs (limited to 'src') diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index aef8f1a74fb..1d77ce74c80 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -54,6 +54,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::TyCtxt; use rustc_span::{ symbol::{sym, Symbol}, @@ -62,6 +63,7 @@ use rustc_span::{ use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Serialize, Serializer}; +use crate::clean::types::TypeAliasItem; use crate::clean::{self, ItemId, RenderedLink, SelfTy}; use crate::error::Error; use crate::formats::cache::Cache; @@ -1139,8 +1141,40 @@ fn render_assoc_items_inner( info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); let cache = &shared.cache; - let Some(v) = cache.impls.get(&it) else { return }; - let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); + let tcx = cx.tcx(); + let av = if let TypeAliasItem(ait) = &*containing_item.kind && + let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) && + let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) && + let Some(mut av) = cache.impls.get(&aliased_type_defid).cloned() && + let Some(alias_def_id) = containing_item.item_id.as_def_id() + { + // This branch of the compiler compares types structually, but does + // not check trait bounds. That's probably fine, since type aliases + // don't normally constrain on them anyway. + // https://github.com/rust-lang/rust/issues/21903 + // + // If that changes, then this will need to check them with type + // unification. + let aliased_ty = tcx.type_of(alias_def_id).skip_binder(); + let reject_cx = DeepRejectCtxt { + treat_obligation_params: TreatParams::AsCandidateKey, + }; + av.retain(|impl_| { + if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() { + reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder()) + } else { + false + } + }); + av + } else { + Vec::new() + }; + let blank = Vec::new(); + let v = cache.impls.get(&it).unwrap_or(&blank); + let (non_trait, traits): (Vec<_>, _) = + v.iter().chain(&av[..]).partition(|i| i.inner_impl().trait_.is_none()); + let mut saw_impls = FxHashSet::default(); if !non_trait.is_empty() { let mut tmp_buf = Buffer::html(); let (render_mode, id, class_html) = match what { @@ -1169,6 +1203,9 @@ fn render_assoc_items_inner( }; let mut impls_buf = Buffer::html(); for i in &non_trait { + if !saw_impls.insert(i.def_id()) { + continue; + } render_impl( &mut impls_buf, cx, @@ -1214,8 +1251,10 @@ fn render_assoc_items_inner( let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits.into_iter().partition(|t| t.inner_impl().kind.is_auto()); - let (blanket_impl, concrete): (Vec<&Impl>, _) = - concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); + let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete + .into_iter() + .filter(|t| saw_impls.insert(t.def_id())) + .partition(|t| t.inner_impl().kind.is_blanket()); render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl); } diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs new file mode 100644 index 00000000000..555d0579bee --- /dev/null +++ b/tests/rustdoc/issue-32077-type-alias-impls.rs @@ -0,0 +1,59 @@ +// Regression test for . + +#![crate_name = "foo"] + +pub struct GenericStruct(T); + +impl GenericStruct { + pub fn on_gen(arg: T) {} +} + +impl GenericStruct { + pub fn on_u32(arg: u32) {} +} + +pub trait Foo {} +pub trait Bar {} + +impl Foo for GenericStruct {} +impl Bar for GenericStruct {} + +// @has 'foo/type.TypedefStruct.html' +// We check that we have the implementation of the type alias itself. +// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct' +// @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()' +// @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl GenericStruct' +// @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)' +// @has - '//*[@id="impl-Foo-for-GenericStruct%3CT%3E"]/h3' 'impl Foo for GenericStruct' +// This trait implementation doesn't match the type alias parameters so shouldn't appear in docs. +// @!has - '//h3' 'impl Bar for GenericStruct {}' +// Same goes for the `Deref` impl. +// @!has - '//h2' 'Methods from Deref' +pub type TypedefStruct = GenericStruct; + +impl TypedefStruct { + pub fn on_alias() {} +} + +impl std::ops::Deref for GenericStruct { + type Target = u32; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub struct Wrap(GenericStruct); + +// @has 'foo/type.Alias.html' +// @has - '//h2' 'Methods from Deref' +// @has - '//*[@id="impl-Deref-for-Wrap%3CT%3E"]/h3' 'impl Deref for Wrap' +pub type Alias = Wrap; + +impl std::ops::Deref for Wrap { + type Target = GenericStruct; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} -- cgit 1.4.1-3-g733a5 From 2c35abe37c1e8fb51fa15892f59aaa248a768960 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 15 Aug 2023 14:13:17 +0200 Subject: rustdoc: show inner enum and struct in type definition for concrete type --- src/librustdoc/clean/inline.rs | 3 + src/librustdoc/clean/mod.rs | 116 +++++++++++++++++++++++++++++-- src/librustdoc/clean/types.rs | 21 ++++++ src/librustdoc/html/render/print_item.rs | 94 +++++++++++++++++++++++++ src/librustdoc/json/conversions.rs | 2 +- tests/rustdoc/typedef-inner-variants.rs | 80 +++++++++++++++++++++ 6 files changed, 311 insertions(+), 5 deletions(-) create mode 100644 tests/rustdoc/typedef-inner-variants.rs (limited to 'src') diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc86a3d7475..25f303d8a52 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -299,6 +299,9 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box( } } +fn clean_ty_alias_inner_type<'tcx>( + ty: Ty<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + let ty::Adt(adt_def, args) = ty.kind() else { + return None; + }; + + Some(if adt_def.is_enum() { + let variants: rustc_index::IndexVec<_, _> = adt_def + .variants() + .iter() + .map(|variant| clean_variant_def_with_args(variant, args, cx)) + .collect(); + + let has_stripped_variants = adt_def.variants().len() != variants.len(); + TypeAliasInnerType::Enum { + variants, + has_stripped_variants, + is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(), + } + } else { + let variant = adt_def + .variants() + .iter() + .next() + .unwrap_or_else(|| bug!("a struct or union should always have one variant def")); + + let fields: Vec<_> = + clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect(); + + let has_stripped_fields = variant.fields.len() != fields.len(); + if adt_def.is_struct() { + TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields, has_stripped_fields } + } else { + TypeAliasInnerType::Union { fields, has_stripped_fields } + } + }) +} + fn clean_proc_macro<'tcx>( item: &hir::Item<'tcx>, name: &mut Symbol, @@ -1222,6 +1263,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext Box::new(TypeAlias { type_: clean_ty(default, cx), generics, + inner_type: None, item_type: Some(item_type), }), bounds, @@ -1264,7 +1306,12 @@ pub(crate) fn clean_impl_item<'tcx>( None, ); AssocTypeItem( - Box::new(TypeAlias { type_, generics, item_type: Some(item_type) }), + Box::new(TypeAlias { + type_, + generics, + inner_type: None, + item_type: Some(item_type), + }), Vec::new(), ) } @@ -1471,6 +1518,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), bounds, @@ -1490,6 +1538,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), // Associated types inside trait or inherent impls are not allowed to have @@ -2350,6 +2399,60 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont ) } +pub(crate) fn clean_variant_def_with_args<'tcx>( + variant: &ty::VariantDef, + args: &GenericArgsRef<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Item { + let discriminant = match variant.discr { + ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }), + ty::VariantDiscr::Relative(_) => None, + }; + + let kind = match variant.ctor_kind() { + Some(CtorKind::Const) => VariantKind::CLike, + Some(CtorKind::Fn) => VariantKind::Tuple( + variant + .fields + .iter() + .filter(|field| field.vis.is_public()) + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + ), + None => VariantKind::Struct(VariantStruct { + fields: variant + .fields + .iter() + .filter(|field| field.vis.is_public()) + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + }), + }; + + Item::from_def_id_and_parts( + variant.def_id, + Some(variant.name), + VariantItem(Variant { kind, discriminant }), + cx, + ) +} + fn clean_variant_data<'tcx>( variant: &hir::VariantData<'tcx>, disr_expr: &Option, @@ -2604,7 +2707,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::TyAlias(hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; let rustdoc_ty = clean_ty(hir_ty, cx); - let ty = clean_middle_ty( + let type_ = clean_middle_ty( ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None, @@ -2617,10 +2720,15 @@ fn clean_maybe_renamed_item<'tcx>( cx.current_type_aliases.remove(&def_id); } } + + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + let inner_type = clean_ty_alias_inner_type(ty, cx); + TypeAliasItem(Box::new(TypeAlias { - type_: rustdoc_ty, generics, - item_type: Some(ty), + inner_type, + type_: rustdoc_ty, + item_type: Some(type_), })) } ItemKind::Enum(ref def, generics) => EnumItem(Enum { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9cf3c068b60..6efe4179707 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2229,10 +2229,31 @@ pub(crate) struct PathSegment { pub(crate) args: GenericArgs, } +#[derive(Clone, Debug)] +pub(crate) enum TypeAliasInnerType { + Enum { + variants: IndexVec, + has_stripped_variants: bool, + is_non_exhaustive: bool, + }, + Union { + fields: Vec, + has_stripped_fields: bool, + }, + Struct { + ctor_kind: Option, + fields: Vec, + has_stripped_fields: bool, + }, +} + #[derive(Clone, Debug)] pub(crate) struct TypeAlias { pub(crate) type_: Type, pub(crate) generics: Generics, + /// Inner `AdtDef` type, ie `type TyKind = IrTyKind`, + /// to be shown directly on the typedef page. + pub(crate) inner_type: Option, /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type /// alias instead of the final type. This will always have the final type, regardless of whether /// `type_` came from HIR or from metadata. diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 007c1cf1ef9..09be756f26d 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,6 +1237,100 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + // Only show inner variants if: + // - the typealias does NOT have any generics (modulo lifetimes) + // - AND the aliased type has some generics + // + // Otherwise, showing a non-generic type is rendurant with its own page, or + // if it still has some generics, it's not as useful. + let should_print_inner_type = t + .generics + .params + .iter() + .all(|param| matches!(param.kind, clean::GenericParamDefKind::Lifetime { .. })) + && t.generics.where_predicates.is_empty() + && t.type_.generics().is_some_and(|generics| !generics.is_empty()); + + if should_print_inner_type { + fn toggle(w: &mut W, f: F) + where + W: fmt::Write, + F: FnOnce(&mut W), + { + write!( + w, + "
\ + \ + Show Aliased Type\ + ", + ) + .unwrap(); + f(w); + write!(w, "
").unwrap(); + } + + match &t.inner_type { + Some(clean::TypeAliasInnerType::Enum { + variants, + has_stripped_variants: has_stripped_entries, + is_non_exhaustive, + }) => { + toggle(w, |w| { + wrap_item(w, |w| { + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); + render_enum_fields( + w, + cx, + None, + variants.iter(), + variants.len(), + *has_stripped_entries, + *is_non_exhaustive, + ) + }); + item_variants(w, cx, it, variants.iter()); + }); + } + Some(clean::TypeAliasInnerType::Union { fields, has_stripped_fields }) => { + toggle(w, |w| { + wrap_item(w, |w| { + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + None, + None, + fields, + "", + true, + *has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + }); + } + Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields, has_stripped_fields }) => { + toggle(w, |w| { + wrap_item(w, |w| { + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + None, + *ctor_kind, + fields, + "", + true, + *has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + }); + } + None => {} + } + } + let def_id = it.item_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 66b5798797f..406c7218f98 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -789,7 +789,7 @@ pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind impl FromWithTcx> for TypeAlias { fn from_tcx(type_alias: Box, tcx: TyCtxt<'_>) -> Self { - let clean::TypeAlias { type_, generics, item_type: _ } = *type_alias; + let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = *type_alias; TypeAlias { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) } } } diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs new file mode 100644 index 00000000000..e0c5b7dd98f --- /dev/null +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -0,0 +1,80 @@ +#![crate_name = "inner_variants"] + +pub struct Adt; +pub struct Ty; + +// @has 'inner_variants/type.AliasTy.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +pub type AliasTy = Ty; + +// @has 'inner_variants/enum.IrTyKind.html' +pub enum IrTyKind { + /// Doc comment for AdtKind + AdtKind(A), + /// and another one for TyKind + TyKind(A, B), + // no comment + StructKind { a: A, }, +} + +// @has 'inner_variants/type.NearlyTyKind.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +pub type NearlyTyKind = IrTyKind; + +// @has 'inner_variants/type.TyKind.html' +// @count - '//*[@id="variants"]' 1 +// @count - '//*[@id="fields"]' 0 +// @count - '//*[@class="variant"]' 3 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "enum TyKind" +pub type TyKind = IrTyKind; + +// @has 'inner_variants/union.OneOr.html' +pub union OneOr { + pub one: i64, + pub or: A, +} + +// @has 'inner_variants/type.OneOrF64.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//*[@class="structfield small-section-header"]' 2 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "union OneOrF64" +pub type OneOrF64 = OneOr; + +// @has 'inner_variants/struct.One.html' +pub struct One { + pub val: T, + __hidden: T, +} + +// @has 'inner_variants/type.OneU64.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//*[@class="structfield small-section-header"]' 1 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct OneU64" +pub type OneU64 = One; + +// @has 'inner_variants/struct.OnceA.html' +pub struct OnceA<'a, A> { + a: &'a A, // private +} + +// @has 'inner_variants/type.Once.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct Once<'a>" +pub type Once<'a> = OnceA<'a, i64>; + +// @has 'inner_variants/struct.HighlyGenericStruct.html' +pub struct HighlyGenericStruct { + pub z: (A, B, C, D) +} + +// VERIFY that we NOT show the Aliased Type +// @has 'inner_variants/type.HighlyGenericAABB.html' +// @count - '//details[@class="toggle"]' 0 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +pub type HighlyGenericAABB = HighlyGenericStruct; -- cgit 1.4.1-3-g733a5 From 6b3bba8c3e60e08805a5b4b556c5ec128d350382 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 16 Aug 2023 17:12:04 +0200 Subject: rustdoc: handle typedef inner type when doing cross-crate inlining --- src/librustdoc/clean/inline.rs | 16 ++++++---------- tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs | 5 +++++ tests/rustdoc/typedef-inner-variants.rs | 11 +++++++++++ 3 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs (limited to 'src') diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 25f303d8a52..dd43ee03383 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -20,7 +20,8 @@ use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty, - clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type, + clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes, + AttributesExt, ImplKind, ItemId, Type, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -289,19 +290,14 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box { let predicates = cx.tcx.explicit_predicates_of(did); - let type_ = clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()), - cx, - Some(did), - None, - ); + let ty = cx.tcx.type_of(did).instantiate_identity(); + let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None); + let inner_type = clean_ty_alias_inner_type(ty, cx); Box::new(clean::TypeAlias { type_, generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), - // FIXME: Figure-out how to handle inner_type with - // clean_ty_typedef_inner_type - inner_type: None, + inner_type, item_type: None, }) } diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs new file mode 100644 index 00000000000..f4e020b3b95 --- /dev/null +++ b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs @@ -0,0 +1,5 @@ +pub struct InlineOne { + pub inline: A +} + +pub type InlineU64 = InlineOne; diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index e0c5b7dd98f..46acd86e12f 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -1,5 +1,11 @@ +// This test checks different combinations of structs, enums, and unions +// for the "Show Aliased Type" feature on type definition. + #![crate_name = "inner_variants"] +// aux-build:cross_crate_generic_typedef.rs +extern crate cross_crate_generic_typedef; + pub struct Adt; pub struct Ty; @@ -78,3 +84,8 @@ pub struct HighlyGenericStruct { // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 0 pub type HighlyGenericAABB = HighlyGenericStruct; + +// @has 'inner_variants/type.InlineU64.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +pub use cross_crate_generic_typedef::InlineU64; -- cgit 1.4.1-3-g733a5 From af6889c28c5ad72433562caf75d2dc97bf494424 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 18 Aug 2023 17:57:20 +0200 Subject: rustdoc: bind typedef inner type items to the folding system This let's us handle a multitude of things for free: - #[doc(hidden)] - private fields/variants - --document-private-items - --document-hidden-items And correct in the process the determination of "has stripped items" by doing the same logic done by other ones. --- src/librustdoc/clean/mod.rs | 9 ++------- src/librustdoc/clean/types.rs | 17 +++------------- src/librustdoc/fold.rs | 23 +++++++++++++++++++++- src/librustdoc/formats/cache.rs | 1 + src/librustdoc/html/render/print_item.rs | 33 +++++++++++++++++++------------- tests/rustdoc/typedef-inner-variants.rs | 6 +++++- 6 files changed, 53 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d0d92a1116f..892dfe4240b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -971,10 +971,8 @@ fn clean_ty_alias_inner_type<'tcx>( .map(|variant| clean_variant_def_with_args(variant, args, cx)) .collect(); - let has_stripped_variants = adt_def.variants().len() != variants.len(); TypeAliasInnerType::Enum { variants, - has_stripped_variants, is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(), } } else { @@ -987,11 +985,10 @@ fn clean_ty_alias_inner_type<'tcx>( let fields: Vec<_> = clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect(); - let has_stripped_fields = variant.fields.len() != fields.len(); if adt_def.is_struct() { - TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields, has_stripped_fields } + TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields } } else { - TypeAliasInnerType::Union { fields, has_stripped_fields } + TypeAliasInnerType::Union { fields } } }) } @@ -2415,7 +2412,6 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( variant .fields .iter() - .filter(|field| field.vis.is_public()) .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); clean_field_with_def_id( @@ -2431,7 +2427,6 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( fields: variant .fields .iter() - .filter(|field| field.vis.is_public()) .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); clean_field_with_def_id( diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6efe4179707..9cc5d7c2911 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2231,20 +2231,9 @@ pub(crate) struct PathSegment { #[derive(Clone, Debug)] pub(crate) enum TypeAliasInnerType { - Enum { - variants: IndexVec, - has_stripped_variants: bool, - is_non_exhaustive: bool, - }, - Union { - fields: Vec, - has_stripped_fields: bool, - }, - Struct { - ctor_kind: Option, - fields: Vec, - has_stripped_fields: bool, - }, + Enum { variants: IndexVec, is_non_exhaustive: bool }, + Union { fields: Vec }, + Struct { ctor_kind: Option, fields: Vec }, } #[derive(Clone, Debug)] diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ceba643ed5f..cf11e2d7899 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -52,10 +52,31 @@ pub(crate) trait DocFolder: Sized { VariantItem(Variant { kind, discriminant }) } + TypeAliasItem(mut typealias) => { + typealias.inner_type = typealias.inner_type.map(|inner_type| match inner_type { + TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants = variants + .into_iter_enumerated() + .filter_map(|(_, x)| self.fold_item(x)) + .collect(); + + TypeAliasInnerType::Enum { variants, is_non_exhaustive } + } + TypeAliasInnerType::Union { fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Union { fields } + } + TypeAliasInnerType::Struct { ctor_kind, fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Struct { ctor_kind, fields } + } + }); + + TypeAliasItem(typealias) + } ExternCrateItem { src: _ } | ImportItem(_) | FunctionItem(_) - | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) | ConstantItem(_) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9a34e7cce8a..4c6e7dfb987 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -457,6 +457,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { | clean::StructItem(..) | clean::UnionItem(..) | clean::VariantItem(..) + | clean::TypeAliasItem(..) | clean::ImplItem(..) => { self.cache.parent_stack.push(ParentStackItem::new(&item)); (self.fold_item_recur(item), true) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 09be756f26d..4f3a792fd7f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1270,30 +1270,34 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c } match &t.inner_type { - Some(clean::TypeAliasInnerType::Enum { - variants, - has_stripped_variants: has_stripped_entries, - is_non_exhaustive, - }) => { + Some(clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive }) => { toggle(w, |w| { + let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); wrap_item(w, |w| { + let variants_len = variants.len(); + let variants_count = variants_iter().count(); + let has_stripped_entries = variants_len != variants_count; + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); render_enum_fields( w, cx, None, - variants.iter(), - variants.len(), - *has_stripped_entries, + variants_iter(), + variants_count, + has_stripped_entries, *is_non_exhaustive, ) }); - item_variants(w, cx, it, variants.iter()); + item_variants(w, cx, it, variants_iter()); }); } - Some(clean::TypeAliasInnerType::Union { fields, has_stripped_fields }) => { + Some(clean::TypeAliasInnerType::Union { fields }) => { toggle(w, |w| { wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); render_struct_fields( w, @@ -1302,16 +1306,19 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c fields, "", true, - *has_stripped_fields, + has_stripped_fields, cx, ); }); item_fields(w, cx, it, fields, None); }); } - Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields, has_stripped_fields }) => { + Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields }) => { toggle(w, |w| { wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); render_struct_fields( w, @@ -1320,7 +1327,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c fields, "", true, - *has_stripped_fields, + has_stripped_fields, cx, ); }); diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index 46acd86e12f..cb9c1248c46 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -22,6 +22,8 @@ pub enum IrTyKind { TyKind(A, B), // no comment StructKind { a: A, }, + #[doc(hidden)] + Unspecified, } // @has 'inner_variants/type.NearlyTyKind.html' @@ -52,7 +54,9 @@ pub type OneOrF64 = OneOr; // @has 'inner_variants/struct.One.html' pub struct One { pub val: T, - __hidden: T, + #[doc(hidden)] + pub __hidden: T, + __private: T, } // @has 'inner_variants/type.OneU64.html' -- cgit 1.4.1-3-g733a5 From 9443f8474548842f15d099f11856fde11bf87bd2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 18 Aug 2023 19:02:45 +0200 Subject: rustdoc: normalize all typedef inner types --- src/librustdoc/clean/mod.rs | 25 +++++++++++++++++++++++++ tests/rustdoc/typedef-inner-variants.rs | 30 +++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 892dfe4240b..0ebec2d9ba2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2406,6 +2406,11 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( ty::VariantDiscr::Relative(_) => None, }; + use rustc_middle::traits::ObligationCause; + use rustc_trait_selection::infer::TyCtxtInferExt; + use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; + + let infcx = cx.tcx.infer_ctxt().build(); let kind = match variant.ctor_kind() { Some(CtorKind::Const) => VariantKind::CLike, Some(CtorKind::Fn) => VariantKind::Tuple( @@ -2414,6 +2419,16 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( .iter() .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + clean_field_with_def_id( field.did, field.name, @@ -2429,6 +2444,16 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( .iter() .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + clean_field_with_def_id( field.did, field.name, diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index cb9c1248c46..f3ba097ee08 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -8,6 +8,17 @@ extern crate cross_crate_generic_typedef; pub struct Adt; pub struct Ty; +pub struct TyCtxt; + +pub trait Interner { + type Adt; + type Ty; +} + +impl Interner for TyCtxt { + type Adt = Adt; + type Ty = Ty; +} // @has 'inner_variants/type.AliasTy.html' // @count - '//*[@id="variants"]' 0 @@ -15,11 +26,11 @@ pub struct Ty; pub type AliasTy = Ty; // @has 'inner_variants/enum.IrTyKind.html' -pub enum IrTyKind { +pub enum IrTyKind { /// Doc comment for AdtKind - AdtKind(A), + AdtKind(I::Adt), /// and another one for TyKind - TyKind(A, B), + TyKind(I::Adt, ::Ty), // no comment StructKind { a: A, }, #[doc(hidden)] @@ -29,14 +40,18 @@ pub enum IrTyKind { // @has 'inner_variants/type.NearlyTyKind.html' // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 0 -pub type NearlyTyKind = IrTyKind; +pub type NearlyTyKind = IrTyKind; // @has 'inner_variants/type.TyKind.html' // @count - '//*[@id="variants"]' 1 // @count - '//*[@id="fields"]' 0 // @count - '//*[@class="variant"]' 3 // @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "enum TyKind" -pub type TyKind = IrTyKind; +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[1]' "Adt" +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[2]' "Adt" +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[3]' "Ty" +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[4]' "i64" +pub type TyKind = IrTyKind; // @has 'inner_variants/union.OneOr.html' pub union OneOr { @@ -68,13 +83,14 @@ pub type OneU64 = One; // @has 'inner_variants/struct.OnceA.html' pub struct OnceA<'a, A> { - a: &'a A, // private + pub a: &'a A, } // @has 'inner_variants/type.Once.html' // @count - '//*[@id="variants"]' 0 -// @count - '//*[@id="fields"]' 0 +// @count - '//*[@id="fields"]' 1 // @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct Once<'a>" +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "&'a" pub type Once<'a> = OnceA<'a, i64>; // @has 'inner_variants/struct.HighlyGenericStruct.html' -- cgit 1.4.1-3-g733a5 From 282acb93c91371bfcb9256c274a932d45207fa03 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 25 Aug 2023 22:36:58 +0200 Subject: rustdoc: remove details for type alias inner type and fix sidebar --- src/librustdoc/clean/types.rs | 17 ++++ src/librustdoc/html/render/print_item.rs | 143 +++++++++++-------------------- src/librustdoc/html/render/sidebar.rs | 28 +++++- tests/rustdoc/typedef-inner-variants.rs | 26 +++--- 4 files changed, 110 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9cc5d7c2911..ce3f1bcf215 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2252,6 +2252,23 @@ pub(crate) struct TypeAlias { pub(crate) item_type: Option, } +impl TypeAlias { + pub(crate) fn should_display_inner_type(&self) -> bool { + // Only show inner variants if: + // - the typealias does NOT have any generics (modulo lifetimes) + // - AND the aliased type has some generics + // + // Otherwise, showing a non-generic type is rendurant with its own page, or + // if it still has some generics, it's not as useful. + self.generics + .params + .iter() + .all(|param| matches!(param.kind, GenericParamDefKind::Lifetime { .. })) + && self.generics.where_predicates.is_empty() + && self.type_.generics().is_some_and(|generics| !generics.is_empty()) + } +} + #[derive(Clone, Debug)] pub(crate) struct OpaqueTy { pub(crate) bounds: Vec, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 4f3a792fd7f..fc0549c3f64 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,104 +1237,63 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - // Only show inner variants if: - // - the typealias does NOT have any generics (modulo lifetimes) - // - AND the aliased type has some generics - // - // Otherwise, showing a non-generic type is rendurant with its own page, or - // if it still has some generics, it's not as useful. - let should_print_inner_type = t - .generics - .params - .iter() - .all(|param| matches!(param.kind, clean::GenericParamDefKind::Lifetime { .. })) - && t.generics.where_predicates.is_empty() - && t.type_.generics().is_some_and(|generics| !generics.is_empty()); - - if should_print_inner_type { - fn toggle(w: &mut W, f: F) - where - W: fmt::Write, - F: FnOnce(&mut W), - { - write!( - w, - "
\ - \ - Show Aliased Type\ - ", - ) - .unwrap(); - f(w); - write!(w, "
").unwrap(); - } - - match &t.inner_type { - Some(clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive }) => { - toggle(w, |w| { - let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); - wrap_item(w, |w| { - let variants_len = variants.len(); - let variants_count = variants_iter().count(); - let has_stripped_entries = variants_len != variants_count; - - write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); - render_enum_fields( - w, - cx, - None, - variants_iter(), - variants_count, - has_stripped_entries, - *is_non_exhaustive, - ) - }); - item_variants(w, cx, it, variants_iter()); + if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + write!( + w, + "

\ + Aliased Type§

" + ); + + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); + wrap_item(w, |w| { + let variants_len = variants.len(); + let variants_count = variants_iter().count(); + let has_stripped_entries = variants_len != variants_count; + + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); + render_enum_fields( + w, + cx, + None, + variants_iter(), + variants_count, + has_stripped_entries, + *is_non_exhaustive, + ) }); + item_variants(w, cx, it, variants_iter()); } - Some(clean::TypeAliasInnerType::Union { fields }) => { - toggle(w, |w| { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; - - write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); - render_struct_fields( - w, - None, - None, - fields, - "", - true, - has_stripped_fields, - cx, - ); - }); - item_fields(w, cx, it, fields, None); + clean::TypeAliasInnerType::Union { fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields(w, None, None, fields, "", true, has_stripped_fields, cx); }); + item_fields(w, cx, it, fields, None); } - Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields }) => { - toggle(w, |w| { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; - - write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); - render_struct_fields( - w, - None, - *ctor_kind, - fields, - "", - true, - has_stripped_fields, - cx, - ); - }); - item_fields(w, cx, it, fields, None); + clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + None, + *ctor_kind, + fields, + "", + true, + has_stripped_fields, + cx, + ); }); + item_fields(w, cx, it, fields, None); } - None => {} } } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index b96b1536156..c82a45303a4 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -82,7 +82,7 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf clean::PrimitiveItem(_) => sidebar_primitive(cx, it), clean::UnionItem(ref u) => sidebar_union(cx, it, u), clean::EnumItem(ref e) => sidebar_enum(cx, it, e), - clean::TypeAliasItem(_) => sidebar_type_alias(cx, it), + clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t), clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)], clean::ForeignTypeItem => sidebar_foreign_type(cx, it), _ => vec![], @@ -230,8 +230,32 @@ fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec> { +fn sidebar_type_alias<'a>( + cx: &'a Context<'_>, + it: &'a clean::Item, + t: &'a clean::TypeAlias, +) -> Vec> { let mut items = vec![]; + if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { + let mut variants = variants + .iter() + .filter(|i| !i.is_stripped()) + .filter_map(|v| v.name) + .map(|name| Link::new(format!("variant.{name}"), name.to_string())) + .collect::>(); + variants.sort_unstable(); + + items.push(LinkBlock::new(Link::new("variants", "Variants"), variants)); + } + clean::TypeAliasInnerType::Union { fields } + | clean::TypeAliasInnerType::Struct { ctor_kind: _, fields } => { + let fields = get_struct_fields_name(fields); + items.push(LinkBlock::new(Link::new("fields", "Fields"), fields)); + } + } + } sidebar_assoc_items(cx, it, &mut items); items } diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index f3ba097ee08..31edb0a8706 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -43,14 +43,15 @@ pub enum IrTyKind { pub type NearlyTyKind = IrTyKind; // @has 'inner_variants/type.TyKind.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 1 // @count - '//*[@id="fields"]' 0 // @count - '//*[@class="variant"]' 3 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "enum TyKind" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[1]' "Adt" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[2]' "Adt" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[3]' "Ty" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[4]' "i64" +// @matches - '//pre[@class="rust item-decl"]//code' "enum TyKind" +// @has - '//pre[@class="rust item-decl"]//code/a[1]' "Adt" +// @has - '//pre[@class="rust item-decl"]//code/a[2]' "Adt" +// @has - '//pre[@class="rust item-decl"]//code/a[3]' "Ty" +// @has - '//pre[@class="rust item-decl"]//code/a[4]' "i64" pub type TyKind = IrTyKind; // @has 'inner_variants/union.OneOr.html' @@ -60,10 +61,11 @@ pub union OneOr { } // @has 'inner_variants/type.OneOrF64.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 // @count - '//*[@class="structfield small-section-header"]' 2 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "union OneOrF64" +// @matches - '//pre[@class="rust item-decl"]//code' "union OneOrF64" pub type OneOrF64 = OneOr; // @has 'inner_variants/struct.One.html' @@ -75,10 +77,12 @@ pub struct One { } // @has 'inner_variants/type.OneU64.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 // @count - '//*[@class="structfield small-section-header"]' 1 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct OneU64" +// @matches - '//pre[@class="rust item-decl"]//code' "struct OneU64" +// @matches - '//pre[@class="rust item-decl"]//code' "pub val" pub type OneU64 = One; // @has 'inner_variants/struct.OnceA.html' @@ -87,10 +91,11 @@ pub struct OnceA<'a, A> { } // @has 'inner_variants/type.Once.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct Once<'a>" -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "&'a" +// @matches - '//pre[@class="rust item-decl"]//code' "struct Once<'a>" +// @matches - '//pre[@class="rust item-decl"]//code' "&'a" pub type Once<'a> = OnceA<'a, i64>; // @has 'inner_variants/struct.HighlyGenericStruct.html' @@ -100,12 +105,13 @@ pub struct HighlyGenericStruct { // VERIFY that we NOT show the Aliased Type // @has 'inner_variants/type.HighlyGenericAABB.html' -// @count - '//details[@class="toggle"]' 0 +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 0 pub type HighlyGenericAABB = HighlyGenericStruct; // @has 'inner_variants/type.InlineU64.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 pub use cross_crate_generic_typedef::InlineU64; -- cgit 1.4.1-3-g733a5 From b3686c2fd6ad57912e1b0e778bedb0b9a05c73fa Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 25 Aug 2023 07:32:54 -0700 Subject: Add note about lazy_type_alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: León Orell Valerian Liehr --- src/librustdoc/html/render/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1d77ce74c80..a85e8356c2f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1153,8 +1153,8 @@ fn render_assoc_items_inner( // don't normally constrain on them anyway. // https://github.com/rust-lang/rust/issues/21903 // - // If that changes, then this will need to check them with type - // unification. + // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification. + // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress. let aliased_ty = tcx.type_of(alias_def_id).skip_binder(); let reject_cx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey, -- cgit 1.4.1-3-g733a5 From 706d010c8b590f40cc2fb3de7b744d9a59a93ac9 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 25 Aug 2023 23:07:03 +0200 Subject: rustdoc: always print type alias inner type (with it's where clauses) --- src/librustdoc/clean/types.rs | 17 ----------- src/librustdoc/html/render/print_item.rs | 17 ++++++++--- src/librustdoc/html/render/sidebar.rs | 2 +- .../typedef-inner-variants-lazy_type_alias.rs | 34 ++++++++++++++++++++++ tests/rustdoc/typedef-inner-variants.rs | 8 +++-- 5 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs (limited to 'src') diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ce3f1bcf215..9cc5d7c2911 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2252,23 +2252,6 @@ pub(crate) struct TypeAlias { pub(crate) item_type: Option, } -impl TypeAlias { - pub(crate) fn should_display_inner_type(&self) -> bool { - // Only show inner variants if: - // - the typealias does NOT have any generics (modulo lifetimes) - // - AND the aliased type has some generics - // - // Otherwise, showing a non-generic type is rendurant with its own page, or - // if it still has some generics, it's not as useful. - self.generics - .params - .iter() - .all(|param| matches!(param.kind, GenericParamDefKind::Lifetime { .. })) - && self.generics.where_predicates.is_empty() - && self.type_.generics().is_some_and(|generics| !generics.is_empty()) - } -} - #[derive(Clone, Debug)] pub(crate) struct OpaqueTy { pub(crate) bounds: Vec, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index fc0549c3f64..2da7cb01c90 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,7 +1237,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + if let Some(inner_type) = &t.inner_type { write!( w, "

\ @@ -1256,7 +1256,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c render_enum_fields( w, cx, - None, + Some(&t.generics), variants_iter(), variants_count, has_stripped_entries, @@ -1271,7 +1271,16 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c let has_stripped_fields = fields.len() != fields_count; write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); - render_struct_fields(w, None, None, fields, "", true, has_stripped_fields, cx); + render_struct_fields( + w, + Some(&t.generics), + None, + fields, + "", + true, + has_stripped_fields, + cx, + ); }); item_fields(w, cx, it, fields, None); } @@ -1283,7 +1292,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); render_struct_fields( w, - None, + Some(&t.generics), *ctor_kind, fields, "", diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index c82a45303a4..fce31a8423d 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -236,7 +236,7 @@ fn sidebar_type_alias<'a>( t: &'a clean::TypeAlias, ) -> Vec> { let mut items = vec![]; - if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + if let Some(inner_type) = &t.inner_type { match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { let mut variants = variants diff --git a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs new file mode 100644 index 00000000000..ff84352d716 --- /dev/null +++ b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs @@ -0,0 +1,34 @@ +#![crate_name = "inner_types_lazy"] + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +// @has 'inner_types_lazy/struct.Pair.html' +pub struct Pair { + pub first: A, + pub second: B, +} + +// @has 'inner_types_lazy/type.ReversedTypesPair.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 0 +pub type ReversedTypesPair = Pair; + +// @has 'inner_types_lazy/type.ReadWrite.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 2 +pub type ReadWrite = Pair +where + R: std::io::Read, + W: std::io::Write; + +// @has 'inner_types_lazy/type.VecPair.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 0 +pub type VecPair = Pair, Vec>; diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index 31edb0a8706..b734714fd64 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -38,7 +38,8 @@ pub enum IrTyKind { } // @has 'inner_variants/type.NearlyTyKind.html' -// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 1 // @count - '//*[@id="fields"]' 0 pub type NearlyTyKind = IrTyKind; @@ -103,11 +104,12 @@ pub struct HighlyGenericStruct { pub z: (A, B, C, D) } -// VERIFY that we NOT show the Aliased Type // @has 'inner_variants/type.HighlyGenericAABB.html' // @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 -// @count - '//*[@id="fields"]' 0 +// @count - '//*[@id="fields"]' 1 +// @matches - '//pre[@class="rust item-decl"]//code' "struct HighlyGenericAABB" +// @matches - '//pre[@class="rust item-decl"]//code' "pub z" pub type HighlyGenericAABB = HighlyGenericStruct; // @has 'inner_variants/type.InlineU64.html' -- cgit 1.4.1-3-g733a5 From 85e4b89cf615c112c72243a2d8f4a55010ecbd4b Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 28 Aug 2023 10:00:26 +0200 Subject: rustdoc: start new "Sections" section in the book with Aliased Type --- src/doc/rustdoc/src/how-to-read-rustdoc.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 9deb7009cfe..cd6e29ffd66 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -38,6 +38,22 @@ followed by a list of fields or variants for Rust types. Finally, the page lists associated functions and trait implementations, including automatic and blanket implementations that `rustdoc` knows about. +### Sections + + + + + + +#### Aliased Type + +A type alias is expanded at compile time to its +[aliased type](https://doc.rust-lang.org/reference/items/type-aliases.html). +That may involve substituting some or all of the type parameters in the target +type with types provided by the type alias definition. The Aliased Type section +shows the result of this expansion, including the types of public fields or +variants, which may depend on those substitutions. + ### Navigation Subheadings, variants, fields, and many other things in this documentation -- cgit 1.4.1-3-g733a5 From b8e0e797e701f60bd975b3f8a295e1cb1a1de58c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Sep 2023 17:04:44 +0200 Subject: bootstrap/format: remove unnecessary paths.push --- src/bootstrap/format.rs | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index d658be0b8eb..11f2762f766 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -127,8 +127,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { Err(_) => false, }; - let mut paths = paths.to_vec(); - if git_available { let in_working_tree = match build .config @@ -201,8 +199,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { "WARN: Something went wrong when running git commands:\n{err}\n\ Falling back to formatting all files." ); - // Something went wrong when getting the version. Just format all the files. - paths.push(".".into()); } } } -- cgit 1.4.1-3-g733a5 From 2619a6ea5105a8cd7358419000117bbc25d0409e Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 6 Sep 2023 12:58:59 +0800 Subject: Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/tools/cargo b/src/tools/cargo index 96fe1c9e1ae..d14c85f4e6e 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 96fe1c9e1aecd8f57063e3753969bb6418fd2fd5 +Subproject commit d14c85f4e6e7671673b1a1bc87231ff7164761e1 -- cgit 1.4.1-3-g733a5 From e0593f30fbaf8fdc05784ee90833596b2d659d9c Mon Sep 17 00:00:00 2001 From: Goldstein Date: Wed, 6 Sep 2023 10:14:09 +0300 Subject: fix log formatting in bootstrap --- src/bootstrap/lib.rs | 2 +- src/bootstrap/llvm.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 4396bbc51a3..671d25484d0 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1019,7 +1019,7 @@ impl Build { fn info(&self, msg: &str) { match self.config.dry_run { - DryRun::SelfCheck => return, + DryRun::SelfCheck => (), DryRun::Disabled | DryRun::UserSelected => { println!("{msg}"); } diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 07502e0e9dd..aefed501513 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -598,9 +598,9 @@ fn configure_cmake( } else if target.contains("linux") { cfg.define("CMAKE_SYSTEM_NAME", "Linux"); } else { - builder.info( + builder.info(&format!( "could not determine CMAKE_SYSTEM_NAME from the target `{target}`, build may fail", - ); + )); } // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in -- cgit 1.4.1-3-g733a5 From 1abbd4cd4fa1c18c706505b71ed49cf0fda0ebee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Apr 2023 17:42:39 +0000 Subject: Render missing fields in tuple struct/enum as /* private fields */ --- src/librustdoc/html/render/print_item.rs | 44 +++++++++++++++------- .../const-generics/const-generic-defaults.rs | 2 +- .../rustdoc/const-generics/const-generics-docs.rs | 4 +- tests/rustdoc/issue-88600.rs | 4 +- tests/rustdoc/where.SWhere_Simd_item-decl.html | 2 +- tests/rustdoc/where.alpha_trait_decl.html | 2 +- tests/rustdoc/where.rs | 2 +- 7 files changed, 38 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cb78f903462..066b5d6b36c 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1315,6 +1315,12 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( s: &'a [clean::Item], ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(|f| { + if s.iter() + .all(|field| matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))) + { + return f.write_str("/* private fields */"); + } + for (i, ty) in s.iter().enumerate() { if i > 0 { f.write_str(", ")?; @@ -1936,21 +1942,31 @@ fn render_struct( } Some(CtorKind::Fn) => { w.write_str("("); - for (i, field) in fields.iter().enumerate() { - if i > 0 { - w.write_str(", "); - } - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), - clean::StructFieldItem(ref ty) => { - write!( - w, - "{}{}", - visibility_print_with_space(field.visibility(tcx), field.item_id, cx), - ty.print(cx), - ) + if fields.iter().all(|field| { + matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..))) + }) { + write!(w, "/* private fields */"); + } else { + for (i, field) in fields.iter().enumerate() { + if i > 0 { + w.write_str(", "); + } + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), + clean::StructFieldItem(ref ty) => { + write!( + w, + "{}{}", + visibility_print_with_space( + field.visibility(tcx), + field.item_id, + cx + ), + ty.print(cx), + ) + } + _ => unreachable!(), } - _ => unreachable!(), } } w.write_str(")"); diff --git a/tests/rustdoc/const-generics/const-generic-defaults.rs b/tests/rustdoc/const-generics/const-generic-defaults.rs index f781c6a62f2..7a0a794112d 100644 --- a/tests/rustdoc/const-generics/const-generic-defaults.rs +++ b/tests/rustdoc/const-generics/const-generic-defaults.rs @@ -1,5 +1,5 @@ #![crate_name = "foo"] // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \ -// 'pub struct Foo(_);' +// 'pub struct Foo(' pub struct Foo(T); diff --git a/tests/rustdoc/const-generics/const-generics-docs.rs b/tests/rustdoc/const-generics/const-generics-docs.rs index 828486a41d4..70a9518f05b 100644 --- a/tests/rustdoc/const-generics/const-generics-docs.rs +++ b/tests/rustdoc/const-generics/const-generics-docs.rs @@ -33,7 +33,7 @@ impl Trait for [u8; N] {} // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \ // 'pub struct Foo where u8: Trait' pub struct Foo where u8: Trait; -// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar(_)' +// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar(' pub struct Bar([T; N]); // @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl Foowhere u8: Trait' @@ -92,7 +92,7 @@ macro_rules! define_me { } // @has foo/struct.Foz.html '//pre[@class="rust item-decl"]' \ -// 'pub struct Foz(_);' +// 'pub struct Foz(/* private fields */);' define_me!(Foz); trait Q { diff --git a/tests/rustdoc/issue-88600.rs b/tests/rustdoc/issue-88600.rs index db0d102b741..f89af472f6e 100644 --- a/tests/rustdoc/issue-88600.rs +++ b/tests/rustdoc/issue-88600.rs @@ -8,10 +8,10 @@ pub struct S; // @has issue_88600/enum.FooEnum.html pub enum FooEnum { - // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(_)' + // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(/* private fields */)' // @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0 HiddenTupleItem(#[doc(hidden)] H), - // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(_, _)' + // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(/* private fields */)' // @count - '//*[@id="variant.MultipleHidden.field.0"]' 0 // @count - '//*[@id="variant.MultipleHidden.field.1"]' 0 MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H), diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html index 3e72ba2b74f..46708b9e4e9 100644 --- a/tests/rustdoc/where.SWhere_Simd_item-decl.html +++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html @@ -1,3 +1,3 @@ -
pub struct Simd<T>(_)
+
pub struct Simd<T>(/* private fields */)
 where
     T: MyTrait;
diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc/where.alpha_trait_decl.html index a7700055c9a..0c0b2d1ceca 100644 --- a/tests/rustdoc/where.alpha_trait_decl.html +++ b/tests/rustdoc/where.alpha_trait_decl.html @@ -1,3 +1,3 @@ -pub struct Alpha<A>(_) +pub struct Alpha<A>(/* private fields */) where A: MyTrait; \ No newline at end of file diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 2aa9c8b5461..aea02c14039 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -4,7 +4,7 @@ use std::io::Lines; pub trait MyTrait { fn dummy(&self) { } } -// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(_) where A: MyTrait" +// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(/* private fields */) where A: MyTrait" // @snapshot alpha_trait_decl - '//*[@class="rust item-decl"]/code' pub struct Alpha(A) where A: MyTrait; // @has foo/trait.Bravo.html '//pre' "pub trait Bravowhere B: MyTrait" -- cgit 1.4.1-3-g733a5 From 73d8dcb803aad67df31abe99f573a2320282bc60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Sep 2023 16:36:00 +0200 Subject: miri: catch function calls where the argument is caller-invalid / the return value callee-invalid --- compiler/rustc_const_eval/src/interpret/place.rs | 7 +++++ src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs | 13 --------- .../miri/tests/fail/validity/cast_fn_ptr1.stderr | 15 ---------- src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs | 15 ---------- .../miri/tests/fail/validity/cast_fn_ptr2.stderr | 15 ---------- .../validity/cast_fn_ptr_invalid_callee_arg.rs | 13 +++++++++ .../validity/cast_fn_ptr_invalid_callee_arg.stderr | 15 ++++++++++ .../validity/cast_fn_ptr_invalid_callee_ret.rs | 28 ++++++++++++++++++ .../validity/cast_fn_ptr_invalid_callee_ret.stderr | 15 ++++++++++ .../validity/cast_fn_ptr_invalid_caller_arg.rs | 34 ++++++++++++++++++++++ .../validity/cast_fn_ptr_invalid_caller_arg.stderr | 20 +++++++++++++ .../validity/cast_fn_ptr_invalid_caller_ret.rs | 15 ++++++++++ .../validity/cast_fn_ptr_invalid_caller_ret.stderr | 15 ++++++++++ 13 files changed, 162 insertions(+), 58 deletions(-) delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr (limited to 'src') diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index d8ad82d3da0..90f2b470179 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -796,6 +796,13 @@ where dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, ) -> InterpResult<'tcx> { + // Generally for transmutation, data must be valid both at the old and new type. + // But if the types are the same, the 2nd validation below suffices. + if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) { + self.validate_operand(&src.to_op(self)?)?; + } + + // Do the actual copy. self.copy_op_no_validate(src, dest, allow_transmute)?; if M::enforce_validity(self, dest.layout()) { diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs deleted file mode 100644 index 6ab73569c63..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@compile-flags: -Zmiri-permissive-provenance - -fn main() { - // Cast a function pointer such that on a call, the argument gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that - // should fail, but validation should. - fn f(_x: &i32) {} - - let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; - - g(0usize as *const i32) - //~^ ERROR: encountered a null reference -} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr deleted file mode 100644 index 133e4b2c16a..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr1.rs:LL:CC - | -LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs deleted file mode 100644 index 64ddb563be5..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@compile-flags: -Zmiri-permissive-provenance - -fn main() { - // Cast a function pointer such that when returning, the return value gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that - // should fail, but validation should. - fn f() -> *const i32 { - 0usize as *const i32 - } - - let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; - - let _x = g(); - //~^ ERROR: encountered a null reference -} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr deleted file mode 100644 index 21001f2b460..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr2.rs:LL:CC - | -LL | let _x = g(); - | ^^^ constructing invalid value: encountered a null reference - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs new file mode 100644 index 00000000000..6ab73569c63 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs @@ -0,0 +1,13 @@ +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + // Cast a function pointer such that on a call, the argument gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f(_x: &i32) {} + + let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; + + g(0usize as *const i32) + //~^ ERROR: encountered a null reference +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr new file mode 100644 index 00000000000..21e403b47f8 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a null reference + --> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC + | +LL | g(0usize as *const i32) + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs new file mode 100644 index 00000000000..7cdc15c6094 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs @@ -0,0 +1,28 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that +// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer +// type. That way we never get an "invalid value constructed" error inside the function, it can +// only possibly be detected when the return value is passed to the caller. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn f() -> NonZeroU32 { + mir! { + { + let tmp = ptr::addr_of_mut!(RET); + let ptr = tmp as *mut u32; + *ptr = 0; + Return() + } + } +} + +fn main() { + let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) }; + // There's a NonZeroU32-to-u32 transmute happening here + f(); //~ERROR: expected something greater or equal to 1 +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr new file mode 100644 index 00000000000..ccfb8890939 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + | +LL | f(); + | ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs new file mode 100644 index 00000000000..ee80186d4b5 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -0,0 +1,34 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +fn f(c: u32) { + println!("{c}"); +} + +// Call that function in a bad way, with an invalid NonZeroU32, but without +// ever materializing this as a NonZeroU32 value outside the call itself. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn call(f: fn(NonZeroU32)) { + mir! { + let _res: (); + { + let c = 0; + let tmp = ptr::addr_of!(c); + let ptr = tmp as *const NonZeroU32; + // The call site now is a NonZeroU32-to-u32 transmute. + Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1 + } + retblock = { + Return() + } + } +} + +fn main() { + let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) }; + call(f); +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr new file mode 100644 index 00000000000..234c2804008 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | Call(_res = f(*ptr), retblock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC +note: inside `main` + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | call(f); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs new file mode 100644 index 00000000000..64ddb563be5 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs @@ -0,0 +1,15 @@ +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + // Cast a function pointer such that when returning, the return value gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f() -> *const i32 { + 0usize as *const i32 + } + + let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; + + let _x = g(); + //~^ ERROR: encountered a null reference +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr new file mode 100644 index 00000000000..bd9866acbd4 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a null reference + --> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC + | +LL | let _x = g(); + | ^^^ constructing invalid value: encountered a null reference + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From f49382c0508db608aa9c33d6a8c77d2955d8f62c Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Thu, 31 Aug 2023 22:12:47 +0200 Subject: Use `Freeze` for `SourceFile.lines` --- .../src/debuginfo/line_info.rs | 2 +- compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 2 +- compiler/rustc_data_structures/src/sync/freeze.rs | 12 + compiler/rustc_middle/src/query/on_disk_cache.rs | 2 +- .../rustc_query_system/src/ich/impls_syntax.rs | 9 +- compiler/rustc_span/src/lib.rs | 263 +++++++++++---------- compiler/rustc_span/src/source_map.rs | 2 +- compiler/rustc_span/src/source_map/tests.rs | 4 +- compiler/rustc_span/src/tests.rs | 4 +- .../clippy_lints/src/undocumented_unsafe_blocks.rs | 84 +++---- src/tools/clippy/clippy_utils/src/source.rs | 2 +- 11 files changed, 203 insertions(+), 183 deletions(-) (limited to 'src') diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 998263de584..b19b935a0fe 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -81,7 +81,7 @@ impl DebugContext { match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { - let line_pos = file.lines(|lines| lines[line]); + let line_pos = file.lines()[line]; let col = file.relative_position(span.lo()) - line_pos; (file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 2301f66dc28..487263709e1 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -263,7 +263,7 @@ impl CodegenCx<'_, '_> { pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc { let (file, line, col) = match self.sess().source_map().lookup_line(pos) { Ok(SourceFileAndLine { sf: file, line }) => { - let line_pos = file.lines(|lines| lines[line]); + let line_pos = file.lines()[line]; // Use 1-based indexing. let line = (line + 1) as u32; diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index 88c710e5236..ad71ae1af51 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -3,6 +3,7 @@ use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard}; use crate::sync::{DynSend, DynSync}; use std::{ cell::UnsafeCell, + intrinsics::likely, marker::PhantomData, ops::{Deref, DerefMut}, sync::atomic::Ordering, @@ -49,6 +50,17 @@ impl FreezeLock { self.frozen.load(Ordering::Acquire) } + /// Get the inner value if frozen. + #[inline] + pub fn get(&self) -> Option<&T> { + if likely(self.frozen.load(Ordering::Acquire)) { + // SAFETY: This is frozen so the data cannot be modified. + unsafe { Some(&*self.data.get()) } + } else { + None + } + } + #[inline] pub fn read(&self) -> FreezeReadGuard<'_, T> { FreezeReadGuard { diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 64853bd9612..154c930dc0f 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -692,7 +692,7 @@ impl<'a, 'tcx> Decodable> for Span { let len = BytePos::decode(decoder); let file_lo = decoder.file_index_to_file(file_lo_index); - let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo); + let lo = file_lo.lines()[line_lo - 1] + col_lo; let lo = file_lo.absolute_position(lo); let hi = lo + len; diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index f2b13f95def..b2177be0e36 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -79,15 +79,16 @@ impl<'a> HashStable> for SourceFile { src_hash.hash_stable(hcx, hasher); - // We are always in `Lines` form by the time we reach here. - assert!(self.lines.borrow().is_lines()); - self.lines(|lines| { + { + // We are always in `Lines` form by the time we reach here. + assert!(self.lines.read().is_lines()); + let lines = self.lines(); // We only hash the relative position within this source_file lines.len().hash_stable(hcx, hasher); for &line in lines.iter() { line.hash_stable(hcx, hasher); } - }); + } // We only hash the relative position within this source_file multibyte_chars.len().hash_stable(hcx, hasher); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 8ef17ed671b..8976ee83c4e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -33,7 +33,7 @@ extern crate rustc_macros; #[macro_use] extern crate tracing; -use rustc_data_structures::AtomicRef; +use rustc_data_structures::{cold_path, AtomicRef}; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -1348,7 +1348,7 @@ pub struct SourceFile { /// The byte length of this source. pub source_len: RelativeBytePos, /// Locations of lines beginnings in the source code. - pub lines: Lock, + pub lines: FreezeLock, /// Locations of multi-byte characters in the source code. pub multibyte_chars: Vec, /// Width of characters that are not narrow in the source code. @@ -1373,7 +1373,10 @@ impl Clone for SourceFile { }, start_pos: self.start_pos, source_len: self.source_len, - lines: Lock::new(self.lines.borrow().clone()), + lines: { + let lock = self.lines.read(); + FreezeLock::with(lock.clone(), self.lines.is_frozen()) + }, multibyte_chars: self.multibyte_chars.clone(), non_narrow_chars: self.non_narrow_chars.clone(), normalized_pos: self.normalized_pos.clone(), @@ -1391,64 +1394,63 @@ impl Encodable for SourceFile { self.source_len.encode(s); // We are always in `Lines` form by the time we reach here. - assert!(self.lines.borrow().is_lines()); - self.lines(|lines| { - // Store the length. - s.emit_u32(lines.len() as u32); - - // Compute and store the difference list. - if lines.len() != 0 { - let max_line_length = if lines.len() == 1 { - 0 - } else { - lines - .array_windows() - .map(|&[fst, snd]| snd - fst) - .map(|bp| bp.to_usize()) - .max() - .unwrap() - }; - - let bytes_per_diff: usize = match max_line_length { - 0..=0xFF => 1, - 0x100..=0xFFFF => 2, - _ => 4, - }; - - // Encode the number of bytes used per diff. - s.emit_u8(bytes_per_diff as u8); - - // Encode the first element. - assert_eq!(lines[0], RelativeBytePos(0)); - - // Encode the difference list. - let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst); - let num_diffs = lines.len() - 1; - let mut raw_diffs; - match bytes_per_diff { - 1 => { - raw_diffs = Vec::with_capacity(num_diffs); - for diff in diff_iter { - raw_diffs.push(diff.0 as u8); - } + assert!(self.lines.read().is_lines()); + let lines = self.lines(); + // Store the length. + s.emit_u32(lines.len() as u32); + + // Compute and store the difference list. + if lines.len() != 0 { + let max_line_length = if lines.len() == 1 { + 0 + } else { + lines + .array_windows() + .map(|&[fst, snd]| snd - fst) + .map(|bp| bp.to_usize()) + .max() + .unwrap() + }; + + let bytes_per_diff: usize = match max_line_length { + 0..=0xFF => 1, + 0x100..=0xFFFF => 2, + _ => 4, + }; + + // Encode the number of bytes used per diff. + s.emit_u8(bytes_per_diff as u8); + + // Encode the first element. + assert_eq!(lines[0], RelativeBytePos(0)); + + // Encode the difference list. + let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst); + let num_diffs = lines.len() - 1; + let mut raw_diffs; + match bytes_per_diff { + 1 => { + raw_diffs = Vec::with_capacity(num_diffs); + for diff in diff_iter { + raw_diffs.push(diff.0 as u8); } - 2 => { - raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); - for diff in diff_iter { - raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes()); - } + } + 2 => { + raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); + for diff in diff_iter { + raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes()); } - 4 => { - raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); - for diff in diff_iter { - raw_diffs.extend_from_slice(&(diff.0).to_le_bytes()); - } + } + 4 => { + raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); + for diff in diff_iter { + raw_diffs.extend_from_slice(&(diff.0).to_le_bytes()); } - _ => unreachable!(), } - s.emit_raw_bytes(&raw_diffs); + _ => unreachable!(), } - }); + s.emit_raw_bytes(&raw_diffs); + } self.multibyte_chars.encode(s); self.non_narrow_chars.encode(s); @@ -1491,7 +1493,7 @@ impl Decodable for SourceFile { // Unused - the metadata decoder will construct // a new SourceFile, filling in `external_src` properly external_src: FreezeLock::frozen(ExternalSource::Unneeded), - lines: Lock::new(lines), + lines: FreezeLock::new(lines), multibyte_chars, non_narrow_chars, normalized_pos, @@ -1535,7 +1537,7 @@ impl SourceFile { external_src: FreezeLock::frozen(ExternalSource::Unneeded), start_pos: BytePos::from_u32(0), source_len: RelativeBytePos::from_u32(source_len), - lines: Lock::new(SourceFileLines::Lines(lines)), + lines: FreezeLock::frozen(SourceFileLines::Lines(lines)), multibyte_chars, non_narrow_chars, normalized_pos, @@ -1544,65 +1546,82 @@ impl SourceFile { }) } - pub fn lines(&self, f: F) -> R - where - F: FnOnce(&[RelativeBytePos]) -> R, - { - let mut guard = self.lines.borrow_mut(); - match &*guard { - SourceFileLines::Lines(lines) => f(lines), - SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }) => { - // Convert from "diffs" form to "lines" form. - let num_lines = num_diffs + 1; - let mut lines = Vec::with_capacity(num_lines); - let mut line_start = RelativeBytePos(0); - lines.push(line_start); - - assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff); - match bytes_per_diff { - 1 => { - lines.extend(raw_diffs.into_iter().map(|&diff| { - line_start = line_start + RelativeBytePos(diff as u32); - line_start - })); - } - 2 => { - lines.extend((0..*num_diffs).map(|i| { - let pos = bytes_per_diff * i; - let bytes = [raw_diffs[pos], raw_diffs[pos + 1]]; - let diff = u16::from_le_bytes(bytes); - line_start = line_start + RelativeBytePos(diff as u32); - line_start - })); - } - 4 => { - lines.extend((0..*num_diffs).map(|i| { - let pos = bytes_per_diff * i; - let bytes = [ - raw_diffs[pos], - raw_diffs[pos + 1], - raw_diffs[pos + 2], - raw_diffs[pos + 3], - ]; - let diff = u32::from_le_bytes(bytes); - line_start = line_start + RelativeBytePos(diff); - line_start - })); - } - _ => unreachable!(), - } - let res = f(&lines); - *guard = SourceFileLines::Lines(lines); - res + /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes it. + fn convert_diffs_to_lines_frozen(&self) { + let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return }; + + let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard { + SourceFileLines::Diffs(diffs) => diffs, + SourceFileLines::Lines(..) => { + FreezeWriteGuard::freeze(guard); + return; } + }; + + // Convert from "diffs" form to "lines" form. + let num_lines = num_diffs + 1; + let mut lines = Vec::with_capacity(num_lines); + let mut line_start = RelativeBytePos(0); + lines.push(line_start); + + assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff); + match bytes_per_diff { + 1 => { + lines.extend(raw_diffs.into_iter().map(|&diff| { + line_start = line_start + RelativeBytePos(diff as u32); + line_start + })); + } + 2 => { + lines.extend((0..*num_diffs).map(|i| { + let pos = bytes_per_diff * i; + let bytes = [raw_diffs[pos], raw_diffs[pos + 1]]; + let diff = u16::from_le_bytes(bytes); + line_start = line_start + RelativeBytePos(diff as u32); + line_start + })); + } + 4 => { + lines.extend((0..*num_diffs).map(|i| { + let pos = bytes_per_diff * i; + let bytes = [ + raw_diffs[pos], + raw_diffs[pos + 1], + raw_diffs[pos + 2], + raw_diffs[pos + 3], + ]; + let diff = u32::from_le_bytes(bytes); + line_start = line_start + RelativeBytePos(diff); + line_start + })); + } + _ => unreachable!(), + } + + *guard = SourceFileLines::Lines(lines); + + FreezeWriteGuard::freeze(guard); + } + + pub fn lines(&self) -> &[RelativeBytePos] { + if let Some(SourceFileLines::Lines(lines)) = self.lines.get() { + return &lines[..]; } + + cold_path(|| { + self.convert_diffs_to_lines_frozen(); + if let Some(SourceFileLines::Lines(lines)) = self.lines.get() { + return &lines[..]; + } + unreachable!() + }) } /// Returns the `BytePos` of the beginning of the current line. pub fn line_begin_pos(&self, pos: BytePos) -> BytePos { let pos = self.relative_position(pos); let line_index = self.lookup_line(pos).unwrap(); - let line_start_pos = self.lines(|lines| lines[line_index]); + let line_start_pos = self.lines()[line_index]; self.absolute_position(line_start_pos) } @@ -1662,7 +1681,7 @@ impl SourceFile { } let begin = { - let line = self.lines(|lines| lines.get(line_number).copied())?; + let line = self.lines().get(line_number).copied()?; line.to_usize() }; @@ -1686,7 +1705,7 @@ impl SourceFile { } pub fn count_lines(&self) -> usize { - self.lines(|lines| lines.len()) + self.lines().len() } #[inline] @@ -1709,7 +1728,7 @@ impl SourceFile { /// number. If the source_file is empty or the position is located before the /// first line, `None` is returned. pub fn lookup_line(&self, pos: RelativeBytePos) -> Option { - self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1)) + self.lines().partition_point(|x| x <= &pos).checked_sub(1) } pub fn line_bounds(&self, line_index: usize) -> Range { @@ -1717,15 +1736,13 @@ impl SourceFile { return self.start_pos..self.start_pos; } - self.lines(|lines| { - assert!(line_index < lines.len()); - if line_index == (lines.len() - 1) { - self.absolute_position(lines[line_index])..self.end_position() - } else { - self.absolute_position(lines[line_index]) - ..self.absolute_position(lines[line_index + 1]) - } - }) + let lines = self.lines(); + assert!(line_index < lines.len()); + if line_index == (lines.len() - 1) { + self.absolute_position(lines[line_index])..self.end_position() + } else { + self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1]) + } } /// Returns whether or not the file contains the given `SourceMap` byte @@ -1811,7 +1828,7 @@ impl SourceFile { match self.lookup_line(pos) { Some(a) => { let line = a + 1; // Line numbers start at 1 - let linebpos = self.lines(|lines| lines[a]); + let linebpos = self.lines()[a]; let linechpos = self.bytepos_to_file_charpos(linebpos); let col = chpos - linechpos; debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos); @@ -1831,7 +1848,7 @@ impl SourceFile { let (line, col_or_chpos) = self.lookup_file_pos(pos); if line > 0 { let col = col_or_chpos; - let linebpos = self.lines(|lines| lines[line - 1]); + let linebpos = self.lines()[line - 1]; let col_display = { let start_width_idx = self .non_narrow_chars diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 20bd57cae6d..68727a6c40e 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -328,7 +328,7 @@ impl SourceMap { name_hash: Hash128, source_len: u32, cnum: CrateNum, - file_local_lines: Lock, + file_local_lines: FreezeLock, multibyte_chars: Vec, non_narrow_chars: Vec, normalized_pos: Vec, diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 7689e6afac5..e393db02064 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -1,6 +1,6 @@ use super::*; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{FreezeLock, Lrc}; fn init_source_map() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); @@ -246,7 +246,7 @@ fn t10() { name_hash, source_len.to_u32(), CrateNum::new(0), - lines, + FreezeLock::new(lines.read().clone()), multibyte_chars, non_narrow_chars, normalized_pos, diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index a980ee8d9e0..cb88fa89058 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -7,9 +7,7 @@ fn test_lookup_line() { SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256) .unwrap(); sf.start_pos = BytePos(3); - sf.lines(|lines| { - assert_eq!(lines, &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]) - }); + assert_eq!(sf.lines(), &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]); assert_eq!(sf.lookup_line(RelativeBytePos(0)), Some(0)); assert_eq!(sf.lookup_line(RelativeBytePos(1)), Some(0)); diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index a1ea3a495eb..da8d8ed4c0f 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -507,20 +507,18 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - return unsafe_line.sf.lines(|lines| { - if comment_start_line.line >= unsafe_line.line { - HasSafetyComment::No - } else { - match text_has_safety_comment( - src, - &lines[comment_start_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } + return if comment_start_line.line >= unsafe_line.line { + HasSafetyComment::No + } else { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }); + }; } } HasSafetyComment::Maybe @@ -551,20 +549,18 @@ fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> H && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - return unsafe_line.sf.lines(|lines| { - if comment_start_line.line >= unsafe_line.line { - HasSafetyComment::No - } else { - match text_has_safety_comment( - src, - &lines[comment_start_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } + return if comment_start_line.line >= unsafe_line.line { + HasSafetyComment::No + } else { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }); + }; } } HasSafetyComment::Maybe @@ -614,20 +610,18 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span && Lrc::ptr_eq(&unsafe_line.sf, ¯o_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - unsafe_line.sf.lines(|lines| { - if macro_line.line < unsafe_line.line { - match text_has_safety_comment( - src, - &lines[macro_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } - } else { - HasSafetyComment::No + if macro_line.line < unsafe_line.line { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }) + } else { + HasSafetyComment::No + } } else { // Problem getting source text. Pretend a comment was found. HasSafetyComment::Maybe @@ -671,13 +665,11 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { // Get the text from the start of function body to the unsafe block. // fn foo() { some_stuff; unsafe { stuff }; other_stuff; } // ^-------------^ - unsafe_line.sf.lines(|lines| { - body_line.line < unsafe_line.line && text_has_safety_comment( - src, - &lines[body_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ).is_some() - }) + body_line.line < unsafe_line.line && text_has_safety_comment( + src, + &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ).is_some() } else { // Problem getting source text. Pretend a comment was found. true diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 03416d35ba4..600cd084c19 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -118,7 +118,7 @@ fn first_char_in_first_line(cx: &T, span: Span) -> Option(cx: &T, span: Span) -> Span { let span = original_sp(span, DUMMY_SP); let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap(); - let line_start = sf.lines(|lines| lines[line]); + let line_start = sf.lines()[line]; let line_start = sf.absolute_position(line_start); span.with_lo(line_start) } -- cgit 1.4.1-3-g733a5 From caf6ce5ea28e7bf3ab0eeac21bfce5e3013e3347 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 28 Jul 2023 20:44:25 +0200 Subject: Stabilize `PATH` option for `--print KIND=PATH` Description of the `PATH` option: > A filepath may optionally be specified for each requested information > kind, in the format `--print KIND=PATH`, just like for `--emit`. When > a path is specified, information will be written there instead of to > stdout. --- compiler/rustc_session/src/config.rs | 6 ------ src/doc/rustc/src/command-line-arguments.md | 4 ++++ src/doc/unstable-book/src/compiler-flags/path-options.md | 11 ----------- tests/run-make/print-cfg/Makefile | 8 ++++---- tests/ui/feature-gates/print-with-path.cfg.stderr | 2 -- tests/ui/feature-gates/print-with-path.rs | 7 ------- tests/ui/feature-gates/print-with-path.target-cpus.stderr | 2 -- tests/ui/feature-gates/print-with-path.target-features.stderr | 2 -- 8 files changed, 8 insertions(+), 34 deletions(-) delete mode 100644 src/doc/unstable-book/src/compiler-flags/path-options.md delete mode 100644 tests/ui/feature-gates/print-with-path.cfg.stderr delete mode 100644 tests/ui/feature-gates/print-with-path.rs delete mode 100644 tests/ui/feature-gates/print-with-path.target-cpus.stderr delete mode 100644 tests/ui/feature-gates/print-with-path.target-features.stderr (limited to 'src') diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f00472f181d..302e4e55d59 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2160,12 +2160,6 @@ fn collect_print_requests( prints.extend(matches.opt_strs("print").into_iter().map(|req| { let (req, out) = split_out_file_name(&req); - if out.is_some() && !unstable_opts.unstable_options { - handler.early_error( - "the `-Z unstable-options` flag must also be passed to \ - enable the path print option", - ); - } let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) { Some((_, PrintKind::TargetSpec)) => { if unstable_opts.unstable_options { diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 2c7c05c0c4b..4d32897cc14 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -260,6 +260,10 @@ The valid types of print values are: This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable is present in the environment, or otherwise returns the variable's parsed value. +A filepath may optionally be specified for each requested information kind, in +the format `--print KIND=PATH`, just like for `--emit`. When a path is +specified, information will be written there instead of to stdout. + [conditional compilation]: ../reference/conditional-compilation.html [deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html diff --git a/src/doc/unstable-book/src/compiler-flags/path-options.md b/src/doc/unstable-book/src/compiler-flags/path-options.md deleted file mode 100644 index 0786ef1f166..00000000000 --- a/src/doc/unstable-book/src/compiler-flags/path-options.md +++ /dev/null @@ -1,11 +0,0 @@ -# `--print` Options - -The behavior of the `--print` flag can be modified by optionally be specifying a filepath -for each requested information kind, in the format `--print KIND=PATH`, just like for -`--emit`. When a path is specified, information will be written there instead of to stdout. - -This is unstable feature, so you have to provide `-Zunstable-options` to enable it. - -## Examples - -`rustc main.rs -Z unstable-options --print cfg=cfgs.txt` diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile index 654c303b3e2..6b153e5b54e 100644 --- a/tests/run-make/print-cfg/Makefile +++ b/tests/run-make/print-cfg/Makefile @@ -13,19 +13,19 @@ all: default output_to_file output_to_file: # Backend-independent, printed by rustc_driver_impl/src/lib.rs - $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt -Z unstable-options + $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt $(CGREP) windows < $(TMPDIR)/cfg.txt # Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs - $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt -Z unstable-options + $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt $(CGREP) dynamic-no-pic < $(TMPDIR)/relocation-models.txt # Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs - $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt -Z unstable-options + $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt $(CGREP) reference-types < $(TMPDIR)/target-features.txt # Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp - $(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt -Z unstable-options + $(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt $(CGREP) generic < $(TMPDIR)/target-cpus.txt ifdef IS_WINDOWS diff --git a/tests/ui/feature-gates/print-with-path.cfg.stderr b/tests/ui/feature-gates/print-with-path.cfg.stderr deleted file mode 100644 index a6c51baa320..00000000000 --- a/tests/ui/feature-gates/print-with-path.cfg.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - diff --git a/tests/ui/feature-gates/print-with-path.rs b/tests/ui/feature-gates/print-with-path.rs deleted file mode 100644 index f929c14c218..00000000000 --- a/tests/ui/feature-gates/print-with-path.rs +++ /dev/null @@ -1,7 +0,0 @@ -// check-fail -// revisions: cfg target-features target-cpus -// [cfg]compile-flags: --print cfg=cfg.txt -// [target-cpus]compile-flags: --print target-cpu=target_cpu.txt -// [target-features]compile-flags: --print target-features=target_features.txt - -fn main() {} diff --git a/tests/ui/feature-gates/print-with-path.target-cpus.stderr b/tests/ui/feature-gates/print-with-path.target-cpus.stderr deleted file mode 100644 index a6c51baa320..00000000000 --- a/tests/ui/feature-gates/print-with-path.target-cpus.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - diff --git a/tests/ui/feature-gates/print-with-path.target-features.stderr b/tests/ui/feature-gates/print-with-path.target-features.stderr deleted file mode 100644 index a6c51baa320..00000000000 --- a/tests/ui/feature-gates/print-with-path.target-features.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - -- cgit 1.4.1-3-g733a5 From 00b7d70710aa34e495a91727fe3e5bd7f97ae55e Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 7 Sep 2023 13:05:30 -0700 Subject: rustdoc: remove unused ID `mainThemeStyle` This was added in 003b2bc1c65251ec2fc80b78ed91c43fb35402ec and used to build the URL of the theme stylesheets. It isn't used any more, because f9e1f6ffdf03ec33cb29e20c88fc7bcc938c7f42 changed it so that the URL was supplied in a `` tag, which also provides the hashes of the files. --- src/librustdoc/html/markdown.rs | 1 - src/librustdoc/html/templates/page.html | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 98cc38a10d4..a8d85fb6fb4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1574,7 +1574,6 @@ fn init_id_map() -> FxHashMap, usize> { map.insert("crate-search-div".into(), 1); // This is the list of IDs used in HTML generated in Rust (including the ones // used in tera template files). - map.insert("mainThemeStyle".into(), 1); map.insert("themeStyle".into(), 1); map.insert("settings-menu".into(), 1); map.insert("help-button".into(), 1); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 60ccfe4da44..8cb43634377 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -15,8 +15,7 @@ {# #} {# #} + href="{{static_root_path|safe}}{{files.rustdoc_css}}"> {# #} {% if !layout.default_settings.is_empty() %}