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
@@ -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>,
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},
36 changes: 36 additions & 0 deletions src/librustdoc/html/escape.rs
Original file line number Diff line number Diff line change
@@ -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
@@ -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);
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
@@ -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();
9 changes: 8 additions & 1 deletion src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
@@ -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 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>