about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-04 22:26:41 +0000
committerbors <bors@rust-lang.org>2023-12-04 22:26:41 +0000
commitda1da3f1a03edae03769fcb2866137a773bb6a93 (patch)
tree11468bfeca2ab0a3d68a043321a4ade8fbc71a54
parent0e2dac8375950a12812ec65868e42b43ed214ef9 (diff)
parentbaa3f96b424efa3396d61abd997f74f2537fa530 (diff)
downloadrust-da1da3f1a03edae03769fcb2866137a773bb6a93.tar.gz
rust-da1da3f1a03edae03769fcb2866137a773bb6a93.zip
Auto merge of #118618 - GuillaumeGomez:rollup-24ur21r, r=GuillaumeGomez
Rollup of 4 pull requests

Successful merges:

 - #118508 (rustdoc: do not escape quotes in body text)
 - #118565 (interpret: make numeric_intrinsic accessible from Miri)
 - #118591 (portable-simd: fix test suite build)
 - #118600 ([rustdoc] Don't generate the "Fields" heading if there is no field displayed)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs82
-rw-r--r--library/portable-simd/crates/core_simd/tests/pointers.rs2
-rw-r--r--src/librustdoc/html/escape.rs36
-rw-r--r--src/librustdoc/html/highlight.rs12
-rw-r--r--src/librustdoc/html/highlight/fixtures/dos_line.html2
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.html8
-rw-r--r--src/librustdoc/html/render/print_item.rs9
-rw-r--r--tests/rustdoc/enum-variant-fields-heading.rs18
-rw-r--r--tests/rustdoc/enum-variant-fields-heading.variants.html3
9 files changed, 116 insertions, 56 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 80e14f5a884..c29f23b913f 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -3,17 +3,22 @@
 //! and miri.
 
 use rustc_hir::def_id::DefId;
-use rustc_middle::mir::{
-    self,
-    interpret::{Allocation, ConstAllocation, GlobalId, InterpResult, PointerArithmetic, Scalar},
-    BinOp, ConstValue, NonDivergingIntrinsic,
-};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::{
+    mir::{
+        self,
+        interpret::{
+            Allocation, ConstAllocation, GlobalId, InterpResult, PointerArithmetic, Scalar,
+        },
+        BinOp, ConstValue, NonDivergingIntrinsic,
+    },
+    ty::layout::TyAndLayout,
+};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, Primitive, Size};
+use rustc_target::abi::Size;
 
 use super::{
     util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
@@ -22,23 +27,6 @@ use super::{
 
 use crate::fluent_generated as fluent;
 
-fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> {
-    let size = match kind {
-        Primitive::Int(integer, _) => integer.size(),
-        _ => bug!("invalid `{}` argument: {:?}", name, bits),
-    };
-    let extra = 128 - u128::from(size.bits());
-    let bits_out = match name {
-        sym::ctpop => u128::from(bits.count_ones()),
-        sym::ctlz => u128::from(bits.leading_zeros()) - extra,
-        sym::cttz => u128::from((bits << extra).trailing_zeros()) - extra,
-        sym::bswap => (bits << extra).swap_bytes(),
-        sym::bitreverse => (bits << extra).reverse_bits(),
-        _ => bug!("not a numeric intrinsic: {}", name),
-    };
-    Scalar::from_uint(bits_out, size)
-}
-
 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
 pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
     let path = crate::util::type_name(tcx, ty);
@@ -179,30 +167,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | sym::bswap
             | sym::bitreverse => {
                 let ty = instance_args.type_at(0);
-                let layout_of = self.layout_of(ty)?;
+                let layout = self.layout_of(ty)?;
                 let val = self.read_scalar(&args[0])?;
-                let bits = val.to_bits(layout_of.size)?;
-                let kind = match layout_of.abi {
-                    Abi::Scalar(scalar) => scalar.primitive(),
-                    _ => span_bug!(
-                        self.cur_span(),
-                        "{} called on invalid type {:?}",
-                        intrinsic_name,
-                        ty
-                    ),
-                };
-                let (nonzero, actual_intrinsic_name) = match intrinsic_name {
-                    sym::cttz_nonzero => (true, sym::cttz),
-                    sym::ctlz_nonzero => (true, sym::ctlz),
-                    other => (false, other),
-                };
-                if nonzero && bits == 0 {
-                    throw_ub_custom!(
-                        fluent::const_eval_call_nonzero_intrinsic,
-                        name = intrinsic_name,
-                    );
-                }
-                let out_val = numeric_intrinsic(actual_intrinsic_name, bits, kind);
+                let out_val = self.numeric_intrinsic(intrinsic_name, val, layout)?;
                 self.write_scalar(out_val, dest)?;
             }
             sym::saturating_add | sym::saturating_sub => {
@@ -493,6 +460,29 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
+    pub fn numeric_intrinsic(
+        &self,
+        name: Symbol,
+        val: Scalar<M::Provenance>,
+        layout: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
+        assert!(layout.ty.is_integral(), "invalid type for numeric intrinsic: {}", layout.ty);
+        let bits = val.to_bits(layout.size)?;
+        let extra = 128 - u128::from(layout.size.bits());
+        let bits_out = match name {
+            sym::ctpop => u128::from(bits.count_ones()),
+            sym::ctlz_nonzero | sym::cttz_nonzero if bits == 0 => {
+                throw_ub_custom!(fluent::const_eval_call_nonzero_intrinsic, name = name,);
+            }
+            sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra,
+            sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra,
+            sym::bswap => (bits << extra).swap_bytes(),
+            sym::bitreverse => (bits << extra).reverse_bits(),
+            _ => bug!("not a numeric intrinsic: {}", name),
+        };
+        Ok(Scalar::from_uint(bits_out, layout.size))
+    }
+
     pub fn exact_div(
         &mut self,
         a: &ImmTy<'tcx, M::Provenance>,
diff --git a/library/portable-simd/crates/core_simd/tests/pointers.rs b/library/portable-simd/crates/core_simd/tests/pointers.rs
index a90ff928ced..b9f32d16e01 100644
--- a/library/portable-simd/crates/core_simd/tests/pointers.rs
+++ b/library/portable-simd/crates/core_simd/tests/pointers.rs
@@ -1,4 +1,4 @@
-#![feature(portable_simd, strict_provenance)]
+#![feature(portable_simd, strict_provenance, exposed_provenance)]
 
 use core_simd::simd::{
     ptr::{SimdConstPtr, SimdMutPtr},
diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs
index 4a19d0a44c3..ea4b573aeb9 100644
--- a/src/librustdoc/html/escape.rs
+++ b/src/librustdoc/html/escape.rs
@@ -38,3 +38,39 @@ impl<'a> fmt::Display for Escape<'a> {
         Ok(())
     }
 }
+
+/// Wrapper struct which will emit the HTML-escaped version of the contained
+/// string when passed to a format string.
+///
+/// This is only safe to use for text nodes. If you need your output to be
+/// safely contained in an attribute, use [`Escape`]. If you don't know the
+/// difference, use [`Escape`].
+pub(crate) struct EscapeBodyText<'a>(pub &'a str);
+
+impl<'a> fmt::Display for EscapeBodyText<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Because the internet is always right, turns out there's not that many
+        // characters to escape: http://stackoverflow.com/questions/7381974
+        let EscapeBodyText(s) = *self;
+        let pile_o_bits = s;
+        let mut last = 0;
+        for (i, ch) in s.char_indices() {
+            let s = match ch {
+                '>' => "&gt;",
+                '<' => "&lt;",
+                '&' => "&amp;",
+                _ => continue,
+            };
+            fmt.write_str(&pile_o_bits[last..i])?;
+            fmt.write_str(s)?;
+            // NOTE: we only expect single byte characters here - which is fine as long as we
+            // only match single byte characters
+            last = i + 1;
+        }
+
+        if last < s.len() {
+            fmt.write_str(&pile_o_bits[last..])?;
+        }
+        Ok(())
+    }
+}
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index b762c8a1ce6..1cdc792a819 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -6,7 +6,7 @@
 //! Use the `render_with_highlighting` to highlight some rust code.
 
 use crate::clean::PrimitiveType;
-use crate::html::escape::Escape;
+use crate::html::escape::EscapeBodyText;
 use crate::html::render::{Context, LinkFromSrc};
 
 use std::collections::VecDeque;
@@ -189,7 +189,7 @@ impl<'a, 'tcx, F: Write> TokenHandler<'a, 'tcx, F> {
             && can_merge(current_class, Some(*parent_class), "")
         {
             for (text, class) in self.pending_elems.iter() {
-                string(self.out, Escape(text), *class, &self.href_context, false);
+                string(self.out, EscapeBodyText(text), *class, &self.href_context, false);
             }
         } else {
             // We only want to "open" the tag ourselves if we have more than one pending and if the
@@ -202,7 +202,13 @@ impl<'a, 'tcx, F: Write> TokenHandler<'a, 'tcx, F> {
                 None
             };
             for (text, class) in self.pending_elems.iter() {
-                string(self.out, Escape(text), *class, &self.href_context, close_tag.is_none());
+                string(
+                    self.out,
+                    EscapeBodyText(text),
+                    *class,
+                    &self.href_context,
+                    close_tag.is_none(),
+                );
             }
             if let Some(close_tag) = close_tag {
                 exit_span(self.out, close_tag);
diff --git a/src/librustdoc/html/highlight/fixtures/dos_line.html b/src/librustdoc/html/highlight/fixtures/dos_line.html
index 30b50ca7c66..b98e6712590 100644
--- a/src/librustdoc/html/highlight/fixtures/dos_line.html
+++ b/src/librustdoc/html/highlight/fixtures/dos_line.html
@@ -1,3 +1,3 @@
 <span class="kw">pub fn </span>foo() {
-<span class="macro">println!</span>(<span class="string">&quot;foo&quot;</span>);
+<span class="macro">println!</span>(<span class="string">"foo"</span>);
 }
diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html
index fced2eacd9e..aa735e81597 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.html
+++ b/src/librustdoc/html/highlight/fixtures/sample.html
@@ -8,12 +8,12 @@
 .lifetime { color: #B76514; }
 .question-mark { color: #ff9011; }
 </style>
-<pre><code><span class="attr">#![crate_type = <span class="string">&quot;lib&quot;</span>]
+<pre><code><span class="attr">#![crate_type = <span class="string">"lib"</span>]
 
 </span><span class="kw">use </span>std::path::{Path, PathBuf};
 
-<span class="attr">#[cfg(target_os = <span class="string">&quot;linux&quot;</span>)]
-#[cfg(target_os = <span class="string">&quot;windows&quot;</span>)]
+<span class="attr">#[cfg(target_os = <span class="string">"linux"</span>)]
+#[cfg(target_os = <span class="string">"windows"</span>)]
 </span><span class="kw">fn </span>main() -&gt; () {
     <span class="kw">let </span>foo = <span class="bool-val">true </span>&amp;&amp; <span class="bool-val">false </span>|| <span class="bool-val">true</span>;
     <span class="kw">let _</span>: <span class="kw-2">*const </span>() = <span class="number">0</span>;
@@ -22,7 +22,7 @@
     <span class="kw">let _ </span>= <span class="kw-2">*</span>foo;
     <span class="macro">mac!</span>(foo, <span class="kw-2">&amp;mut </span>bar);
     <span class="macro">assert!</span>(<span class="self">self</span>.length &lt; N &amp;&amp; index &lt;= <span class="self">self</span>.length);
-    ::std::env::var(<span class="string">&quot;gateau&quot;</span>).is_ok();
+    ::std::env::var(<span class="string">"gateau"</span>).is_ok();
     <span class="attr">#[rustfmt::skip]
     </span><span class="kw">let </span>s:std::path::PathBuf = std::path::PathBuf::new();
     <span class="kw">let </span><span class="kw-2">mut </span>s = String::new();
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 131b1d608e6..ff7ce01e807 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1737,7 +1737,14 @@ fn item_variants(
         w.write_str("</h3></section>");
 
         let heading_and_fields = match &variant_data.kind {
-            clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+            clean::VariantKind::Struct(s) => {
+                // If there is no field to display, no need to add the heading.
+                if s.fields.iter().any(|f| !f.is_doc_hidden()) {
+                    Some(("Fields", &s.fields))
+                } else {
+                    None
+                }
+            }
             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.
diff --git a/tests/rustdoc/enum-variant-fields-heading.rs b/tests/rustdoc/enum-variant-fields-heading.rs
new file mode 100644
index 00000000000..8a7c99a8735
--- /dev/null
+++ b/tests/rustdoc/enum-variant-fields-heading.rs
@@ -0,0 +1,18 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/118195>.
+// It ensures that the "Fields" heading is not generated if no field is displayed.
+
+#![crate_name = "foo"]
+
+// @has 'foo/enum.Foo.html'
+// @has - '//*[@id="variant.A"]' 'A'
+// @count - '//*[@id="variant.A.fields"]' 0
+// @has - '//*[@id="variant.B"]' 'B'
+// @count - '//*[@id="variant.B.fields"]' 0
+// @snapshot variants - '//*[@id="main-content"]/*[@class="variants"]'
+
+pub enum Foo {
+    /// A variant with no fields
+    A {},
+    /// A variant with hidden fields
+    B { #[doc(hidden)] a: u8 },
+}
diff --git a/tests/rustdoc/enum-variant-fields-heading.variants.html b/tests/rustdoc/enum-variant-fields-heading.variants.html
new file mode 100644
index 00000000000..bcb36f7cf86
--- /dev/null
+++ b/tests/rustdoc/enum-variant-fields-heading.variants.html
@@ -0,0 +1,3 @@
+<div class="variants"><section id="variant.A" class="variant"><a href="#variant.A" class="anchor">&#167;</a><h3 class="code-header">A</h3></section><div class="docblock"><p>A variant with no fields</p>
+</div><section id="variant.B" class="variant"><a href="#variant.B" class="anchor">&#167;</a><h3 class="code-header">B</h3></section><div class="docblock"><p>A variant with hidden fields</p>
+</div></div>
\ No newline at end of file