From 64fa12a4fb1447e3368ae2cd08cf75ea576997ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 15 Aug 2023 10:10:35 +0200 Subject: [PATCH 1/9] rustdoc: hide repr(transparent) if it isn't part of the public ABI --- src/doc/rustdoc/src/advanced-features.md | 20 ++++++++ src/librustdoc/clean/types.rs | 51 +++++++++++++------ src/librustdoc/html/render/mod.rs | 16 +++--- src/librustdoc/html/render/print_item.rs | 23 ++++----- src/librustdoc/json/conversions.rs | 3 +- tests/rustdoc/inline_cross/attributes.rs | 7 +++ .../inline_cross/auxiliary/attributes.rs | 2 + tests/rustdoc/inline_cross/auxiliary/repr.rs | 22 +++++++- tests/rustdoc/inline_cross/repr.rs | 21 ++++++-- tests/rustdoc/repr.rs | 29 +++++++++++ 10 files changed, 152 insertions(+), 42 deletions(-) create mode 100644 tests/rustdoc/inline_cross/attributes.rs create mode 100644 tests/rustdoc/inline_cross/auxiliary/attributes.rs create mode 100644 tests/rustdoc/repr.rs diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index dbf0baec04c03..1733c8fc9a246 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -110,3 +110,23 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL to automatically go to the first result. + +## `#[repr(transparent)]`: Documenting the transparent representation + +You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and +in the [Rustonomicon][repr-trans-nomicon]. + +Since this representation is only considered part of the public ABI if the single field with non-trivial +size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays +the attribute if and only if the non-1-ZST field is public or at least one field is public in case all +fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized. + +It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]` +if one wishes to declare the representation as private even if the non-1-ZST field is public. +However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work. +Therefore, if you would like to do so, you should always write it down in prose independently of whether +you use `cfg_attr` or not. + +[repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation +[repr-trans-nomicon]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent +[cross-crate-cfg-doc]: https://github.com/rust-lang/rust/issues/114952 diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b276745f3170b..ecbe7017bf199 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -709,12 +709,16 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec { + pub(crate) fn attributes( + &self, + tcx: TyCtxt<'_>, + cache: &Cache, + keep_as_is: bool, + ) -> Vec { const ALLOWED_ATTRIBUTES: &[Symbol] = - &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive]; + &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; use rustc_abi::IntegerType; - use rustc_middle::ty::ReprFlags; let mut attrs: Vec = self .attrs @@ -735,20 +739,38 @@ impl Item { } }) .collect(); - if let Some(def_id) = self.def_id() && - !def_id.is_local() && - // This check is needed because `adt_def` will panic if not a compatible type otherwise... - matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) + if !keep_as_is + && let Some(def_id) = self.def_id() + && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() { - let repr = tcx.adt_def(def_id).repr(); + let adt = tcx.adt_def(def_id); + let repr = adt.repr(); let mut out = Vec::new(); - if repr.flags.contains(ReprFlags::IS_C) { + if repr.c() { out.push("C"); } - if repr.flags.contains(ReprFlags::IS_TRANSPARENT) { - out.push("transparent"); + if repr.transparent() { + // Render `repr(transparent)` iff the non-1-ZST field is public or at least one + // field is public in case all fields are 1-ZST fields. + let render_transparent = cache.document_private + || adt + .all_fields() + .find(|field| { + let ty = + field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); + tcx.layout_of(tcx.param_env(field.did).and(ty)) + .is_ok_and(|layout| !layout.is_1zst()) + }) + .map_or_else( + || adt.all_fields().any(|field| field.vis.is_public()), + |field| field.vis.is_public(), + ); + + if render_transparent { + out.push("transparent"); + } } - if repr.flags.contains(ReprFlags::IS_SIMD) { + if repr.simd() { out.push("simd"); } let pack_s; @@ -773,10 +795,9 @@ impl Item { }; out.push(&int_s); } - if out.is_empty() { - return Vec::new(); + if !out.is_empty() { + attrs.push(format!("#[repr({})]", out.join(", "))); } - attrs.push(format!("#[repr({})]", out.join(", "))); } attrs } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f70f59d3be389..04889ba710ce9 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -856,10 +856,10 @@ fn assoc_method( let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; let indent_str = " "; - write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx)); + write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx)); (4, indent_str, Ending::NoNewline) } else { - render_attributes_in_code(w, meth, tcx); + render_attributes_in_code(w, meth, cx); (0, "", Ending::Newline) }; w.reserve(header_len + "{".len() + "".len()); @@ -1035,13 +1035,13 @@ fn render_assoc_item( // When an attribute is rendered inside a `
` tag, it is formatted using
 // a whitespace prefix and newline.
-fn render_attributes_in_pre<'a, 'b: 'a>(
+fn render_attributes_in_pre<'a, 'tcx: 'a>(
     it: &'a clean::Item,
     prefix: &'a str,
-    tcx: TyCtxt<'b>,
-) -> impl fmt::Display + Captures<'a> + Captures<'b> {
+    cx: &'a Context<'tcx>,
+) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
     crate::html::format::display_fn(move |f| {
-        for a in it.attributes(tcx, false) {
+        for a in it.attributes(cx.tcx(), cx.cache(), false) {
             writeln!(f, "{prefix}{a}")?;
         }
         Ok(())
@@ -1050,8 +1050,8 @@ fn render_attributes_in_pre<'a, 'b: 'a>(
 
 // When an attribute is rendered inside a  tag, it is formatted using
 // a div to produce a newline after it.
-fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, tcx: TyCtxt<'_>) {
-    for attr in it.attributes(tcx, false) {
+fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
+    for attr in it.attributes(cx.tcx(), cx.cache(), false) {
         write!(w, "
{attr}
").unwrap(); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index c6751c9585ee9..209d71c4f3ba7 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -117,8 +117,7 @@ macro_rules! item_template_methods { fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { let (item, cx) = self.item_and_mut_cx(); - let tcx = cx.tcx(); - let v = render_attributes_in_pre(item, "", tcx); + let v = render_attributes_in_pre(item, "", &cx); write!(f, "{v}") }) } @@ -656,7 +655,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle w, "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", - attrs = render_attributes_in_pre(it, "", tcx), + attrs = render_attributes_in_pre(it, "", cx), vis = visibility, constness = constness, asyncness = asyncness, @@ -691,7 +690,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write!( w, "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}", - attrs = render_attributes_in_pre(it, "", tcx), + attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), unsafety = t.unsafety(tcx).print_with_space(), is_auto = if t.is_auto(tcx) { "auto " } else { "" }, @@ -1170,7 +1169,7 @@ fn item_trait_alias( write!( w, "{attrs}trait {name}{generics}{where_b} = {bounds};", - attrs = render_attributes_in_pre(it, "", cx.tcx()), + attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), generics = t.generics.print(cx), where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline), @@ -1198,7 +1197,7 @@ fn item_opaque_ty( write!( w, "{attrs}type {name}{generics}{where_clause} = impl {bounds};", - attrs = render_attributes_in_pre(it, "", cx.tcx()), + attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), generics = t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), @@ -1223,7 +1222,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!( w, "{attrs}{vis}type {name}{generics}{where_clause} = {type_};", - attrs = render_attributes_in_pre(it, "", cx.tcx()), + attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), name = it.name.unwrap(), generics = t.generics.print(cx), @@ -1408,7 +1407,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let tcx = cx.tcx(); let count_variants = e.variants().count(); wrap_item(w, |w| { - render_attributes_in_code(w, it, tcx); + render_attributes_in_code(w, it, cx); write!( w, "{}enum {}{}", @@ -1644,7 +1643,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { wrap_item(w, |w| { let tcx = cx.tcx(); - render_attributes_in_code(w, it, tcx); + render_attributes_in_code(w, it, cx); write!( w, @@ -1693,7 +1692,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { wrap_item(w, |w| { - render_attributes_in_code(w, it, cx.tcx()); + render_attributes_in_code(w, it, cx); render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); }); @@ -1753,7 +1752,7 @@ fn item_fields( fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_item(w, |buffer| { - render_attributes_in_code(buffer, it, cx.tcx()); + render_attributes_in_code(buffer, it, cx); write!( buffer, "{vis}static {mutability}{name}: {typ}", @@ -1771,7 +1770,7 @@ fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) { wrap_item(w, |buffer| { buffer.write_str("extern {\n").unwrap(); - render_attributes_in_code(buffer, it, cx.tcx()); + render_attributes_in_code(buffer, it, cx); write!( buffer, " {}type {};\n}}", diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0886501596056..47e50107b520c 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -18,6 +18,7 @@ use rustdoc_json_types::*; use crate::clean::{self, ItemId}; use crate::formats::item_type::ItemType; +use crate::formats::FormatRenderer; use crate::json::JsonRenderer; use crate::passes::collect_intra_doc_links::UrlFragment; @@ -41,7 +42,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes(self.tcx, true); + let attrs = item.attributes(self.tcx, self.cache(), true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::Item { name, item_id, .. } = item; diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc/inline_cross/attributes.rs new file mode 100644 index 0000000000000..c0b75c48fee91 --- /dev/null +++ b/tests/rustdoc/inline_cross/attributes.rs @@ -0,0 +1,7 @@ +// aux-crate:attributes=attributes.rs +// edition:2021 +#![crate_name = "user"] + +// @has 'user/struct.NonExhaustive.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]' +pub use attributes::NonExhaustive; diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc/inline_cross/auxiliary/attributes.rs new file mode 100644 index 0000000000000..c6f155d4ba5a9 --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/attributes.rs @@ -0,0 +1,2 @@ +#[non_exhaustive] +pub struct NonExhaustive; diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs index 4a6648a643980..35f08c11b7b3a 100644 --- a/tests/rustdoc/inline_cross/auxiliary/repr.rs +++ b/tests/rustdoc/inline_cross/auxiliary/repr.rs @@ -10,7 +10,7 @@ pub struct ReprSimd { } #[repr(transparent)] pub struct ReprTransparent { - field: u8, + pub field: u8, } #[repr(isize)] pub enum ReprIsize { @@ -20,3 +20,23 @@ pub enum ReprIsize { pub enum ReprU8 { Bla, } + +#[repr(transparent)] // private +pub struct ReprTransparentPrivField { + field: u32, // non-1-ZST field +} + +#[repr(transparent)] // public +pub struct ReprTransparentPriv1ZstFields { + marker0: Marker, + pub main: u64, // non-1-ZST field + marker1: Marker, +} + +#[repr(transparent)] // private +pub struct ReprTransparentPrivFieldPub1ZstFields { + main: [u16; 0], // non-1-ZST field + pub marker: Marker, +} + +pub struct Marker; // 1-ZST diff --git a/tests/rustdoc/inline_cross/repr.rs b/tests/rustdoc/inline_cross/repr.rs index 9e107cee9e91b..2f3d8f0038846 100644 --- a/tests/rustdoc/inline_cross/repr.rs +++ b/tests/rustdoc/inline_cross/repr.rs @@ -9,21 +9,32 @@ extern crate repr; // @has 'foo/struct.ReprC.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]' -#[doc(inline)] pub use repr::ReprC; // @has 'foo/struct.ReprSimd.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]' -#[doc(inline)] pub use repr::ReprSimd; // @has 'foo/struct.ReprTransparent.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -#[doc(inline)] pub use repr::ReprTransparent; // @has 'foo/enum.ReprIsize.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]' -#[doc(inline)] pub use repr::ReprIsize; // @has 'foo/enum.ReprU8.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]' -#[doc(inline)] pub use repr::ReprU8; + +// Regression test for . +// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one +// field is public in case all fields are 1-ZST fields. + +// @has 'foo/struct.ReprTransparentPrivField.html' +// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +pub use repr::ReprTransparentPrivField; + +// @has 'foo/struct.ReprTransparentPriv1ZstFields.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +pub use repr::ReprTransparentPriv1ZstFields; + +// @has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html' +// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +pub use repr::ReprTransparentPrivFieldPub1ZstFields; diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc/repr.rs new file mode 100644 index 0000000000000..fbb46e126ba6a --- /dev/null +++ b/tests/rustdoc/repr.rs @@ -0,0 +1,29 @@ +// Regression test for . +// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one +// field is public in case all fields are 1-ZST fields. + +// @has 'repr/struct.ReprTransparentPrivField.html' +// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // private +pub struct ReprTransparentPrivField { + field: u32, // non-1-ZST field +} + +// @has 'repr/struct.ReprTransparentPriv1ZstFields.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // public +pub struct ReprTransparentPriv1ZstFields { + marker0: Marker, + pub main: u64, // non-1-ZST field + marker1: Marker, +} + +// @has 'repr/struct.ReprTransparentPub1ZstField.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // public +pub struct ReprTransparentPub1ZstField { + marker0: Marker, + pub marker1: Marker, +} + +struct Marker; // 1-ZST From 58d62fc271457a5d1cfdfc947c5039df6326a45e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 10 Oct 2023 16:59:49 +1100 Subject: [PATCH 2/9] Don't accidentally detect the commit hash as an `fadd` instruction --- tests/codegen/target-feature-inline-closure.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/codegen/target-feature-inline-closure.rs b/tests/codegen/target-feature-inline-closure.rs index d075706173fd1..54cb27242d5a7 100644 --- a/tests/codegen/target-feature-inline-closure.rs +++ b/tests/codegen/target-feature-inline-closure.rs @@ -31,3 +31,7 @@ unsafe fn without_avx(x: __m256) -> __m256 { }; add(x, x) } + +// Don't allow the above CHECK-NOT to accidentally match a commit hash in the +// compiler version. +// CHECK-LABEL: rustc version From 361c1641741238baa5a52da255ced6cbe506e5d2 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 10 Oct 2023 18:52:50 +0300 Subject: [PATCH 3/9] sort/reorganize dependencies in bootstrap/Cargo.toml Signed-off-by: onur-ozkan --- src/bootstrap/Cargo.toml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 9bf26948af3aa..8363992309ab6 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -31,12 +31,18 @@ test = false [dependencies] build_helper = { path = "../tools/build_helper" } +cc = "1.0.69" +clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } +clap_complete = "4.2.2" cmake = "0.1.38" filetime = "0.2" -cc = "1.0.69" -libc = "0.2" hex = "0.4" +ignore = "0.4.10" +libc = "0.2" object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } +once_cell = "1.7.2" +opener = "0.5" +semver = "1.0.17" serde = "1.0.137" # Directly use serde_derive rather than through the derive feature of serde to allow building both # in parallel and to allow serde_json and toml to start building as soon as serde has been built. @@ -46,17 +52,11 @@ sha2 = "0.10" tar = "0.4" termcolor = "1.2.0" toml = "0.5" -ignore = "0.4.10" -opener = "0.5" -once_cell = "1.7.2" -xz2 = "0.1" walkdir = "2" +xz2 = "0.1" # Dependencies needed by the build-metrics feature sysinfo = { version = "0.26.0", optional = true } -clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } -clap_complete = "4.2.2" -semver = "1.0.17" # Solaris doesn't support flock() and thus fd-lock is not option now [target.'cfg(not(target_os = "solaris"))'.dependencies] From acaec5ca463133811b383f0a819082979e6513b0 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 10 Oct 2023 18:53:23 +0300 Subject: [PATCH 4/9] move `features` above to appear before others sections Signed-off-by: onur-ozkan --- src/bootstrap/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 8363992309ab6..7e72e87710486 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -5,6 +5,9 @@ edition = "2021" build = "build.rs" default-run = "bootstrap" +[features] +build-metrics = ["sysinfo"] + [lib] path = "lib.rs" doctest = false @@ -80,9 +83,6 @@ features = [ [dev-dependencies] pretty_assertions = "1.4" -[features] -build-metrics = ["sysinfo"] - # We care a lot about bootstrap's compile times, so don't include debuginfo for # dependencies, only bootstrap itself. [profile.dev] From b3c95c522ca838a4709b4a55539a9653fe9eb7c6 Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Sat, 14 Oct 2023 09:35:31 +0000 Subject: [PATCH 5/9] Fix broken build on ESP-IDF caused by #115108 --- library/std/src/sys/unix/process/mod.rs | 8 ++++++-- .../src/sys/unix/process/process_unsupported.rs | 4 ++-- .../process/process_unsupported/wait_status.rs | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 0cf163d9fb8e9..947ef4c8aeff5 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -6,6 +6,9 @@ pub use crate::sys_common::process::CommandEnvs; #[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))] mod process_common; +#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] +mod process_unsupported; + cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { #[path = "process_fuchsia.rs"] @@ -15,8 +18,9 @@ cfg_if::cfg_if! { #[path = "process_vxworks.rs"] mod process_inner; } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] { - #[path = "process_unsupported.rs"] - mod process_inner; + mod process_inner { + pub use super::process_unsupported::*; + } } else { #[path = "process_unix.rs"] mod process_inner; diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs index 325d3f23be7c2..2fbb31922653c 100644 --- a/library/std/src/sys/unix/process/process_unsupported.rs +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -63,12 +63,12 @@ pub struct ExitStatusError(NonZero_c_int); impl Into for ExitStatusError { fn into(self) -> ExitStatus { - ExitStatus(self.0.into()) + ExitStatus::from(c_int::from(self.0)) } } impl ExitStatusError { pub fn code(self) -> Option { - ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) + ExitStatus::from(c_int::from(self.0)).code().map(|st| st.try_into().unwrap()) } } diff --git a/library/std/src/sys/unix/process/process_unsupported/wait_status.rs b/library/std/src/sys/unix/process/process_unsupported/wait_status.rs index 3c649db1a35e5..72b7ae18cff27 100644 --- a/library/std/src/sys/unix/process/process_unsupported/wait_status.rs +++ b/library/std/src/sys/unix/process/process_unsupported/wait_status.rs @@ -1,10 +1,13 @@ //! Emulated wait status for non-Unix #[cfg(unix) platforms //! //! Separate module to facilitate testing against a real Unix implementation. +use core::ffi::NonZero_c_int; use crate::ffi::c_int; use crate::fmt; +use super::ExitStatusError; + /// Emulated wait status for use by `process_unsupported.rs` /// /// Uses the "traditional unix" encoding. For use on platfors which are `#[cfg(unix)]` @@ -40,6 +43,19 @@ impl ExitStatus { if (w & 0x7f) == 0 { Some((w & 0xff00) >> 8) } else { None } } + #[allow(unused)] + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is + // true on all actual versions of Unix, is widely assumed, and is specified in SuS + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not + // true for a platform pretending to be Unix, the tests (our doctests, and also + // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. + match NonZero_c_int::try_from(self.wait_status) { + /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), + /* was zero, couldn't convert */ Err(_) => Ok(()), + } + } + pub fn signal(&self) -> Option { let signal = self.wait_status & 0x007f; if signal > 0 && signal < 0x7f { Some(signal) } else { None } From aab3b9327ed2233da15e57b1d552473549e15300 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 14 Oct 2023 00:57:50 +0200 Subject: [PATCH 6/9] Propagate pattern errors via a new `PatKind::Error` variant Instead of via `Const::new_error` --- compiler/rustc_middle/src/thir.rs | 31 ++++++++++++++++--- compiler/rustc_middle/src/thir/visit.rs | 2 +- .../rustc_mir_build/src/build/matches/mod.rs | 5 ++- .../src/build/matches/simplify.rs | 2 +- .../rustc_mir_build/src/build/matches/test.rs | 6 ++-- .../rustc_mir_build/src/check_unsafety.rs | 3 +- .../src/thir/pattern/check_match.rs | 4 +-- .../src/thir/pattern/const_to_pat.rs | 22 +++++-------- .../src/thir/pattern/deconstruct_pat.rs | 4 +++ .../rustc_mir_build/src/thir/pattern/mod.rs | 1 + compiler/rustc_mir_build/src/thir/print.rs | 3 ++ .../typeid-equality-by-subtyping.stderr | 14 +-------- 12 files changed, 56 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 08f7434a4a9c8..67804998a3293 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -19,11 +19,12 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarArgs}; -use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; +use rustc_middle::ty::{ + self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty, + UpvarArgs, +}; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; @@ -632,7 +633,7 @@ impl<'tcx> Pat<'tcx> { use PatKind::*; match &self.kind { - Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {} + Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } => subpattern.walk_(it), @@ -647,6 +648,21 @@ impl<'tcx> Pat<'tcx> { } } + /// Whether the pattern has a `PatKind::Error` nested within. + pub fn pat_error_reported(&self) -> Result<(), ErrorGuaranteed> { + let mut error = None; + self.walk(|pat| { + if let PatKind::Error(e) = pat.kind && error.is_none() { + error = Some(e); + } + error.is_none() + }); + match error { + None => Ok(()), + Some(e) => Err(e), + } + } + /// Walk the pattern in left-to-right order. /// /// If you always want to recurse, prefer this method over `walk`. @@ -771,6 +787,10 @@ pub enum PatKind<'tcx> { Or { pats: Box<[Box>]>, }, + + /// An error has been encountered during lowering. We probably shouldn't report more lints + /// related to this pattern. + Error(ErrorGuaranteed), } #[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)] @@ -934,6 +954,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } Ok(()) } + PatKind::Error(_) => write!(f, ""), } } } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index b84e15688848b..afb58438519cc 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -226,7 +226,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' is_primary: _, name: _, } => visitor.visit_pat(&subpattern), - Binding { .. } | Wild => {} + Binding { .. } | Wild | Error(_) => {} Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => { for subpattern in subpatterns { visitor.visit_pat(&subpattern.pattern); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index eb1c6a9824a47..ab3ffabe29790 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -814,7 +814,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {} + PatKind::Constant { .. } + | PatKind::Range { .. } + | PatKind::Wild + | PatKind::Error(_) => {} PatKind::Deref { ref subpattern } => { self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 17ac1f4e0cea6..f340feb40d4a7 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -168,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } - PatKind::Wild => { + PatKind::Wild | PatKind::Error(_) => { // nothing left to do Ok(()) } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 795d1db8eecda..dde3702ca634c 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -77,7 +77,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Wild | PatKind::Binding { .. } | PatKind::Leaf { .. } - | PatKind::Deref { .. } => self.error_simplifiable(match_pair), + | PatKind::Deref { .. } + | PatKind::Error(_) => self.error_simplifiable(match_pair), } } @@ -111,7 +112,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Binding { .. } | PatKind::AscribeUserType { .. } | PatKind::Leaf { .. } - | PatKind::Deref { .. } => { + | PatKind::Deref { .. } + | PatKind::Error(_) => { // don't know how to add these patterns to a switch false } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 192bd4a83e3ed..6cf2ecc51e9e0 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -224,7 +224,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns PatKind::Or { .. } | - PatKind::AscribeUserType { .. } => {} + PatKind::AscribeUserType { .. } | + PatKind::Error(_) => {} } }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 93434dd3cc290..5caf37f5b0641 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -19,7 +19,7 @@ use rustc_hir::HirId; use rustc_middle::thir::visit::{self, Visitor}; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; @@ -683,7 +683,7 @@ fn non_exhaustive_match<'p, 'tcx>( expr_span: Span, ) -> ErrorGuaranteed { for &arm in arms { - if let Err(err) = thir[arm].pattern.error_reported() { + if let Err(err) = thir[arm].pattern.pat_error_reported() { return err; } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index fde6defd87f1b..32d389c4354c7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -196,9 +196,7 @@ impl<'tcx> ConstToPat<'tcx> { }; // All branches above emitted an error. Don't print any more lints. // We errored. Signal that in the pattern, so that follow up errors can be silenced. - let kind = PatKind::Constant { - value: mir::Const::Ty(ty::Const::new_error(self.tcx(), e, cv.ty())), - }; + let kind = PatKind::Error(e); return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); } else if !self.saw_const_match_lint.get() { if let Some(mir_structural_match_violation) = mir_structural_match_violation { @@ -351,7 +349,7 @@ impl<'tcx> ConstToPat<'tcx> { let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty }); self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } + PatKind::Error(e) } ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,); @@ -359,7 +357,7 @@ impl<'tcx> ConstToPat<'tcx> { let e = tcx.sess.emit_err(err); self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } + PatKind::Error(e) } ty::Adt(adt_def, args) if adt_def.is_enum() => { let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap(); @@ -434,17 +432,13 @@ impl<'tcx> ConstToPat<'tcx> { } else { if let Some(e) = self.saw_const_match_error.get() { // We already errored. Signal that in the pattern, so that follow up errors can be silenced. - PatKind::Constant { - value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)), - } + PatKind::Error(e) } else { let err = TypeNotStructural { span, non_sm_ty: *pointee_ty }; let e = tcx.sess.emit_err(err); self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. - PatKind::Constant { - value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)), - } + PatKind::Error(e) } } } @@ -456,9 +450,7 @@ impl<'tcx> ConstToPat<'tcx> { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; let e = tcx.sess.emit_err(err); // We errored. Signal that in the pattern, so that follow up errors can be silenced. - PatKind::Constant { - value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)), - } + PatKind::Error(e) } else { let old = self.behind_reference.replace(true); // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when @@ -489,7 +481,7 @@ impl<'tcx> ConstToPat<'tcx> { let e = tcx.sess.emit_err(err); self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } + PatKind::Error(e) } }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index a7a000ba31c6f..bbc0aeb66cfda 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1525,6 +1525,10 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let pats = expand_or_pat(pat); fields = Fields::from_iter(cx, pats.into_iter().map(mkpat)); } + PatKind::Error(_) => { + ctor = Opaque; + fields = Fields::empty(); + } } DeconstructedPat::new(ctor, fields, pat.ty, pat.span) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 25726c5a8725e..400ff16acceb8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -791,6 +791,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { match *self { PatKind::Wild => PatKind::Wild, + PatKind::Error(e) => PatKind::Error(e), PatKind::AscribeUserType { ref subpattern, ascription: Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 3b6276cfeb0e6..c957611b975c7 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -757,6 +757,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "]", depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } + PatKind::Error(_) => { + print_indented!(self, "Error", depth_lvl + 1); + } } print_indented!(self, "}", depth_lvl); diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr index 69bc174b6beeb..8cbd12654480a 100644 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr @@ -7,17 +7,5 @@ LL | WHAT_A_TYPE => 0, = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error[E0015]: cannot match on `TypeId` in constant functions - --> $DIR/typeid-equality-by-subtyping.rs:18:9 - | -LL | WHAT_A_TYPE => 0, - | ^^^^^^^^^^^ - | - = note: `TypeId` cannot be compared in compile-time, and therefore cannot be used in `match`es -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0015`. From 8646afb9c5ddad4e7c6805390d5265db54203f0d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 14 Oct 2023 01:49:41 +0200 Subject: [PATCH 7/9] Use `PatKind::Error` instead of `PatKind::Wild` to report errors --- .../src/thir/pattern/check_match.rs | 6 +++ .../rustc_mir_build/src/thir/pattern/mod.rs | 41 +++++++++---------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 5caf37f5b0641..064afed9f7d44 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -426,6 +426,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { #[instrument(level = "trace", skip(self))] fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option) { + // If we got errors while lowering, don't emit anything more. + if let Err(err) = pat.pat_error_reported() { + self.error = Err(err); + return; + } + let mut cx = self.new_cx(self.lint_level, false); let pattern = self.lower_pattern(&mut cx, pat); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 400ff16acceb8..76ed6d2b6d73d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -252,10 +252,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); - // FIXME?: returning `_` can cause inaccurate "unreachable" warnings. This can be - // fixed by returning `PatKind::Const(ConstKind::Error(...))` if #115937 gets - // merged. - self.lower_pattern_range(lo_expr, hi_expr, end, ty, span).unwrap_or(PatKind::Wild) + self.lower_pattern_range(lo_expr, hi_expr, end, ty, span) + .unwrap_or_else(PatKind::Error) } hir::PatKind::Path(ref qpath) => { @@ -423,9 +421,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if adt_def.is_enum() { let args = match ty.kind() { ty::Adt(_, args) | ty::FnDef(_, args) => args, - ty::Error(_) => { + ty::Error(e) => { // Avoid ICE (#50585) - return PatKind::Wild; + return PatKind::Error(*e); } _ => bug!("inappropriate type for def: {:?}", ty), }; @@ -452,7 +450,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { | Res::SelfTyAlias { .. } | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, _ => { - match res { + let e = match res { Res::Def(DefKind::ConstParam, _) => { self.tcx.sess.emit_err(ConstParamInPattern { span }) } @@ -461,7 +459,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } _ => self.tcx.sess.emit_err(NonConstPath { span }), }; - PatKind::Wild + PatKind::Error(e) } }; @@ -513,14 +511,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // It should be assoc consts if there's no error but we cannot resolve it. debug_assert!(is_associated_const); - self.tcx.sess.emit_err(AssocConstInPattern { span }); - - return pat_from_kind(PatKind::Wild); + let e = self.tcx.sess.emit_err(AssocConstInPattern { span }); + return pat_from_kind(PatKind::Error(e)); } Err(_) => { - self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); - return pat_from_kind(PatKind::Wild); + let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); + return pat_from_kind(PatKind::Error(e)); } }; @@ -574,12 +571,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Err(ErrorHandled::TooGeneric(_)) => { // While `Reported | Linted` cases will have diagnostics emitted already // it is not true for TooGeneric case, so we need to give user more information. - self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); - pat_from_kind(PatKind::Wild) + let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); + pat_from_kind(PatKind::Error(e)) } Err(_) => { - self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); - pat_from_kind(PatKind::Wild) + let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); + pat_from_kind(PatKind::Error(e)) } } } @@ -629,7 +626,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None }; debug_assert!(!args.has_free_regions()); - let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args }; + let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; // First try using a valtree in order to destructure the constant into a pattern. // FIXME: replace "try to do a thing, then fall back to another thing" // but something more principled, like a trait query checking whether this can be turned into a valtree. @@ -649,10 +646,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind, Err(ErrorHandled::TooGeneric(_)) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. - self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); - PatKind::Wild + let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); + PatKind::Error(e) } - Err(ErrorHandled::Reported(..)) => PatKind::Wild, + Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()), } } } @@ -685,7 +682,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Ok(constant) => { self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind } - Err(LitToConstError::Reported(_)) => PatKind::Wild, + Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } } From 89f75ff4d05d22ca3b9b3d70fc6bcd225c8dbf12 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 14 Oct 2023 03:06:18 +0200 Subject: [PATCH 8/9] Skip most of check_match checks in the presence of `PatKind::Error` --- .../src/thir/pattern/check_match.rs | 26 ++++++++---- tests/ui/pattern/usefulness/consts-opaque.rs | 2 - .../pattern/usefulness/consts-opaque.stderr | 41 ++++--------------- 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 064afed9f7d44..bcecd0ff9db2f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -231,6 +231,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { if let LetSource::None = source { return; } + if let Err(err) = pat.pat_error_reported() { + self.error = Err(err); + return; + } self.check_patterns(pat, Refutable); let mut cx = self.new_cx(self.lint_level, true); let tpat = self.lower_pattern(&mut cx, pat); @@ -252,6 +256,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { self.with_lint_level(arm.lint_level, |this| { this.check_patterns(&arm.pattern, Refutable); }); + if let Err(err) = arm.pattern.pat_error_reported() { + self.error = Err(err); + return; + } } let tarms: Vec<_> = arms @@ -334,7 +342,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // and record chain members that aren't let exprs. let mut chain_refutabilities = Vec::new(); - let add = |expr: ExprId, mut local_lint_level| { + let mut error = Ok(()); + let mut add = |expr: ExprId, mut local_lint_level| { // `local_lint_level` is the lint level enclosing the pattern inside `expr`. let mut expr = &self.thir[expr]; debug!(?expr, ?local_lint_level, "add"); @@ -348,6 +357,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { debug!(?expr, ?local_lint_level, "after scopes"); match expr.kind { ExprKind::Let { box ref pat, expr: _ } => { + if let Err(err) = pat.pat_error_reported() { + error = Err(err); + return None; + } let mut ncx = self.new_cx(local_lint_level, true); let tpat = self.lower_pattern(&mut ncx, pat); let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); @@ -380,6 +393,11 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { debug!(?chain_refutabilities); chain_refutabilities.reverse(); + if error.is_err() { + self.error = error; + return; + } + // Third, emit the actual warnings. if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) { // The entire chain is made up of irrefutable `let` statements @@ -688,12 +706,6 @@ fn non_exhaustive_match<'p, 'tcx>( arms: &[ArmId], expr_span: Span, ) -> ErrorGuaranteed { - for &arm in arms { - if let Err(err) = thir[arm].pattern.pat_error_reported() { - return err; - } - } - let is_empty_match = arms.is_empty(); let non_empty_enum = match scrut_ty.kind() { ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(), diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs index 2032cf13bc26e..6dc1425cf037e 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.rs +++ b/tests/ui/pattern/usefulness/consts-opaque.rs @@ -52,7 +52,6 @@ fn main() { BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} - //~^ ERROR unreachable pattern } match BAR { @@ -60,7 +59,6 @@ fn main() { //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` Bar => {} _ => {} - //~^ ERROR unreachable pattern } match BAR { diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index cd88e6a22e4a5..51f2f276bbe2e 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -38,7 +38,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:59:9 + --> $DIR/consts-opaque.rs:58:9 | LL | BAR => {} | ^^^ @@ -47,7 +47,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:67:9 + --> $DIR/consts-opaque.rs:65:9 | LL | BAR => {} | ^^^ @@ -56,7 +56,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:69:9 + --> $DIR/consts-opaque.rs:67:9 | LL | BAR => {} | ^^^ @@ -65,7 +65,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:75:9 + --> $DIR/consts-opaque.rs:73:9 | LL | BAZ => {} | ^^^ @@ -74,7 +74,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:83:9 + --> $DIR/consts-opaque.rs:81:9 | LL | BAZ => {} | ^^^ @@ -83,7 +83,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:89:9 + --> $DIR/consts-opaque.rs:87:9 | LL | BAZ => {} | ^^^ @@ -91,37 +91,14 @@ LL | BAZ => {} = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: unreachable pattern - --> $DIR/consts-opaque.rs:54:9 - | -LL | Bar => {} - | --- matches any value -... -LL | _ => {} - | ^ unreachable pattern - | -note: the lint level is defined here - --> $DIR/consts-opaque.rs:6:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/consts-opaque.rs:62:9 - | -LL | Bar => {} - | --- matches any value -LL | _ => {} - | ^ unreachable pattern - error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered - --> $DIR/consts-opaque.rs:124:11 + --> $DIR/consts-opaque.rs:122:11 | LL | match WRAPQUUX { | ^^^^^^^^ pattern `Wrap(_)` not covered | note: `Wrap usize>` defined here - --> $DIR/consts-opaque.rs:106:12 + --> $DIR/consts-opaque.rs:104:12 | LL | struct Wrap(T); | ^^^^ @@ -132,6 +109,6 @@ LL ~ WRAPQUUX => {}, LL + Wrap(_) => todo!() | -error: aborting due to 12 previous errors; 1 warning emitted +error: aborting due to 10 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0004`. From 3a0799d6d0c36a4c67603b12a15c481b46e82dd9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 14 Oct 2023 13:25:46 +0000 Subject: [PATCH 9/9] Add some unsoundness tests for opaques capturing hidden regions not in substs --- .../rpit-hidden-erased-unsoundness.rs | 25 +++++++++++++++ .../rpit-hidden-erased-unsoundness.stderr | 18 +++++++++++ .../rpit-hide-lifetime-for-swap.rs | 32 +++++++++++++++++++ .../rpit-hide-lifetime-for-swap.stderr | 18 +++++++++++ .../tait-hidden-erased-unsoundness.rs | 28 ++++++++++++++++ .../tait-hidden-erased-unsoundness.stderr | 13 ++++++++ 6 files changed, 134 insertions(+) create mode 100644 tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs create mode 100644 tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr create mode 100644 tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs create mode 100644 tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr create mode 100644 tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs create mode 100644 tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs new file mode 100644 index 0000000000000..6863a3c73badf --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs @@ -0,0 +1,25 @@ +// This test should never pass! + +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl Captures<'_> for T {} + +struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>); +unsafe impl Send for MyTy<'_, 'static> {} + +fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a { + MyTy::<'a, 'b>(None) +} + +fn step2<'a, 'b: 'a>() -> impl Sized + 'a { + step1::<'a, 'b>() + //~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds +} + +fn step3<'a, 'b: 'a>() -> impl Send + 'a { + step2::<'a, 'b>() + // This should not be Send unless `'b: 'static` +} + +fn main() {} diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr new file mode 100644 index 0000000000000..168a5aa18ec45 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr @@ -0,0 +1,18 @@ +error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds + --> $DIR/rpit-hidden-erased-unsoundness.rs:16:5 + | +LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a { + | -- --------------- opaque type defined here + | | + | hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here +LL | step1::<'a, 'b>() + | ^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Sized + 'a` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + 'b { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs new file mode 100644 index 0000000000000..4de2ffbb80870 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs @@ -0,0 +1,32 @@ +// This test should never pass! + +use std::cell::RefCell; +use std::rc::Rc; + +trait Swap: Sized { + fn swap(self, other: Self); +} + +impl Swap for Rc> { + fn swap(self, other: Self) { + >::swap(&self, &other); + } +} + +fn hide<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { + x + //~^ ERROR hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds +} + +fn dangle() -> &'static [i32; 3] { + let long = Rc::new(RefCell::new(&[4, 5, 6])); + let x = [1, 2, 3]; + let short = Rc::new(RefCell::new(&x)); + hide(long.clone()).swap(hide(short)); + let res: &'static [i32; 3] = *long.borrow(); + res +} + +fn main() { + println!("{:?}", dangle()); +} diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr new file mode 100644 index 0000000000000..cabba4bafafdd --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr @@ -0,0 +1,18 @@ +error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds + --> $DIR/rpit-hide-lifetime-for-swap.rs:17:5 + | +LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { + | -- -------------- opaque type defined here + | | + | hidden type `Rc>` captures the lifetime `'b` as defined here +LL | x + | ^ + | +help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a + 'b { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs new file mode 100644 index 0000000000000..40efd941e338c --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs @@ -0,0 +1,28 @@ +// This test should never pass! + +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl Captures<'_> for T {} + +struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>); +unsafe impl Send for MyTy<'_, 'static> {} + +fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a { + MyTy::<'a, 'b>(None) +} + +mod tait { + type Tait<'a> = impl Sized + 'a; + pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> { + super::step1::<'a, 'b>() + //~^ ERROR hidden type for `Tait<'a>` captures lifetime that does not appear in bounds + } +} + +fn step3<'a, 'b: 'a>() -> impl Send + 'a { + tait::step2::<'a, 'b>() + // This should not be Send unless `'b: 'static` +} + +fn main() {} diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr new file mode 100644 index 0000000000000..baeec6d5892d1 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr @@ -0,0 +1,13 @@ +error[E0700]: hidden type for `Tait<'a>` captures lifetime that does not appear in bounds + --> $DIR/tait-hidden-erased-unsoundness.rs:18:9 + | +LL | type Tait<'a> = impl Sized + 'a; + | --------------- opaque type defined here +LL | pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> { + | -- hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here +LL | super::step1::<'a, 'b>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`.