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
This commit is contained in:
commit
da1da3f1a0
@ -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>,
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![feature(portable_simd, strict_provenance)]
|
||||
#![feature(portable_simd, strict_provenance, exposed_provenance)]
|
||||
|
||||
use core_simd::simd::{
|
||||
ptr::{SimdConstPtr, SimdMutPtr},
|
||||
|
@ -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 {
|
||||
'>' => ">",
|
||||
'<' => "<",
|
||||
'&' => "&",
|
||||
_ => 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(())
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -1,3 +1,3 @@
|
||||
<span class="kw">pub fn </span>foo() {
|
||||
<span class="macro">println!</span>(<span class="string">"foo"</span>);
|
||||
<span class="macro">println!</span>(<span class="string">"foo"</span>);
|
||||
}
|
||||
|
@ -8,12 +8,12 @@
|
||||
.lifetime { color: #B76514; }
|
||||
.question-mark { color: #ff9011; }
|
||||
</style>
|
||||
<pre><code><span class="attr">#![crate_type = <span class="string">"lib"</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">"linux"</span>)]
|
||||
#[cfg(target_os = <span class="string">"windows"</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() -> () {
|
||||
<span class="kw">let </span>foo = <span class="bool-val">true </span>&& <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">&mut </span>bar);
|
||||
<span class="macro">assert!</span>(<span class="self">self</span>.length < N && index <= <span class="self">self</span>.length);
|
||||
::std::env::var(<span class="string">"gateau"</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();
|
||||
|
@ -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.
|
||||
|
18
tests/rustdoc/enum-variant-fields-heading.rs
Normal file
18
tests/rustdoc/enum-variant-fields-heading.rs
Normal file
@ -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
tests/rustdoc/enum-variant-fields-heading.variants.html
Normal file
3
tests/rustdoc/enum-variant-fields-heading.variants.html
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="variants"><section id="variant.A" class="variant"><a href="#variant.A" class="anchor">§</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">§</a><h3 class="code-header">B</h3></section><div class="docblock"><p>A variant with hidden fields</p>
|
||||
</div></div>
|
Loading…
x
Reference in New Issue
Block a user