diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index 40e801d03885c..f71e6f3e6f3a6 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -1,14 +1,18 @@
use std::io;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_index::IndexVec;
use rustc_middle::mir::pretty::{
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
};
use rustc_middle::mir::{Body, ClosureRegionRequirements};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_session::config::MirIncludeSpans;
use crate::borrow_set::BorrowSet;
+use crate::constraints::OutlivesConstraint;
use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
+use crate::type_check::Locations;
use crate::{BorrowckInferCtxt, RegionInferenceContext};
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
@@ -50,6 +54,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
/// - the NLL MIR
/// - the list of polonius localized constraints
/// - a mermaid graph of the CFG
+/// - a mermaid graph of the NLL regions and the constraints between them
+/// - a mermaid graph of the NLL SCCs and the constraints between them
fn emit_polonius_dump<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
@@ -68,7 +74,7 @@ fn emit_polonius_dump<'tcx>(
// Section 1: the NLL + Polonius MIR.
writeln!(out, "
")?;
writeln!(out, "Raw MIR dump")?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
emit_html_mir(
tcx,
body,
@@ -78,15 +84,31 @@ fn emit_polonius_dump<'tcx>(
closure_region_requirements,
out,
)?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
writeln!(out, "
")?;
// Section 2: mermaid visualization of the CFG.
writeln!(out, "")?;
writeln!(out, "Control-flow graph")?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
emit_mermaid_cfg(body, out)?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
+ writeln!(out, "
")?;
+
+ // Section 3: mermaid visualization of the NLL region graph.
+ writeln!(out, "")?;
+ writeln!(out, "NLL regions")?;
+ writeln!(out, "
")?;
+ emit_mermaid_nll_regions(regioncx, out)?;
+ writeln!(out, "
")?;
+ writeln!(out, "
")?;
+
+ // Section 4: mermaid visualization of the NLL SCC graph.
+ writeln!(out, "")?;
+ writeln!(out, "NLL SCCs")?;
+ writeln!(out, "
")?;
+ emit_mermaid_nll_sccs(regioncx, out)?;
+ writeln!(out, "
")?;
writeln!(out, "
")?;
// Finalize the dump with the HTML epilogue.
@@ -261,3 +283,112 @@ fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()>
Ok(())
}
+
+/// Emits a region's label: index, universe, external name.
+fn render_region(
+ region: RegionVid,
+ regioncx: &RegionInferenceContext<'_>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ let def = regioncx.region_definition(region);
+ let universe = def.universe;
+
+ write!(out, "'{}", region.as_usize())?;
+ if !universe.is_root() {
+ write!(out, "/{universe:?}")?;
+ }
+ if let Some(name) = def.external_name.and_then(|e| e.get_name()) {
+ write!(out, " ({name})")?;
+ }
+ Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL regions and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_regions<'tcx>(
+ regioncx: &RegionInferenceContext<'tcx>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ // The mermaid chart type: a top-down flowchart.
+ writeln!(out, "flowchart TD")?;
+
+ // Emit the region nodes.
+ for region in regioncx.var_infos.indices() {
+ write!(out, "{}[\"", region.as_usize())?;
+ render_region(region, regioncx, out)?;
+ writeln!(out, "\"]")?;
+ }
+
+ // Get a set of edges to check for the reverse edge being present.
+ let edges: FxHashSet<_> = regioncx.outlives_constraints().map(|c| (c.sup, c.sub)).collect();
+
+ // Order (and deduplicate) edges for traversal, to display them in a generally increasing order.
+ let constraint_key = |c: &OutlivesConstraint<'_>| {
+ let min = c.sup.min(c.sub);
+ let max = c.sup.max(c.sub);
+ (min, max)
+ };
+ let mut ordered_edges: Vec<_> = regioncx.outlives_constraints().collect();
+ ordered_edges.sort_by_key(|c| constraint_key(c));
+ ordered_edges.dedup_by_key(|c| constraint_key(c));
+
+ for outlives in ordered_edges {
+ // Source node.
+ write!(out, "{} ", outlives.sup.as_usize())?;
+
+ // The kind of arrow: bidirectional if the opposite edge exists in the set.
+ if edges.contains(&(outlives.sub, outlives.sup)) {
+ write!(out, "<")?;
+ }
+ write!(out, "-- ")?;
+
+ // Edge label from its `Locations`.
+ match outlives.locations {
+ Locations::All(_) => write!(out, "All")?,
+ Locations::Single(location) => write!(out, "{:?}", location)?,
+ }
+
+ // Target node.
+ writeln!(out, " --> {}", outlives.sub.as_usize())?;
+ }
+ Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_sccs<'tcx>(
+ regioncx: &RegionInferenceContext<'tcx>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ // The mermaid chart type: a top-down flowchart.
+ writeln!(out, "flowchart TD")?;
+
+ // Gather and emit the SCC nodes.
+ let mut nodes_per_scc: IndexVec<_, _> =
+ regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect();
+ for region in regioncx.var_infos.indices() {
+ let scc = regioncx.constraint_sccs().scc(region);
+ nodes_per_scc[scc].push(region);
+ }
+ for (scc, regions) in nodes_per_scc.iter_enumerated() {
+ // The node label: the regions contained in the SCC.
+ write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?;
+ for (idx, ®ion) in regions.iter().enumerate() {
+ render_region(region, regioncx, out)?;
+ if idx < regions.len() - 1 {
+ write!(out, ",")?;
+ }
+ }
+ writeln!(out, "}}\"]")?;
+ }
+
+ // Emit the edges between SCCs.
+ let edges = regioncx.constraint_sccs().all_sccs().flat_map(|source| {
+ regioncx.constraint_sccs().successors(source).iter().map(move |&target| (source, target))
+ });
+ for (source, target) in edges {
+ writeln!(out, "{} --> {}", source.as_usize(), target.as_usize())?;
+ }
+
+ Ok(())
+}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 2c99597922e8f..fdcd9caf4ac87 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -126,7 +126,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
&mut self,
name: &str,
params: Vec,
- returns: Vec,
+ mut returns: Vec,
args: &[Value],
) -> Cow<'_, [Value]> {
// Pass i128 arguments by-ref on Windows.
@@ -150,15 +150,19 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
(params, args.into())
};
- // Return i128 using a return area pointer on Windows and s390x.
- let adjust_ret_param =
- if self.tcx.sess.target.is_like_windows || self.tcx.sess.target.arch == "s390x" {
- returns.len() == 1 && returns[0].value_type == types::I128
- } else {
- false
- };
+ let ret_single_i128 = returns.len() == 1 && returns[0].value_type == types::I128;
+ if ret_single_i128 && self.tcx.sess.target.is_like_windows {
+ // Return i128 using the vector ABI on Windows
+ returns[0].value_type = types::I64X2;
+
+ let ret = self.lib_call_unadjusted(name, params, returns, &args)[0];
- if adjust_ret_param {
+ // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
+ let ret_ptr = self.create_stack_slot(16, 16);
+ ret_ptr.store(self, ret, MemFlags::trusted());
+ Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())])
+ } else if ret_single_i128 && self.tcx.sess.target.arch == "s390x" {
+ // Return i128 using a return area pointer on s390x.
let mut params = params;
let mut args = args.to_vec();
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 0b5cb1547fc69..4463631c524be 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -96,25 +96,9 @@ pub(crate) fn clif_int_or_float_cast(
},
);
- if fx.tcx.sess.target.is_like_windows {
- let ret = fx.lib_call(
- &name,
- vec![AbiParam::new(from_ty)],
- vec![AbiParam::new(types::I64X2)],
- &[from],
- )[0];
- // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
- let ret_ptr = fx.create_stack_slot(16, 16);
- ret_ptr.store(fx, ret, MemFlags::trusted());
- ret_ptr.load(fx, types::I128, MemFlags::trusted())
- } else {
- fx.lib_call(
- &name,
- vec![AbiParam::new(from_ty)],
- vec![AbiParam::new(types::I128)],
- &[from],
- )[0]
- }
+ fx.lib_call(&name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(types::I128)], &[
+ from,
+ ])[0]
} else if to_ty == types::I8 || to_ty == types::I16 {
// FIXME implement fcvt_to_*int_sat.i8/i16
let val = if to_signed {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index dcfd7ddabbc42..df5a79086fa3e 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -33,28 +33,14 @@ pub(crate) fn maybe_codegen<'tcx>(
(BinOp::Rem, true) => "__modti3",
_ => unreachable!(),
};
- if fx.tcx.sess.target.is_like_windows {
- let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
- let ret = fx.lib_call(
- name,
- vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
- vec![AbiParam::new(types::I64X2)],
- &args,
- )[0];
- // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
- let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
- ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
- Some(ret_place.to_cvalue(fx))
- } else {
- let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
- let ret_val = fx.lib_call(
- name,
- vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
- vec![AbiParam::new(types::I128)],
- &args,
- )[0];
- Some(CValue::by_val(ret_val, lhs.layout()))
- }
+ let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
+ let ret_val = fx.lib_call(
+ name,
+ vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
+ vec![AbiParam::new(types::I128)],
+ &args,
+ )[0];
+ Some(CValue::by_val(ret_val, lhs.layout()))
}
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 50287b706ce83..2373ab67d42ed 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2830,9 +2830,10 @@ pub(crate) struct DynAfterMut {
pub(crate) struct FnPointerCannotBeConst {
#[primary_span]
pub span: Span,
- #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
#[label]
pub qualifier: Span,
+ #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
+ pub suggestion: Span,
}
#[derive(Diagnostic)]
@@ -2840,9 +2841,10 @@ pub(crate) struct FnPointerCannotBeConst {
pub(crate) struct FnPointerCannotBeAsync {
#[primary_span]
pub span: Span,
- #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
#[label]
pub qualifier: Span,
+ #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
+ pub suggestion: Span,
}
#[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 6497d19a173ca..dc5919b3630ce 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -609,16 +609,58 @@ impl<'a> Parser<'a> {
let span_start = self.token.span;
let ast::FnHeader { ext, safety, constness, coroutine_kind } =
self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
+ let fn_start_lo = self.prev_token.span.lo();
if self.may_recover() && self.token == TokenKind::Lt {
self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
}
let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
let whole_span = lo.to(self.prev_token.span);
- if let ast::Const::Yes(span) = constness {
- self.dcx().emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
+
+ // Order/parsing of "front matter" follows:
+ // ` fn()`
+ // ^ ^ ^ ^ ^
+ // | | | | fn_start_lo
+ // | | | ext_sp.lo
+ // | | safety_sp.lo
+ // | coroutine_sp.lo
+ // const_sp.lo
+ if let ast::Const::Yes(const_span) = constness {
+ let next_token_lo = if let Some(
+ ast::CoroutineKind::Async { span, .. }
+ | ast::CoroutineKind::Gen { span, .. }
+ | ast::CoroutineKind::AsyncGen { span, .. },
+ ) = coroutine_kind
+ {
+ span.lo()
+ } else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety {
+ span.lo()
+ } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
+ span.lo()
+ } else {
+ fn_start_lo
+ };
+ let sugg_span = const_span.with_hi(next_token_lo);
+ self.dcx().emit_err(FnPointerCannotBeConst {
+ span: whole_span,
+ qualifier: const_span,
+ suggestion: sugg_span,
+ });
}
- if let Some(ast::CoroutineKind::Async { span, .. }) = coroutine_kind {
- self.dcx().emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
+ if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind {
+ let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety
+ {
+ span.lo()
+ } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
+ span.lo()
+ } else {
+ fn_start_lo
+ };
+ let sugg_span = async_span.with_hi(next_token_lo);
+ self.dcx().emit_err(FnPointerCannotBeAsync {
+ span: whole_span,
+ qualifier: async_span,
+ suggestion: sugg_span,
+ });
}
// FIXME(gen_blocks): emit a similar error for `gen fn()`
let decl_span = span_start.to(self.prev_token.span);
diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs
index 0944bda26875d..816564d2fed8b 100644
--- a/compiler/rustc_target/src/callconv/x86_win64.rs
+++ b/compiler/rustc_target/src/callconv/x86_win64.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{BackendRepr, Float, Primitive};
+use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
use crate::abi::call::{ArgAbi, FnAbi, Reg};
use crate::spec::HasTargetSpec;
@@ -6,7 +6,7 @@ use crate::spec::HasTargetSpec;
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
- let fixup = |a: &mut ArgAbi<'_, Ty>| {
+ let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
match a.layout.backend_repr {
BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {}
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
@@ -23,11 +23,16 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
// (probably what clang calls "illegal vectors").
}
BackendRepr::Scalar(scalar) => {
- // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
- // with what LLVM expects.
- if a.layout.size.bytes() > 8
+ if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
+ // `i128` is returned in xmm0 by Clang and GCC
+ // FIXME(#134288): This may change for the `-msvc` targets in the future.
+ let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) };
+ a.cast_to(reg);
+ } else if a.layout.size.bytes() > 8
&& !matches!(scalar.primitive(), Primitive::Float(Float::F128))
{
+ // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
+ // with what LLVM expects.
a.make_indirect();
} else {
a.extend_integer_width_to(32);
@@ -37,8 +42,9 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
};
if !fn_abi.ret.is_ignore() {
- fixup(&mut fn_abi.ret);
+ fixup(&mut fn_abi.ret, true);
}
+
for arg in fn_abi.args.iter_mut() {
if arg.is_ignore() && arg.layout.is_zst() {
// Windows ABIs do not talk about ZST since such types do not exist in MSVC.
@@ -49,7 +55,7 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
arg.make_indirect_from_ignore();
continue;
}
- fixup(arg);
+ fixup(arg, false);
}
// FIXME: We should likely also do something about ZST return types, similar to above.
// However, that's non-trivial due to `()`.
diff --git a/library/core/src/iter/sources/from_fn.rs b/library/core/src/iter/sources/from_fn.rs
index 5f3d404d7dca2..75cc0ffe3c77c 100644
--- a/library/core/src/iter/sources/from_fn.rs
+++ b/library/core/src/iter/sources/from_fn.rs
@@ -1,7 +1,7 @@
use crate::fmt;
-/// Creates a new iterator where each iteration calls the provided closure
-/// `F: FnMut() -> Option`.
+/// Creates an iterator with the provided closure
+/// `F: FnMut() -> Option` as its `[next](Iterator::next)` method.
///
/// The iterator will yield the `T`s returned from the closure.
///
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index 4f37e18a8cd76..54a992c9cf4b5 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -324,6 +324,18 @@ impl f128 {
///
/// The precision of this function is non-deterministic. This means it varies by platform,
/// Rust version, and can even differ within the same execution from one invocation to the next.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(f128)]
+ ///
+ /// let x = 2.0_f128;
+ /// let abs_difference = (x.powi(2) - (x * x)).abs();
+ /// assert!(abs_difference <= f128::EPSILON);
+ ///
+ /// assert_eq!(f128::powi(f128::NAN, 0), 1.0);
+ /// ```
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f128", issue = "116909")]
@@ -347,8 +359,10 @@ impl f128 {
///
/// let x = 2.0_f128;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f128::EPSILON);
+ ///
+ /// assert_eq!(f128::powf(1.0, f128::NAN), 1.0);
+ /// assert_eq!(f128::powf(f128::NAN, 0.0), 1.0);
/// # }
/// ```
#[inline]
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index 42cd6e3fe2a5f..e354f2dd98217 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -324,6 +324,18 @@ impl f16 {
///
/// The precision of this function is non-deterministic. This means it varies by platform,
/// Rust version, and can even differ within the same execution from one invocation to the next.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(f16)]
+ ///
+ /// let x = 2.0_f16;
+ /// let abs_difference = (x.powi(2) - (x * x)).abs();
+ /// assert!(abs_difference <= f16::EPSILON);
+ ///
+ /// assert_eq!(f16::powi(f16::NAN, 0), 1.0);
+ /// ```
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f16", issue = "116909")]
@@ -347,8 +359,10 @@ impl f16 {
///
/// let x = 2.0_f16;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f16::EPSILON);
+ ///
+ /// assert_eq!(f16::powf(1.0, f16::NAN), 1.0);
+ /// assert_eq!(f16::powf(f16::NAN, 0.0), 1.0);
/// # }
/// ```
#[inline]
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 438d77b1626be..f9b6723788ae3 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -306,8 +306,9 @@ impl f32 {
/// ```
/// let x = 2.0_f32;
/// let abs_difference = (x.powi(2) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f32::EPSILON);
+ ///
+ /// assert_eq!(f32::powi(f32::NAN, 0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -329,8 +330,10 @@ impl f32 {
/// ```
/// let x = 2.0_f32;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f32::EPSILON);
+ ///
+ /// assert_eq!(f32::powf(1.0, f32::NAN), 1.0);
+ /// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 9bb4bfbab2a0f..0de55a15d48e8 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -306,8 +306,9 @@ impl f64 {
/// ```
/// let x = 2.0_f64;
/// let abs_difference = (x.powi(2) - (x * x)).abs();
+ /// assert!(abs_difference <= f64::EPSILON);
///
- /// assert!(abs_difference < 1e-10);
+ /// assert_eq!(f64::powi(f64::NAN, 0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -329,8 +330,10 @@ impl f64 {
/// ```
/// let x = 2.0_f64;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
+ /// assert!(abs_difference <= f64::EPSILON);
///
- /// assert!(abs_difference < 1e-10);
+ /// assert_eq!(f64::powf(1.0, f64::NAN), 1.0);
+ /// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/src/doc/book b/src/doc/book
index 82a4a49789bc9..fa312a343fbff 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 82a4a49789bc96db1a1b2a210b4c5ed7c9ef0c0d
+Subproject commit fa312a343fbff01bc6cef393e326817f70719813
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index d56e0f3a0656b..4ed5a1a4a2a7e 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit d56e0f3a0656b7702ca466d4b191e16c28262b82
+Subproject commit 4ed5a1a4a2a7ecc2e529a5baaef04f7bc7917eda
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 625b200e5b33a..bc22988655446 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 625b200e5b33a5af35589db0bc454203a3d46d20
+Subproject commit bc2298865544695c63454fc1f9f98a3dc22e9948
diff --git a/src/doc/reference b/src/doc/reference
index 293af99100377..93b921c7d3213 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 293af991003772bdccf2d6b980182d84dd055942
+Subproject commit 93b921c7d3213d38d920f7f905a3bec093d2217d
diff --git a/tests/codegen/i128-x86-callconv.rs b/tests/codegen/i128-x86-callconv.rs
new file mode 100644
index 0000000000000..9a9c9002fc026
--- /dev/null
+++ b/tests/codegen/i128-x86-callconv.rs
@@ -0,0 +1,79 @@
+//! Verify that Rust implements the expected calling convention for `i128`/`u128`.
+
+// Eliminate intermediate instructions during `nop` tests
+//@ compile-flags: -Copt-level=1
+
+//@ add-core-stubs
+//@ revisions: MSVC MINGW
+//@ [MSVC] needs-llvm-components: x86
+//@ [MINGW] needs-llvm-components: x86
+//@ [MSVC] compile-flags: --target x86_64-pc-windows-msvc
+//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu
+//@ [MSVC] filecheck-flags: --check-prefix=WIN
+//@ [MINGW] filecheck-flags: --check-prefix=WIN
+
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+extern crate minicore;
+
+extern "C" {
+ fn extern_call(arg0: i128);
+ fn extern_ret() -> i128;
+}
+
+#[no_mangle]
+pub extern "C" fn pass(_arg0: u32, arg1: i128) {
+ // CHECK-LABEL: @pass(
+ // i128 is passed indirectly on Windows. It should load the pointer to the stack and pass
+ // a pointer to that allocation.
+ // WIN-SAME: %_arg0, ptr{{.*}} %arg1)
+ // WIN: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16
+ // WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1
+ // WIN: store i128 [[LOADED]], ptr [[PASS]]
+ // WIN: call void @extern_call
+ unsafe { extern_call(arg1) };
+}
+
+// Check that we produce the correct return ABI
+#[no_mangle]
+pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 {
+ // CHECK-LABEL: @ret(
+ // i128 is returned in xmm0 on Windows
+ // FIXME(#134288): This may change for the `-msvc` targets in the future.
+ // WIN-SAME: i32{{.*}} %_arg0, ptr{{.*}} %arg1)
+ // WIN: [[LOADED:%[_0-9]+]] = load <16 x i8>, ptr %arg1
+ // WIN-NEXT: ret <16 x i8> [[LOADED]]
+ arg1
+}
+
+// Check that we consume the correct return ABI
+#[no_mangle]
+pub extern "C" fn forward(dst: *mut i128) {
+ // CHECK-LABEL: @forward
+ // WIN-SAME: ptr{{.*}} %dst)
+ // WIN: [[RETURNED:%[_0-9]+]] = tail call <16 x i8> @extern_ret()
+ // WIN: store <16 x i8> [[RETURNED]], ptr %dst
+ // WIN: ret void
+ unsafe { *dst = extern_ret() };
+}
+
+#[repr(C)]
+struct RetAggregate {
+ a: i32,
+ b: i128,
+}
+
+#[no_mangle]
+pub extern "C" fn ret_aggregate(_arg0: u32, arg1: i128) -> RetAggregate {
+ // CHECK-LABEL: @ret_aggregate(
+ // Aggregates should also be returned indirectly
+ // WIN-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1)
+ // WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1
+ // WIN: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]]
+ // WIN: store i128 [[LOADED]], ptr [[GEP]]
+ // WIN: ret void
+ RetAggregate { a: 1, b: arg1 }
+}
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.fixed b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
index e2a2f9486b785..8a97a2f09ccab 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.fixed
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
@@ -2,24 +2,24 @@
//@ edition:2018
// Most of items are taken from ./recover-const-async-fn-ptr.rs but this is able to apply rustfix.
-pub type T0 = fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type T1 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type T2 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type T3 = fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type T4 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type T5 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type T6 = unsafe extern "C" fn();
+pub type T0 = fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type T1 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type T2 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type T3 = fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type T4 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type T5 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type T6 = unsafe extern "C" fn();
//~^ ERROR an `fn` pointer type cannot be `const`
//~| ERROR an `fn` pointer type cannot be `async`
-pub type FTT0 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type FTT1 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type FTT2 = for<'a> unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type FTT3 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type FTT4 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type FTT5 = for<'a> unsafe extern "C" fn();
+pub type FTT0 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type FTT1 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type FTT2 = for<'a> unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type FTT3 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type FTT4 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type FTT5 = for<'a> unsafe extern "C" fn();
//~^ ERROR an `fn` pointer type cannot be `async`
-pub type FTT6 = for<'a> unsafe extern "C" fn();
+pub type FTT6 = for<'a> unsafe extern "C" fn();
//~^ ERROR an `fn` pointer type cannot be `const`
//~| ERROR an `fn` pointer type cannot be `async`
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
index ddc8bac678cfb..b9d2625d9f4be 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
@@ -9,7 +9,7 @@ LL | pub type T0 = const fn();
help: remove the `const` qualifier
|
LL - pub type T0 = const fn();
-LL + pub type T0 = fn();
+LL + pub type T0 = fn();
|
error: an `fn` pointer type cannot be `const`
@@ -23,7 +23,7 @@ LL | pub type T1 = const extern "C" fn();
help: remove the `const` qualifier
|
LL - pub type T1 = const extern "C" fn();
-LL + pub type T1 = extern "C" fn();
+LL + pub type T1 = extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -37,7 +37,7 @@ LL | pub type T2 = const unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - pub type T2 = const unsafe extern "C" fn();
-LL + pub type T2 = unsafe extern "C" fn();
+LL + pub type T2 = unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -51,7 +51,7 @@ LL | pub type T3 = async fn();
help: remove the `async` qualifier
|
LL - pub type T3 = async fn();
-LL + pub type T3 = fn();
+LL + pub type T3 = fn();
|
error: an `fn` pointer type cannot be `async`
@@ -65,7 +65,7 @@ LL | pub type T4 = async extern "C" fn();
help: remove the `async` qualifier
|
LL - pub type T4 = async extern "C" fn();
-LL + pub type T4 = extern "C" fn();
+LL + pub type T4 = extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -79,7 +79,7 @@ LL | pub type T5 = async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - pub type T5 = async unsafe extern "C" fn();
-LL + pub type T5 = unsafe extern "C" fn();
+LL + pub type T5 = unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -93,7 +93,7 @@ LL | pub type T6 = const async unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - pub type T6 = const async unsafe extern "C" fn();
-LL + pub type T6 = async unsafe extern "C" fn();
+LL + pub type T6 = async unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -107,7 +107,7 @@ LL | pub type T6 = const async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - pub type T6 = const async unsafe extern "C" fn();
-LL + pub type T6 = const unsafe extern "C" fn();
+LL + pub type T6 = const unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -121,7 +121,7 @@ LL | pub type FTT0 = for<'a> const fn();
help: remove the `const` qualifier
|
LL - pub type FTT0 = for<'a> const fn();
-LL + pub type FTT0 = for<'a> fn();
+LL + pub type FTT0 = for<'a> fn();
|
error: an `fn` pointer type cannot be `const`
@@ -135,7 +135,7 @@ LL | pub type FTT1 = for<'a> const extern "C" fn();
help: remove the `const` qualifier
|
LL - pub type FTT1 = for<'a> const extern "C" fn();
-LL + pub type FTT1 = for<'a> extern "C" fn();
+LL + pub type FTT1 = for<'a> extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -149,7 +149,7 @@ LL | pub type FTT2 = for<'a> const unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - pub type FTT2 = for<'a> const unsafe extern "C" fn();
-LL + pub type FTT2 = for<'a> unsafe extern "C" fn();
+LL + pub type FTT2 = for<'a> unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -163,7 +163,7 @@ LL | pub type FTT3 = for<'a> async fn();
help: remove the `async` qualifier
|
LL - pub type FTT3 = for<'a> async fn();
-LL + pub type FTT3 = for<'a> fn();
+LL + pub type FTT3 = for<'a> fn();
|
error: an `fn` pointer type cannot be `async`
@@ -177,7 +177,7 @@ LL | pub type FTT4 = for<'a> async extern "C" fn();
help: remove the `async` qualifier
|
LL - pub type FTT4 = for<'a> async extern "C" fn();
-LL + pub type FTT4 = for<'a> extern "C" fn();
+LL + pub type FTT4 = for<'a> extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -191,7 +191,7 @@ LL | pub type FTT5 = for<'a> async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - pub type FTT5 = for<'a> async unsafe extern "C" fn();
-LL + pub type FTT5 = for<'a> unsafe extern "C" fn();
+LL + pub type FTT5 = for<'a> unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -205,7 +205,7 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
-LL + pub type FTT6 = for<'a> async unsafe extern "C" fn();
+LL + pub type FTT6 = for<'a> async unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -219,7 +219,7 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
-LL + pub type FTT6 = for<'a> const unsafe extern "C" fn();
+LL + pub type FTT6 = for<'a> const unsafe extern "C" fn();
|
error: aborting due to 16 previous errors
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
index 9112a0e135a50..4e5927914ccb5 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
@@ -9,7 +9,7 @@ LL | type T0 = const fn();
help: remove the `const` qualifier
|
LL - type T0 = const fn();
-LL + type T0 = fn();
+LL + type T0 = fn();
|
error: an `fn` pointer type cannot be `const`
@@ -23,7 +23,7 @@ LL | type T1 = const extern "C" fn();
help: remove the `const` qualifier
|
LL - type T1 = const extern "C" fn();
-LL + type T1 = extern "C" fn();
+LL + type T1 = extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -37,7 +37,7 @@ LL | type T2 = const unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - type T2 = const unsafe extern "C" fn();
-LL + type T2 = unsafe extern "C" fn();
+LL + type T2 = unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -51,7 +51,7 @@ LL | type T3 = async fn();
help: remove the `async` qualifier
|
LL - type T3 = async fn();
-LL + type T3 = fn();
+LL + type T3 = fn();
|
error: an `fn` pointer type cannot be `async`
@@ -65,7 +65,7 @@ LL | type T4 = async extern "C" fn();
help: remove the `async` qualifier
|
LL - type T4 = async extern "C" fn();
-LL + type T4 = extern "C" fn();
+LL + type T4 = extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -79,7 +79,7 @@ LL | type T5 = async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - type T5 = async unsafe extern "C" fn();
-LL + type T5 = unsafe extern "C" fn();
+LL + type T5 = unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -93,7 +93,7 @@ LL | type T6 = const async unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - type T6 = const async unsafe extern "C" fn();
-LL + type T6 = async unsafe extern "C" fn();
+LL + type T6 = async unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -107,7 +107,7 @@ LL | type T6 = const async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - type T6 = const async unsafe extern "C" fn();
-LL + type T6 = const unsafe extern "C" fn();
+LL + type T6 = const unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -121,7 +121,7 @@ LL | type FT0 = for<'a> const fn();
help: remove the `const` qualifier
|
LL - type FT0 = for<'a> const fn();
-LL + type FT0 = for<'a> fn();
+LL + type FT0 = for<'a> fn();
|
error: an `fn` pointer type cannot be `const`
@@ -135,7 +135,7 @@ LL | type FT1 = for<'a> const extern "C" fn();
help: remove the `const` qualifier
|
LL - type FT1 = for<'a> const extern "C" fn();
-LL + type FT1 = for<'a> extern "C" fn();
+LL + type FT1 = for<'a> extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -149,7 +149,7 @@ LL | type FT2 = for<'a> const unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - type FT2 = for<'a> const unsafe extern "C" fn();
-LL + type FT2 = for<'a> unsafe extern "C" fn();
+LL + type FT2 = for<'a> unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -163,7 +163,7 @@ LL | type FT3 = for<'a> async fn();
help: remove the `async` qualifier
|
LL - type FT3 = for<'a> async fn();
-LL + type FT3 = for<'a> fn();
+LL + type FT3 = for<'a> fn();
|
error: an `fn` pointer type cannot be `async`
@@ -177,7 +177,7 @@ LL | type FT4 = for<'a> async extern "C" fn();
help: remove the `async` qualifier
|
LL - type FT4 = for<'a> async extern "C" fn();
-LL + type FT4 = for<'a> extern "C" fn();
+LL + type FT4 = for<'a> extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -191,7 +191,7 @@ LL | type FT5 = for<'a> async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - type FT5 = for<'a> async unsafe extern "C" fn();
-LL + type FT5 = for<'a> unsafe extern "C" fn();
+LL + type FT5 = for<'a> unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `const`
@@ -205,7 +205,7 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn();
help: remove the `const` qualifier
|
LL - type FT6 = for<'a> const async unsafe extern "C" fn();
-LL + type FT6 = for<'a> async unsafe extern "C" fn();
+LL + type FT6 = for<'a> async unsafe extern "C" fn();
|
error: an `fn` pointer type cannot be `async`
@@ -219,7 +219,7 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn();
help: remove the `async` qualifier
|
LL - type FT6 = for<'a> const async unsafe extern "C" fn();
-LL + type FT6 = for<'a> const unsafe extern "C" fn();
+LL + type FT6 = for<'a> const unsafe extern "C" fn();
|
error[E0308]: mismatched types
diff --git a/tests/ui/asan-odr-win/asan_odr_windows.rs b/tests/ui/sanitizer/asan_odr_windows.rs
similarity index 100%
rename from tests/ui/asan-odr-win/asan_odr_windows.rs
rename to tests/ui/sanitizer/asan_odr_windows.rs
diff --git a/tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs b/tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs
similarity index 100%
rename from tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs
rename to tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs