Auto merge of #124147 - workingjubilee:rollup-7pjnzr6, r=workingjubilee

Rollup of 7 pull requests

Successful merges:

 - #123406 (Force exhaustion in iter::ArrayChunks::into_remainder)
 - #123752 (Properly handle emojis as literal prefix in macros)
 - #123935 (Don't inline integer literals when they overflow - new attempt)
 - #123980 ( Add an opt-in to store incoming edges in `VecGraph` + misc)
 - #124019 (Use raw-dylib for Windows synchronization functions)
 - #124110 (Fix negating `f16` and `f128` constants)
 - #124116 (when suggesting RUST_BACKTRACE=1, add a special note for Miri's env var isolation)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-04-19 05:38:13 +00:00
commit 0ed85d0c8d
51 changed files with 620 additions and 157 deletions

View File

@ -20,10 +20,126 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut fmt = Cow::Borrowed(fmt);
if self.tcx.sess.opts.unstable_opts.flatten_format_args {
fmt = flatten_format_args(fmt);
fmt = inline_literals(fmt);
fmt = self.inline_literals(fmt);
}
expand_format_args(self, sp, &fmt, allow_const)
}
/// Try to convert a literal into an interned string
fn try_inline_lit(&self, lit: token::Lit) -> Option<Symbol> {
match LitKind::from_token_lit(lit) {
Ok(LitKind::Str(s, _)) => Some(s),
Ok(LitKind::Int(n, ty)) => {
match ty {
// unsuffixed integer literals are assumed to be i32's
LitIntType::Unsuffixed => {
(n <= i32::MAX as u128).then_some(Symbol::intern(&n.to_string()))
}
LitIntType::Signed(int_ty) => {
let max_literal = self.int_ty_max(int_ty);
(n <= max_literal).then_some(Symbol::intern(&n.to_string()))
}
LitIntType::Unsigned(uint_ty) => {
let max_literal = self.uint_ty_max(uint_ty);
(n <= max_literal).then_some(Symbol::intern(&n.to_string()))
}
}
}
_ => None,
}
}
/// Get the maximum value of int_ty. It is platform-dependent due to the byte size of isize
fn int_ty_max(&self, int_ty: IntTy) -> u128 {
match int_ty {
IntTy::Isize => self.tcx.data_layout.pointer_size.signed_int_max() as u128,
IntTy::I8 => i8::MAX as u128,
IntTy::I16 => i16::MAX as u128,
IntTy::I32 => i32::MAX as u128,
IntTy::I64 => i64::MAX as u128,
IntTy::I128 => i128::MAX as u128,
}
}
/// Get the maximum value of uint_ty. It is platform-dependent due to the byte size of usize
fn uint_ty_max(&self, uint_ty: UintTy) -> u128 {
match uint_ty {
UintTy::Usize => self.tcx.data_layout.pointer_size.unsigned_int_max(),
UintTy::U8 => u8::MAX as u128,
UintTy::U16 => u16::MAX as u128,
UintTy::U32 => u32::MAX as u128,
UintTy::U64 => u64::MAX as u128,
UintTy::U128 => u128::MAX as u128,
}
}
/// Inline literals into the format string.
///
/// Turns
///
/// `format_args!("Hello, {}! {} {}", "World", 123, x)`
///
/// into
///
/// `format_args!("Hello, World! 123 {}", x)`.
fn inline_literals<'fmt>(&self, mut fmt: Cow<'fmt, FormatArgs>) -> Cow<'fmt, FormatArgs> {
let mut was_inlined = vec![false; fmt.arguments.all_args().len()];
let mut inlined_anything = false;
for i in 0..fmt.template.len() {
let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue };
let Ok(arg_index) = placeholder.argument.index else { continue };
let mut literal = None;
if let FormatTrait::Display = placeholder.format_trait
&& placeholder.format_options == Default::default()
&& let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs()
&& let ExprKind::Lit(lit) = arg.kind
{
literal = self.try_inline_lit(lit);
}
if let Some(literal) = literal {
// Now we need to mutate the outer FormatArgs.
// If this is the first time, this clones the outer FormatArgs.
let fmt = fmt.to_mut();
// Replace the placeholder with the literal.
fmt.template[i] = FormatArgsPiece::Literal(literal);
was_inlined[arg_index] = true;
inlined_anything = true;
}
}
// Remove the arguments that were inlined.
if inlined_anything {
let fmt = fmt.to_mut();
let mut remove = was_inlined;
// Don't remove anything that's still used.
for_all_argument_indexes(&mut fmt.template, |index| remove[*index] = false);
// Drop all the arguments that are marked for removal.
let mut remove_it = remove.iter();
fmt.arguments.all_args_mut().retain(|_| remove_it.next() != Some(&true));
// Calculate the mapping of old to new indexes for the remaining arguments.
let index_map: Vec<usize> = remove
.into_iter()
.scan(0, |i, remove| {
let mapped = *i;
*i += !remove as usize;
Some(mapped)
})
.collect();
// Correct the indexes that refer to arguments that have shifted position.
for_all_argument_indexes(&mut fmt.template, |index| *index = index_map[*index]);
}
fmt
}
}
/// Flattens nested `format_args!()` into one.
@ -103,82 +219,6 @@ fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
fmt
}
/// Inline literals into the format string.
///
/// Turns
///
/// `format_args!("Hello, {}! {} {}", "World", 123, x)`
///
/// into
///
/// `format_args!("Hello, World! 123 {}", x)`.
fn inline_literals(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
let mut was_inlined = vec![false; fmt.arguments.all_args().len()];
let mut inlined_anything = false;
for i in 0..fmt.template.len() {
let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue };
let Ok(arg_index) = placeholder.argument.index else { continue };
let mut literal = None;
if let FormatTrait::Display = placeholder.format_trait
&& placeholder.format_options == Default::default()
&& let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs()
&& let ExprKind::Lit(lit) = arg.kind
{
if let token::LitKind::Str | token::LitKind::StrRaw(_) = lit.kind
&& let Ok(LitKind::Str(s, _)) = LitKind::from_token_lit(lit)
{
literal = Some(s);
} else if let token::LitKind::Integer = lit.kind
&& let Ok(LitKind::Int(n, _)) = LitKind::from_token_lit(lit)
{
literal = Some(Symbol::intern(&n.to_string()));
}
}
if let Some(literal) = literal {
// Now we need to mutate the outer FormatArgs.
// If this is the first time, this clones the outer FormatArgs.
let fmt = fmt.to_mut();
// Replace the placeholder with the literal.
fmt.template[i] = FormatArgsPiece::Literal(literal);
was_inlined[arg_index] = true;
inlined_anything = true;
}
}
// Remove the arguments that were inlined.
if inlined_anything {
let fmt = fmt.to_mut();
let mut remove = was_inlined;
// Don't remove anything that's still used.
for_all_argument_indexes(&mut fmt.template, |index| remove[*index] = false);
// Drop all the arguments that are marked for removal.
let mut remove_it = remove.iter();
fmt.arguments.all_args_mut().retain(|_| remove_it.next() != Some(&true));
// Calculate the mapping of old to new indexes for the remaining arguments.
let index_map: Vec<usize> = remove
.into_iter()
.scan(0, |i, remove| {
let mapped = *i;
*i += !remove as usize;
Some(mapped)
})
.collect();
// Correct the indexes that refer to arguments that have shifted position.
for_all_argument_indexes(&mut fmt.template, |index| *index = index_map[*index]);
}
fmt
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
enum ArgumentType {
Format(FormatTrait),

View File

@ -0,0 +1,37 @@
From 0d741cf82c3c908616abd39dc84ebf7d8702e0c3 Mon Sep 17 00:00:00 2001
From: Chris Denton <chris@chrisdenton.dev>
Date: Tue, 16 Apr 2024 15:51:34 +0000
Subject: [PATCH] Revert use raw-dylib for Windows futex APIs
---
library/std/src/sys/pal/windows/c.rs | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 9d58ce05f01..1c828bac4b6 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -357,19 +357,7 @@ pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
}
#[cfg(not(target_vendor = "win7"))]
-// Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library.
-#[cfg_attr(
- target_arch = "x86",
- link(
- name = "api-ms-win-core-synch-l1-2-0",
- kind = "raw-dylib",
- import_name_type = "undecorated"
- )
-)]
-#[cfg_attr(
- not(target_arch = "x86"),
- link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")
-)]
+#[link(name = "synchronization")]
extern "system" {
pub fn WaitOnAddress(
address: *const c_void,
--
2.42.0.windows.2

View File

@ -70,21 +70,21 @@ pub fn reverse_post_order<G: DirectedGraph + Successors>(
}
/// A "depth-first search" iterator for a directed graph.
pub struct DepthFirstSearch<'graph, G>
pub struct DepthFirstSearch<G>
where
G: ?Sized + DirectedGraph + Successors,
G: DirectedGraph + Successors,
{
graph: &'graph G,
graph: G,
stack: Vec<G::Node>,
visited: BitSet<G::Node>,
}
impl<'graph, G> DepthFirstSearch<'graph, G>
impl<G> DepthFirstSearch<G>
where
G: ?Sized + DirectedGraph + Successors,
G: DirectedGraph + Successors,
{
pub fn new(graph: &'graph G) -> Self {
Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) }
pub fn new(graph: G) -> Self {
Self { stack: vec![], visited: BitSet::new_empty(graph.num_nodes()), graph }
}
/// Version of `push_start_node` that is convenient for chained
@ -125,9 +125,9 @@ where
}
}
impl<G> std::fmt::Debug for DepthFirstSearch<'_, G>
impl<G> std::fmt::Debug for DepthFirstSearch<G>
where
G: ?Sized + DirectedGraph + Successors,
G: DirectedGraph + Successors,
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = fmt.debug_set();
@ -138,9 +138,9 @@ where
}
}
impl<G> Iterator for DepthFirstSearch<'_, G>
impl<G> Iterator for DepthFirstSearch<G>
where
G: ?Sized + DirectedGraph + Successors,
G: DirectedGraph + Successors,
{
type Item = G::Node;

View File

@ -46,9 +46,35 @@ where
.is_some()
}
pub fn depth_first_search<G>(graph: &G, from: G::Node) -> iterate::DepthFirstSearch<'_, G>
pub fn depth_first_search<G>(graph: G, from: G::Node) -> iterate::DepthFirstSearch<G>
where
G: ?Sized + Successors,
G: Successors,
{
iterate::DepthFirstSearch::new(graph).with_start_node(from)
}
pub fn depth_first_search_as_undirected<G>(
graph: G,
from: G::Node,
) -> iterate::DepthFirstSearch<impl Successors<Node = G::Node>>
where
G: Successors + Predecessors,
{
struct AsUndirected<G>(G);
impl<G: DirectedGraph> DirectedGraph for AsUndirected<G> {
type Node = G::Node;
fn num_nodes(&self) -> usize {
self.0.num_nodes()
}
}
impl<G: Successors + Predecessors> Successors for AsUndirected<G> {
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
self.0.successors(node).chain(self.0.predecessors(node))
}
}
iterate::DepthFirstSearch::new(AsUndirected(graph)).with_start_node(from)
}

View File

@ -1,99 +1,235 @@
use crate::graph::{DirectedGraph, NumEdges, Successors};
use crate::graph::{DirectedGraph, NumEdges, Predecessors, Successors};
use rustc_index::{Idx, IndexVec};
#[cfg(test)]
mod tests;
pub struct VecGraph<N: Idx> {
/// Maps from a given node to an index where the set of successors
/// for that node starts. The index indexes into the `edges`
/// vector. To find the range for a given node, we look up the
/// start for that node and then the start for the next node
/// (i.e., with an index 1 higher) and get the range between the
/// two. This vector always has an extra entry so that this works
/// even for the max element.
/// A directed graph, efficient for cases where node indices are pre-existing.
///
/// If `BR` is true, the graph will store back-references, allowing you to get predecessors.
pub struct VecGraph<N: Idx, const BR: bool = false> {
// This is basically a `HashMap<N, (Vec<N>, If<BR, Vec<N>>)>` -- a map from a node index, to
// a list of targets of outgoing edges and (if enabled) a list of sources of incoming edges.
//
// However, it is condensed into two arrays as an optimization.
//
// `node_starts[n]` is the start of the list of targets of outgoing edges for node `n`.
// So you can get node's successors with `edge_targets[node_starts[n]..node_starts[n + 1]]`.
//
// If `BR` is true (back references are enabled), then `node_starts[n + edge_count]` is the
// start of the list of *sources* of incoming edges. You can get predecessors of a node
// similarly to its successors but offsetting by `edge_count`. `edge_count` is
// `edge_targets.len()/2` (again, in case BR is true) because half of the vec is back refs.
//
// All of this might be confusing, so here is an example graph and its representation:
//
// n3 ----+
// ^ | (if BR = true)
// | v outgoing edges incoming edges
// n0 -> n1 -> n2 ______________ __________________
// / \ / \
// node indices[1]: n0, n1, n2, n3, n0, n1, n2, n3, n/a
// vec indices: n0, n1, n2, n3, n4, n5, n6, n7, n8
// node_starts: [0, 1, 3, 4 4, 4, 5, 7, 8]
// | | | | | | | | |
// | | +---+ +---+ | +---+ |
// | | | | | | |
// v v v v v v v
// edge_targets: [n1, n2, n3, n2 n0, n1, n3, n1]
// / \____/ | | \____/ \
// n0->n1 / | | \ n3<-n1
// / n3->n2 [2] n1<-n0 [2] \
// n1->n2, n1->n3 n2<-n1, n2<-n3
//
// The incoming edges are basically stored in the same way as outgoing edges, but offset and
// the graph they store is the inverse of the original. Last index in the `node_starts` array
// always points to one-past-the-end, so that we don't need to bound check `node_starts[n + 1]`
//
// [1]: "node indices" are the indices a user of `VecGraph` might use,
// note that they are different from "vec indices",
// which are the real indices you need to index `node_starts`
//
// [2]: Note that even though n2 also points to here,
// the next index also points here, so n2 has no
// successors (`edge_targets[3..3] = []`).
// Similarly with n0 and incoming edges
//
// If this is still confusing... then sorry :(
//
/// Indices into `edge_targets` that signify a start of list of edges.
node_starts: IndexVec<N, usize>,
/// Targets (or sources for back refs) of edges
edge_targets: Vec<N>,
}
impl<N: Idx + Ord> VecGraph<N> {
impl<N: Idx + Ord, const BR: bool> VecGraph<N, BR> {
pub fn new(num_nodes: usize, mut edge_pairs: Vec<(N, N)>) -> Self {
let num_edges = edge_pairs.len();
let nodes_cap = match BR {
// +1 for special entry at the end, pointing one past the end of `edge_targets`
false => num_nodes + 1,
// *2 for back references
true => (num_nodes * 2) + 1,
};
let edges_cap = match BR {
false => num_edges,
// *2 for back references
true => num_edges * 2,
};
let mut node_starts = IndexVec::with_capacity(nodes_cap);
let mut edge_targets = Vec::with_capacity(edges_cap);
// Sort the edges by the source -- this is important.
edge_pairs.sort();
let num_edges = edge_pairs.len();
// Fill forward references
create_index(
num_nodes,
&mut edge_pairs.iter().map(|&(src, _)| src),
&mut edge_pairs.iter().map(|&(_, tgt)| tgt),
&mut edge_targets,
&mut node_starts,
);
// Store the *target* of each edge into `edge_targets`.
let edge_targets: Vec<N> = edge_pairs.iter().map(|&(_, target)| target).collect();
// Fill back references
if BR {
// Pop the special "last" entry, it will be replaced by first back ref
node_starts.pop();
// Create the *edge starts* array. We are iterating over the
// (sorted) edge pairs. We maintain the invariant that the
// length of the `node_starts` array is enough to store the
// current source node -- so when we see that the source node
// for an edge is greater than the current length, we grow the
// edge-starts array by just enough.
let mut node_starts = IndexVec::with_capacity(num_edges);
for (index, &(source, _)) in edge_pairs.iter().enumerate() {
// If we have a list like `[(0, x), (2, y)]`:
//
// - Start out with `node_starts` of `[]`
// - Iterate to `(0, x)` at index 0:
// - Push one entry because `node_starts.len()` (0) is <= the source (0)
// - Leaving us with `node_starts` of `[0]`
// - Iterate to `(2, y)` at index 1:
// - Push one entry because `node_starts.len()` (1) is <= the source (2)
// - Push one entry because `node_starts.len()` (2) is <= the source (2)
// - Leaving us with `node_starts` of `[0, 1, 1]`
// - Loop terminates
while node_starts.len() <= source.index() {
node_starts.push(index);
}
// Re-sort the edges so that they are sorted by target
edge_pairs.sort_by_key(|&(src, tgt)| (tgt, src));
create_index(
// Back essentially double the number of nodes
num_nodes * 2,
// NB: the source/target are switched here too
// NB: we double the key index, so that we can later use *2 to get the back references
&mut edge_pairs.iter().map(|&(_, tgt)| N::new(tgt.index() + num_nodes)),
&mut edge_pairs.iter().map(|&(src, _)| src),
&mut edge_targets,
&mut node_starts,
);
}
// Pad out the `node_starts` array so that it has `num_nodes +
// 1` entries. Continuing our example above, if `num_nodes` is
// be `3`, we would push one more index: `[0, 1, 1, 2]`.
//
// Interpretation of that vector:
//
// [0, 1, 1, 2]
// ---- range for N=2
// ---- range for N=1
// ---- range for N=0
while node_starts.len() <= num_nodes {
node_starts.push(edge_targets.len());
}
assert_eq!(node_starts.len(), num_nodes + 1);
Self { node_starts, edge_targets }
}
/// Gets the successors for `source` as a slice.
pub fn successors(&self, source: N) -> &[N] {
assert!(source.index() < self.num_nodes());
let start_index = self.node_starts[source];
let end_index = self.node_starts[source.plus(1)];
&self.edge_targets[start_index..end_index]
}
}
impl<N: Idx> DirectedGraph for VecGraph<N> {
impl<N: Idx + Ord> VecGraph<N, true> {
/// Gets the predecessors for `target` as a slice.
pub fn predecessors(&self, target: N) -> &[N] {
assert!(target.index() < self.num_nodes());
let target = N::new(target.index() + self.num_nodes());
let start_index = self.node_starts[target];
let end_index = self.node_starts[target.plus(1)];
&self.edge_targets[start_index..end_index]
}
}
/// Creates/initializes the index for the [`VecGraph`]. A helper for [`VecGraph::new`].
///
/// - `num_nodes` is the target number of nodes in the graph
/// - `sorted_edge_sources` are the edge sources, sorted
/// - `associated_edge_targets` are the edge *targets* in the same order as sources
/// - `edge_targets` is the vec of targets to be extended
/// - `node_starts` is the index to be filled
fn create_index<N: Idx + Ord>(
num_nodes: usize,
sorted_edge_sources: &mut dyn Iterator<Item = N>,
associated_edge_targets: &mut dyn Iterator<Item = N>,
edge_targets: &mut Vec<N>,
node_starts: &mut IndexVec<N, usize>,
) {
let offset = edge_targets.len();
// Store the *target* of each edge into `edge_targets`.
edge_targets.extend(associated_edge_targets);
// Create the *edge starts* array. We are iterating over the
// (sorted) edge pairs. We maintain the invariant that the
// length of the `node_starts` array is enough to store the
// current source node -- so when we see that the source node
// for an edge is greater than the current length, we grow the
// edge-starts array by just enough.
for (index, source) in sorted_edge_sources.enumerate() {
// If we have a list like `[(0, x), (2, y)]`:
//
// - Start out with `node_starts` of `[]`
// - Iterate to `(0, x)` at index 0:
// - Push one entry because `node_starts.len()` (0) is <= the source (0)
// - Leaving us with `node_starts` of `[0]`
// - Iterate to `(2, y)` at index 1:
// - Push one entry because `node_starts.len()` (1) is <= the source (2)
// - Push one entry because `node_starts.len()` (2) is <= the source (2)
// - Leaving us with `node_starts` of `[0, 1, 1]`
// - Loop terminates
while node_starts.len() <= source.index() {
node_starts.push(index + offset);
}
}
// Pad out the `node_starts` array so that it has `num_nodes +
// 1` entries. Continuing our example above, if `num_nodes` is
// be `3`, we would push one more index: `[0, 1, 1, 2]`.
//
// Interpretation of that vector:
//
// [0, 1, 1, 2]
// ---- range for N=2
// ---- range for N=1
// ---- range for N=0
while node_starts.len() <= num_nodes {
node_starts.push(edge_targets.len());
}
assert_eq!(node_starts.len(), num_nodes + 1);
}
impl<N: Idx, const BR: bool> DirectedGraph for VecGraph<N, BR> {
type Node = N;
fn num_nodes(&self) -> usize {
self.node_starts.len() - 1
match BR {
false => self.node_starts.len() - 1,
// If back refs are enabled, half of the array is said back refs
true => (self.node_starts.len() - 1) / 2,
}
}
}
impl<N: Idx> NumEdges for VecGraph<N> {
impl<N: Idx, const BR: bool> NumEdges for VecGraph<N, BR> {
fn num_edges(&self) -> usize {
self.edge_targets.len()
match BR {
false => self.edge_targets.len(),
// If back refs are enabled, half of the array is reversed edges for them
true => self.edge_targets.len() / 2,
}
}
}
impl<N: Idx + Ord> Successors for VecGraph<N> {
impl<N: Idx + Ord, const BR: bool> Successors for VecGraph<N, BR> {
fn successors(&self, node: N) -> impl Iterator<Item = Self::Node> {
self.successors(node).iter().cloned()
}
}
impl<N: Idx + Ord> Predecessors for VecGraph<N, true> {
fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
self.predecessors(node).iter().cloned()
}
}

View File

@ -18,10 +18,18 @@ fn create_graph() -> VecGraph<usize> {
VecGraph::new(7, vec![(0, 1), (1, 2), (1, 3), (3, 4), (5, 1)])
}
fn create_graph_with_back_refs() -> VecGraph<usize, true> {
// Same as above
VecGraph::new(7, vec![(0, 1), (1, 2), (1, 3), (3, 4), (5, 1)])
}
#[test]
fn num_nodes() {
let graph = create_graph();
assert_eq!(graph.num_nodes(), 7);
let graph = create_graph_with_back_refs();
assert_eq!(graph.num_nodes(), 7);
}
#[test]
@ -34,6 +42,27 @@ fn successors() {
assert_eq!(graph.successors(4), &[] as &[usize]);
assert_eq!(graph.successors(5), &[1]);
assert_eq!(graph.successors(6), &[] as &[usize]);
let graph = create_graph_with_back_refs();
assert_eq!(graph.successors(0), &[1]);
assert_eq!(graph.successors(1), &[2, 3]);
assert_eq!(graph.successors(2), &[] as &[usize]);
assert_eq!(graph.successors(3), &[4]);
assert_eq!(graph.successors(4), &[] as &[usize]);
assert_eq!(graph.successors(5), &[1]);
assert_eq!(graph.successors(6), &[] as &[usize]);
}
#[test]
fn predecessors() {
let graph = create_graph_with_back_refs();
assert_eq!(graph.predecessors(0), &[]);
assert_eq!(graph.predecessors(1), &[0, 5]);
assert_eq!(graph.predecessors(2), &[1]);
assert_eq!(graph.predecessors(3), &[1]);
assert_eq!(graph.predecessors(4), &[3]);
assert_eq!(graph.predecessors(5), &[]);
assert_eq!(graph.predecessors(6), &[]);
}
#[test]
@ -41,4 +70,8 @@ fn dfs() {
let graph = create_graph();
let dfs: Vec<_> = graph::depth_first_search(&graph, 0).collect();
assert_eq!(dfs, vec![0, 1, 3, 4, 2]);
let graph = create_graph_with_back_refs();
let dfs: Vec<_> = graph::depth_first_search(&graph, 0).collect();
assert_eq!(dfs, vec![0, 1, 3, 4, 2]);
}

View File

@ -382,7 +382,7 @@ impl<'tcx> MiniGraph<'tcx> {
edges.push((source_node, target_node));
},
);
let graph = VecGraph::new(nodes.len(), edges);
let graph = VecGraph::<_, false>::new(nodes.len(), edges);
let sccs = Sccs::new(&graph);
Self { nodes, sccs }
}

View File

@ -88,6 +88,10 @@ pub enum TokenKind {
/// tokens.
UnknownPrefix,
/// Similar to the above, but *always* an error on every edition. This is used
/// for emoji identifier recovery, as those are not meant to be ever accepted.
InvalidPrefix,
/// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid
/// suffix, but may be present here on string and float literals. Users of
/// this type will need to check for and reject that case.
@ -528,7 +532,7 @@ impl Cursor<'_> {
// Known prefixes must have been handled earlier. So if
// we see a prefix here, it is definitely an unknown prefix.
match self.first() {
'#' | '"' | '\'' => UnknownPrefix,
'#' | '"' | '\'' => InvalidPrefix,
_ => InvalidIdent,
}
}

View File

@ -1023,7 +1023,13 @@ pub(crate) fn parse_float_into_scalar(
let num = num.as_str();
match float_ty {
// FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64`
ty::FloatTy::F16 => num.parse::<Half>().ok().map(Scalar::from_f16),
ty::FloatTy::F16 => {
let mut f = num.parse::<Half>().ok()?;
if neg {
f = -f;
}
Some(Scalar::from_f16(f))
}
ty::FloatTy::F32 => {
let Ok(rust_f) = num.parse::<f32>() else { return None };
let mut f = num
@ -1071,7 +1077,13 @@ pub(crate) fn parse_float_into_scalar(
Some(Scalar::from_f64(f))
}
// FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64`
ty::FloatTy::F128 => num.parse::<Quad>().ok().map(Scalar::from_f128),
ty::FloatTy::F128 => {
let mut f = num.parse::<Quad>().ok()?;
if neg {
f = -f;
}
Some(Scalar::from_f128(f))
}
}
}

View File

@ -204,6 +204,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
self.ident(start)
}
rustc_lexer::TokenKind::InvalidIdent
| rustc_lexer::TokenKind::InvalidPrefix
// Do not recover an identifier with emoji if the codepoint is a confusable
// with a recoverable substitution token, like ``.
if !UNICODE_ARRAY
@ -301,7 +302,9 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
rustc_lexer::TokenKind::Unknown
| rustc_lexer::TokenKind::InvalidIdent
| rustc_lexer::TokenKind::InvalidPrefix => {
// Don't emit diagnostics for sequences of the same invalid token
if swallow_next_invalid > 0 {
swallow_next_invalid -= 1;

View File

@ -34,9 +34,22 @@ where
/// Returns an iterator over the remaining elements of the original iterator
/// that are not going to be returned by this iterator. The returned
/// iterator will yield at most `N-1` elements.
///
/// # Example
/// ```
/// # // Also serves as a regression test for https://github.com/rust-lang/rust/issues/123333
/// # #![feature(iter_array_chunks)]
/// let x = [1,2,3,4,5].into_iter().array_chunks::<2>();
/// let mut rem = x.into_remainder().unwrap();
/// assert_eq!(rem.next(), Some(5));
/// assert_eq!(rem.next(), None);
/// ```
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
#[inline]
pub fn into_remainder(self) -> Option<array::IntoIter<I::Item, N>> {
pub fn into_remainder(mut self) -> Option<array::IntoIter<I::Item, N>> {
if self.remainder.is_none() {
while let Some(_) = self.next() {}
}
self.remainder
}
}

View File

@ -277,6 +277,13 @@ fn default_hook(info: &PanicInfo<'_>) {
"note: run with `RUST_BACKTRACE=1` environment variable to display a \
backtrace"
);
if cfg!(miri) {
let _ = writeln!(
err,
"note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` \
for the environment variable to have an effect"
);
}
}
}
// If backtraces aren't supported or are forced-off, do nothing.

View File

@ -357,7 +357,19 @@ compat_fn_with_fallback! {
}
#[cfg(not(target_vendor = "win7"))]
#[link(name = "synchronization")]
// Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library.
#[cfg_attr(
target_arch = "x86",
link(
name = "api-ms-win-core-synch-l1-2-0",
kind = "raw-dylib",
import_name_type = "undecorated"
)
)]
#[cfg_attr(
not(target_arch = "x86"),
link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")
)]
extern "system" {
pub fn WaitOnAddress(
address: *const c_void,

View File

@ -876,9 +876,10 @@ impl<'src> Classifier<'src> {
},
Some(c) => c,
},
TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {
Class::Ident(self.new_span(before, text))
}
TokenKind::RawIdent
| TokenKind::UnknownPrefix
| TokenKind::InvalidPrefix
| TokenKind::InvalidIdent => Class::Ident(self.new_span(before, text)),
TokenKind::Lifetime { .. } => Class::Lifetime,
TokenKind::Eof => panic!("Eof in advance"),
};

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/exported_symbol_bad_unwind1.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding
--> $DIR/exported_symbol_bad_unwind1.rs:LL:CC
|

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
panic in a function that cannot unwind
stack backtrace:

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
panic in a function that cannot unwind
stack backtrace:

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding
--> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/return_pointer_on_unwind.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/return_pointer_on_unwind.rs:LL:CC
|

View File

@ -1,6 +1,7 @@
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
aborted execution: attempted to instantiate uninhabited type `!`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread caused non-unwinding panic. aborting.
error: abnormal termination: the program aborted execution
--> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC

View File

@ -1,6 +1,7 @@
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
aborted execution: attempted to zero-initialize type `fn()`, which is invalid
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread caused non-unwinding panic. aborting.
error: abnormal termination: the program aborted execution
--> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/bad_unwind.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding
--> $DIR/bad_unwind.rs:LL:CC
|

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/double_panic.rs:LL:CC:
first
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'main' panicked at $DIR/double_panic.rs:LL:CC:
second
stack backtrace:

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/panic_abort1.rs:LL:CC:
panicking from libstd
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: abnormal termination: the program aborted execution
--> RUSTLIB/panic_abort/src/lib.rs:LL:CC
|

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/panic_abort2.rs:LL:CC:
42-panicking from libstd
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: abnormal termination: the program aborted execution
--> RUSTLIB/panic_abort/src/lib.rs:LL:CC
|

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/panic_abort3.rs:LL:CC:
panicking from libcore
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: abnormal termination: the program aborted execution
--> RUSTLIB/panic_abort/src/lib.rs:LL:CC
|

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/panic_abort4.rs:LL:CC:
42-panicking from libcore
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
error: abnormal termination: the program aborted execution
--> RUSTLIB/panic_abort/src/lib.rs:LL:CC
|

View File

@ -3,6 +3,7 @@ warning: You have explicitly enabled MIR optimizations, overriding Miri's defaul
thread 'main' panicked at $DIR/terminate-terminator.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
panic in a function that cannot unwind
stack backtrace:

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/unwind-action-terminate.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
panic in a function that cannot unwind
stack backtrace:

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/div-by-zero-2.rs:LL:CC:
attempt to divide by zero
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC:
explicit panic
thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC:

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/oob_subslice.rs:LL:CC:
range end index 5 out of range for slice of length 4
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/overflowing-lsh-neg.rs:LL:CC:
attempt to shift left with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/overflowing-rsh-1.rs:LL:CC:
attempt to shift right with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/overflowing-rsh-2.rs:LL:CC:
attempt to shift right with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/panic2.rs:LL:CC:
42-panicking from libstd
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/panic3.rs:LL:CC:
panicking from libcore
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/panic4.rs:LL:CC:
42-panicking from libcore
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/transmute_fat2.rs:LL:CC:
index out of bounds: the len is 0 but the index is 0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/unsupported_foreign_function.rs:LL:CC:
unsupported Miri functionality: can't call foreign function `foo` on $OS
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,3 +1,4 @@
thread 'main' panicked at $DIR/unsupported_syscall.rs:LL:CC:
unsupported Miri functionality: can't execute syscall with ID 0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
Hello from std::panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
Caught panic message (&str): Hello from std::panic
thread 'main' panicked at $DIR/catch_panic.rs:LL:CC:
Hello from std::panic: 1

View File

@ -3,6 +3,7 @@ Thread 1 reported it has started
thread '<unnamed>' panicked at $DIR/concurrent-panic.rs:LL:CC:
panic in thread 2
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
Thread 2 blocking on thread 1
Thread 2 reported it has started
Unlocking mutex

View File

@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC:
once
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC:
twice
stack backtrace:

View File

@ -1,5 +1,6 @@
thread '<unnamed>' panicked at $DIR/thread_panic.rs:LL:CC:
Hello!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
thread 'childthread' panicked at $DIR/thread_panic.rs:LL:CC:
Hello, world!

View File

@ -178,7 +178,7 @@ impl<'a> Converter<'a> {
rustc_lexer::TokenKind::Ident => {
SyntaxKind::from_keyword(token_text).unwrap_or(IDENT)
}
rustc_lexer::TokenKind::InvalidIdent => {
rustc_lexer::TokenKind::InvalidPrefix | rustc_lexer::TokenKind::InvalidIdent => {
err = "Ident contains invalid characters";
IDENT
}

View File

@ -0,0 +1,14 @@
//@ only-64bit
fn main() {
format_args!("{}", 0x8f_i8); // issue #115423
//~^ ERROR literal out of range for `i8`
format_args!("{}", 0xffff_ffff_u8); // issue #116633
//~^ ERROR literal out of range for `u8`
format_args!("{}", 0xffff_ffff_ffff_ffff_ffff_usize);
//~^ ERROR literal out of range for `usize`
format_args!("{}", 0x8000_0000_0000_0000_isize);
//~^ ERROR literal out of range for `isize`
format_args!("{}", 0xffff_ffff); // treat unsuffixed literals as i32
//~^ ERROR literal out of range for `i32`
}

View File

@ -0,0 +1,56 @@
error: literal out of range for `i8`
--> $DIR/no-inline-literals-out-of-range.rs:4:24
|
LL | format_args!("{}", 0x8f_i8); // issue #115423
| ^^^^^^^
|
= note: the literal `0x8f_i8` (decimal `143`) does not fit into the type `i8` and will become `-113i8`
= note: `#[deny(overflowing_literals)]` on by default
help: consider using the type `u8` instead
|
LL | format_args!("{}", 0x8f_u8); // issue #115423
| ~~~~~~~
help: to use as a negative number (decimal `-113`), consider using the type `u8` for the literal and cast it to `i8`
|
LL | format_args!("{}", 0x8f_u8 as i8); // issue #115423
| ~~~~~~~~~~~~~
error: literal out of range for `u8`
--> $DIR/no-inline-literals-out-of-range.rs:6:24
|
LL | format_args!("{}", 0xffff_ffff_u8); // issue #116633
| ^^^^^^^^^^^^^^ help: consider using the type `u32` instead: `0xffff_ffff_u32`
|
= note: the literal `0xffff_ffff_u8` (decimal `4294967295`) does not fit into the type `u8` and will become `255u8`
error: literal out of range for `usize`
--> $DIR/no-inline-literals-out-of-range.rs:8:24
|
LL | format_args!("{}", 0xffff_ffff_ffff_ffff_ffff_usize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `0xffff_ffff_ffff_ffff_ffff_usize` (decimal `1208925819614629174706175`) does not fit into the type `usize` and will become `18446744073709551615usize`
error: literal out of range for `isize`
--> $DIR/no-inline-literals-out-of-range.rs:10:24
|
LL | format_args!("{}", 0x8000_0000_0000_0000_isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `0x8000_0000_0000_0000_isize` (decimal `9223372036854775808`) does not fit into the type `isize` and will become `-9223372036854775808isize`
error: literal out of range for `i32`
--> $DIR/no-inline-literals-out-of-range.rs:12:24
|
LL | format_args!("{}", 0xffff_ffff); // treat unsuffixed literals as i32
| ^^^^^^^^^^^
|
= note: the literal `0xffff_ffff` (decimal `4294967295`) does not fit into the type `i32` and will become `-1i32`
= help: consider using the type `u32` instead
help: to use as a negative number (decimal `-1`), consider using the type `u32` for the literal and cast it to `i32`
|
LL | format_args!("{}", 0xffff_ffffu32 as i32); // treat unsuffixed literals as i32
| ~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 5 previous errors

View File

@ -0,0 +1,8 @@
macro_rules! lexes {($($_:tt)*) => {}}
lexes!(🐛#); //~ ERROR identifiers cannot contain emoji
lexes!(🐛"foo");
lexes!(🐛'q');
lexes!(🐛'q);
fn main() {}

View File

@ -0,0 +1,14 @@
error: identifiers cannot contain emoji: `🐛`
--> $DIR/emoji-literal-prefix.rs:3:8
|
LL | lexes!(🐛#);
| ^^
LL | lexes!(🐛"foo");
| ^^
LL | lexes!(🐛'q');
| ^^
LL | lexes!(🐛'q);
| ^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,16 @@
//@ run-pass
#![feature(f16)]
#![feature(f128)]
fn main() {
assert_eq!(0.0_f16.to_bits(), 0x0000);
assert_eq!((-0.0_f16).to_bits(), 0x8000);
assert_eq!(10.0_f16.to_bits(), 0x4900);
assert_eq!((-10.0_f16).to_bits(), 0xC900);
assert_eq!(0.0_f128.to_bits(), 0x0000_0000_0000_0000_0000_0000_0000_0000);
assert_eq!((-0.0_f128).to_bits(), 0x8000_0000_0000_0000_0000_0000_0000_0000);
assert_eq!(10.0_f128.to_bits(), 0x4002_4000_0000_0000_0000_0000_0000_0000);
assert_eq!((-10.0_f128).to_bits(), 0xC002_4000_0000_0000_0000_0000_0000_0000);
}