Skip to content

Commit

Permalink
Auto merge of #118618 - GuillaumeGomez:rollup-24ur21r, r=GuillaumeGomez
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Dec 4, 2023
2 parents 0e2dac8 + baa3f96 commit da1da3f
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 56 deletions.
82 changes: 36 additions & 46 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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>,
Expand Down
2 changes: 1 addition & 1 deletion library/portable-simd/crates/core_simd/tests/pointers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(portable_simd, strict_provenance)]
#![feature(portable_simd, strict_provenance, exposed_provenance)]

use core_simd::simd::{
ptr::{SimdConstPtr, SimdMutPtr},
Expand Down
36 changes: 36 additions & 0 deletions src/librustdoc/html/escape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}
12 changes: 9 additions & 3 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/highlight/fixtures/dos_line.html
Original file line number Diff line number Diff line change
@@ -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>);
}
8 changes: 4 additions & 4 deletions src/librustdoc/html/highlight/fixtures/sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand All @@ -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();
Expand Down
9 changes: 8 additions & 1 deletion src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 18 additions & 0 deletions tests/rustdoc/enum-variant-fields-heading.rs
Original file line number Diff line number Diff line change
@@ -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 },
}
3 changes: 3 additions & 0 deletions tests/rustdoc/enum-variant-fields-heading.variants.html
Original file line number Diff line number Diff line change
@@ -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>

0 comments on commit da1da3f

Please sign in to comment.