Skip to content

Rollup of 4 pull requests #118618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 5, 2023
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>