Auto merge of #142492 - matthiaskrgr:rollup-a132ytq, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - rust-lang/rust#140593 (Temporary lifetime extension through tuple struct and tuple variant constructors) - rust-lang/rust#141399 ([rustdoc] Give more information into extracted doctest information) - rust-lang/rust#141493 (Delegate `<SocketAddr as Debug>` to `ByteStr`) - rust-lang/rust#141811 (Unimplement unsized_locals) - rust-lang/rust#142243 (float tests: deduplicate min, max, and rounding tests) - rust-lang/rust#142464 (variadic functions: remove list of supported ABIs from error) - rust-lang/rust#142477 (Fix incorrect suggestion when calling an associated type with a type anchor) - rust-lang/rust#142484 (Remove unneeded lifetime bound from signature of BTreeSet::extract_if) - rust-lang/rust#142489 (Update the `compiler-builtins` subtree) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
9822e3dc15
158 changed files with 1859 additions and 1941 deletions
|
|
@ -373,8 +373,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
let features = self.tcx().features();
|
||||
features.unsized_locals() || features.unsized_fn_params()
|
||||
self.tcx().features().unsized_fn_params()
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
|
|
@ -957,7 +956,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` or `unsized_locals` is enabled, only function calls
|
||||
// When `unsized_fn_params` is enabled, only function calls
|
||||
// and nullary ops are checked in `check_call_dest`.
|
||||
if !self.unsized_feature_enabled() {
|
||||
match self.body.local_kind(local) {
|
||||
|
|
@ -1941,7 +1940,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` and `unsized_locals` are both not enabled,
|
||||
// When `unsized_fn_params` is not enabled,
|
||||
// this check is done at `check_local`.
|
||||
if self.unsized_feature_enabled() {
|
||||
let span = term.source_info.span;
|
||||
|
|
|
|||
|
|
@ -32,10 +32,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
|
|||
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
|
||||
|
||||
trait Trait {
|
||||
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
|
||||
// without unsized_locals), but wrappers around `Self` currently are not.
|
||||
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
|
||||
// fn wrapper(self: Wrapper<Self>) -> i32;
|
||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
||||
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
|
||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
|
||||
|
|
|
|||
|
|
@ -37,10 +37,6 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
|
|||
|
||||
|
||||
trait Trait {
|
||||
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
|
||||
// without unsized_locals), but wrappers around `Self` currently are not.
|
||||
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
|
||||
// fn wrapper(self: Wrapper<Self>) -> i32;
|
||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
||||
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
|
||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
|
||||
|
|
|
|||
|
|
@ -263,6 +263,8 @@ declare_features! (
|
|||
/// Allows unnamed fields of struct and union type
|
||||
(removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign"), 131045),
|
||||
(removed, unsafe_no_drop_flag, "1.0.0", None, None),
|
||||
/// Allows unsized rvalues at arguments and parameters.
|
||||
(removed, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), Some("removed due to implementation concerns; see https://github.com/rust-lang/rust/issues/111942")),
|
||||
(removed, unsized_tuple_coercion, "1.87.0", Some(42877),
|
||||
Some("The feature restricts possible layouts for tuples, and this restriction is not worth it."), 137728),
|
||||
/// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
|
||||
|
|
|
|||
|
|
@ -667,8 +667,6 @@ declare_features! (
|
|||
(incomplete, unsized_const_params, "1.82.0", Some(95174)),
|
||||
/// Allows unsized fn parameters.
|
||||
(internal, unsized_fn_params, "1.49.0", Some(48055)),
|
||||
/// Allows unsized rvalues at arguments and parameters.
|
||||
(incomplete, unsized_locals, "1.30.0", Some(48055)),
|
||||
/// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
|
||||
(unstable, used_with_arg, "1.60.0", Some(93798)),
|
||||
/// Allows use of attributes in `where` clauses.
|
||||
|
|
|
|||
|
|
@ -599,7 +599,7 @@ hir_analysis_value_of_associated_struct_already_specified =
|
|||
.label = re-bound here
|
||||
.previous_bound_label = `{$item_name}` bound here first
|
||||
|
||||
hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
|
||||
hir_analysis_variadic_function_compatible_convention = C-variadic functions with the {$convention} calling convention are not supported
|
||||
.label = C-variadic function must have a compatible calling convention
|
||||
|
||||
hir_analysis_variances_of = {$variances}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use std::mem;
|
|||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Arm, Block, Expr, LetStmt, Pat, PatKind, Stmt};
|
||||
|
|
@ -752,13 +753,19 @@ fn resolve_local<'tcx>(
|
|||
record_rvalue_scope_if_borrow_expr(visitor, arm.body, blk_id);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => {
|
||||
// FIXME(@dingxiangfei2009): choose call arguments here
|
||||
// for candidacy for extended parameter rule application
|
||||
}
|
||||
hir::ExprKind::Index(..) => {
|
||||
// FIXME(@dingxiangfei2009): select the indices
|
||||
// as candidate for rvalue scope rules
|
||||
hir::ExprKind::Call(func, args) => {
|
||||
// Recurse into tuple constructors, such as `Some(&temp())`.
|
||||
//
|
||||
// That way, there is no difference between `Some(..)` and `Some { 0: .. }`,
|
||||
// even though the former is syntactically a function call.
|
||||
if let hir::ExprKind::Path(path) = &func.kind
|
||||
&& let hir::QPath::Resolved(None, path) = path
|
||||
&& let Res::SelfCtor(_) | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) = path.res
|
||||
{
|
||||
for arg in args {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, arg, blk_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
|
|||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub conventions: &'a str,
|
||||
pub convention: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -115,12 +115,6 @@ fn require_c_abi_if_c_variadic(
|
|||
abi: ExternAbi,
|
||||
span: Span,
|
||||
) {
|
||||
const CONVENTIONS_UNSTABLE: &str =
|
||||
"`C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`";
|
||||
const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
|
||||
const UNSTABLE_EXPLAIN: &str =
|
||||
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
|
||||
|
||||
// ABIs which can stably use varargs
|
||||
if !decl.c_variadic || matches!(abi, ExternAbi::C { .. } | ExternAbi::Cdecl { .. }) {
|
||||
return;
|
||||
|
|
@ -140,20 +134,18 @@ fn require_c_abi_if_c_variadic(
|
|||
|
||||
// Looks like we need to pick an error to emit.
|
||||
// Is there any feature which we could have enabled to make this work?
|
||||
let unstable_explain =
|
||||
format!("C-variadic functions with the {abi} calling convention are unstable");
|
||||
match abi {
|
||||
ExternAbi::System { .. } => {
|
||||
feature_err(&tcx.sess, sym::extern_system_varargs, span, UNSTABLE_EXPLAIN)
|
||||
feature_err(&tcx.sess, sym::extern_system_varargs, span, unstable_explain)
|
||||
}
|
||||
abi if abi.supports_varargs() => {
|
||||
feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, UNSTABLE_EXPLAIN)
|
||||
feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, unstable_explain)
|
||||
}
|
||||
_ => tcx.dcx().create_err(errors::VariadicFunctionCompatibleConvention {
|
||||
span,
|
||||
conventions: if tcx.sess.opts.unstable_features.is_nightly_build() {
|
||||
CONVENTIONS_UNSTABLE
|
||||
} else {
|
||||
CONVENTIONS_STABLE
|
||||
},
|
||||
convention: &format!("{abi}"),
|
||||
}),
|
||||
}
|
||||
.emit();
|
||||
|
|
|
|||
|
|
@ -1662,9 +1662,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
blk_id,
|
||||
expression,
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals() {
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
ObligationCauseCode::ReturnValue(return_expr_id) => {
|
||||
err = self.report_return_mismatched_types(
|
||||
|
|
@ -1676,9 +1674,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
return_expr_id,
|
||||
expression,
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals() {
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
arm_span,
|
||||
|
|
|
|||
|
|
@ -809,9 +809,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
// Here we want to prevent struct constructors from returning unsized types.
|
||||
// There were two cases this happened: fn pointer coercion in stable
|
||||
// and usual function call in presence of unsized_locals.
|
||||
// Here we want to prevent struct constructors from returning unsized types,
|
||||
// which can happen with fn pointer coercion on stable.
|
||||
// Also, as we just want to check sizedness, instead of introducing
|
||||
// placeholder lifetimes with probing, we just replace higher lifetimes
|
||||
// with fresh vars.
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
|||
),
|
||||
);
|
||||
}
|
||||
} else if !self.fcx.tcx.features().unsized_locals() {
|
||||
} else {
|
||||
self.fcx.require_type_is_sized(
|
||||
var_ty,
|
||||
p.span,
|
||||
|
|
|
|||
|
|
@ -724,7 +724,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
let def_path = tcx.def_path_str(adt_def.did());
|
||||
err.span_suggestion(
|
||||
ty.span.to(item_ident.span),
|
||||
sugg_span,
|
||||
format!("to construct a value of type `{}`, use the explicit path", def_path),
|
||||
def_path,
|
||||
Applicability::MachineApplicable,
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
|
||||
debug!(?closure_hir_id, ?args, ?final_upvar_tys);
|
||||
|
||||
if self.tcx.features().unsized_locals() || self.tcx.features().unsized_fn_params() {
|
||||
if self.tcx.features().unsized_fn_params() {
|
||||
for capture in
|
||||
self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1133,13 +1133,6 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
|
|||
/// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has
|
||||
/// the address of the local's allocation and the type of the local.
|
||||
///
|
||||
/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation
|
||||
/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation.
|
||||
/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under
|
||||
/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and
|
||||
/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into
|
||||
/// the current MIR semantics in a clean way - possibly this needs some design work first.
|
||||
///
|
||||
/// For places that are not locals, ie they have a non-empty list of projections, we define the
|
||||
/// values as a function of the parent place, that is the place with its last [`ProjectionElem`]
|
||||
/// stripped. The way this is computed of course depends on the kind of that last projection
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ pub enum InstanceKind<'tcx> {
|
|||
Intrinsic(DefId),
|
||||
|
||||
/// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the
|
||||
/// `unsized_locals` feature).
|
||||
/// `unsized_fn_params` feature).
|
||||
///
|
||||
/// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` -
|
||||
/// and dereference the argument to call the original function.
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
/// local variable of unsized type. For example, consider this program:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(unsized_locals, unsized_fn_params)]
|
||||
/// #![feature(unsized_fn_params)]
|
||||
/// # use core::fmt::Debug;
|
||||
/// fn foo(p: dyn Debug) { dbg!(p); }
|
||||
/// fn foo(_p: dyn Debug) { /* ... */ }
|
||||
///
|
||||
/// fn bar(box_p: Box<dyn Debug>) { foo(*box_p); }
|
||||
/// ```
|
||||
|
|
@ -84,7 +84,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
/// will actually provide a pointer to the interior of the box, and not move the `dyn Debug`
|
||||
/// value to the stack.
|
||||
///
|
||||
/// See #68304 for more details.
|
||||
/// See <https://github.com/rust-lang/rust/issues/68304> for more details.
|
||||
pub(crate) fn as_local_call_operand(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
|
|
|
|||
|
|
@ -1417,9 +1417,9 @@ fn check_field_tys_sized<'tcx>(
|
|||
coroutine_layout: &CoroutineLayout<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
// No need to check if unsized_locals/unsized_fn_params is disabled,
|
||||
// No need to check if unsized_fn_params is disabled,
|
||||
// since we will error during typeck.
|
||||
if !tcx.features().unsized_locals() && !tcx.features().unsized_fn_params() {
|
||||
if !tcx.features().unsized_fn_params() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,8 +240,6 @@ struct VnState<'body, 'tcx> {
|
|||
next_opaque: usize,
|
||||
/// Cache the deref values.
|
||||
derefs: Vec<VnIndex>,
|
||||
/// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop.
|
||||
feature_unsized_locals: bool,
|
||||
ssa: &'body SsaLocals,
|
||||
dominators: Dominators<BasicBlock>,
|
||||
reused_locals: DenseBitSet<Local>,
|
||||
|
|
@ -273,7 +271,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
evaluated: IndexVec::with_capacity(num_values),
|
||||
next_opaque: 1,
|
||||
derefs: Vec::new(),
|
||||
feature_unsized_locals: tcx.features().unsized_locals(),
|
||||
ssa,
|
||||
dominators,
|
||||
reused_locals: DenseBitSet::new_empty(local_decls.len()),
|
||||
|
|
@ -329,13 +326,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
fn assign(&mut self, local: Local, value: VnIndex) {
|
||||
debug_assert!(self.ssa.is_ssa(local));
|
||||
self.locals[local] = Some(value);
|
||||
|
||||
// Only register the value if its type is `Sized`, as we will emit copies of it.
|
||||
let is_sized = !self.feature_unsized_locals
|
||||
|| self.local_decls[local].ty.is_sized(self.tcx, self.typing_env());
|
||||
if is_sized {
|
||||
self.rev_locals[value].push(local);
|
||||
}
|
||||
self.rev_locals[value].push(local);
|
||||
}
|
||||
|
||||
fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex {
|
||||
|
|
|
|||
|
|
@ -2995,9 +2995,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if local {
|
||||
err.note("all local variables must have a statically known size");
|
||||
}
|
||||
if !tcx.features().unsized_locals() {
|
||||
err.help("unsized locals are gated as an unstable feature");
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::SizedArgumentType(hir_id) => {
|
||||
let mut ty = None;
|
||||
|
|
|
|||
|
|
@ -414,8 +414,8 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
|
||||
let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
|
||||
|
||||
// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
|
||||
// However, this is already considered dyn compatible. We allow it as a special case here.
|
||||
// `self: Self` can't be dispatched on.
|
||||
// However, this is considered dyn compatible. We allow it as a special case here.
|
||||
// FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
|
||||
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
|
||||
if receiver_ty != tcx.types.self_param {
|
||||
|
|
|
|||
|
|
@ -1220,11 +1220,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]);
|
||||
/// ```
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
pub fn extract_if<'a, F, R>(&'a mut self, range: R, pred: F) -> ExtractIf<'a, T, R, F, A>
|
||||
pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A>
|
||||
where
|
||||
T: Ord,
|
||||
R: RangeBounds<T>,
|
||||
F: 'a + FnMut(&T) -> bool,
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
let (inner, alloc) = self.map.extract_if_inner(range);
|
||||
ExtractIf { pred, inner, alloc }
|
||||
|
|
@ -1585,11 +1585,11 @@ where
|
|||
}
|
||||
|
||||
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||
impl<'a, T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A>
|
||||
impl<T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A>
|
||||
where
|
||||
T: PartialOrd,
|
||||
R: RangeBounds<T>,
|
||||
F: 'a + FnMut(&T) -> bool,
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
[workspace]
|
||||
# As part of the release process, we delete `libm/Cargo.toml`. Since
|
||||
# this is only run in CI, we shouldn't need to worry about it.
|
||||
allow_dirty = true
|
||||
publish_allow_dirty = true
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
semver_check = false
|
||||
changelog_include = ["libm"] # libm is included as part of builtins
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"builtins-shim",
|
||||
"builtins-test",
|
||||
"compiler-builtins",
|
||||
"crates/josh-sync",
|
||||
"crates/libm-macros",
|
||||
"crates/musl-math-sys",
|
||||
|
|
@ -14,8 +14,8 @@ members = [
|
|||
]
|
||||
|
||||
default-members = [
|
||||
"builtins-shim",
|
||||
"builtins-test",
|
||||
"compiler-builtins",
|
||||
"crates/libm-macros",
|
||||
"libm",
|
||||
"libm-test",
|
||||
|
|
@ -26,6 +26,10 @@ exclude = [
|
|||
# and `mangled-names` disabled, which is the opposite of what is needed for
|
||||
# other tests, so it makes sense to keep it out of the workspace.
|
||||
"builtins-test-intrinsics",
|
||||
# We test via the `builtins-shim` crate, so exclude the `compiler-builtins`
|
||||
# that has a dependency on `core`. See `builtins-shim/Cargo.toml` for more
|
||||
# details.
|
||||
"compiler-builtins",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
|
|
|||
63
library/compiler-builtins/builtins-shim/Cargo.toml
Normal file
63
library/compiler-builtins/builtins-shim/Cargo.toml
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# NOTE: Must be kept in sync with `../compiler-builtins/Cargo.toml`.
|
||||
#
|
||||
# The manifest at `../compiler-builtins` is what actually gets used in the
|
||||
# rust-lang/rust tree; however, we can't build it out of tree because it
|
||||
# depends on `core` by path, and even optional Cargo dependencies need to be
|
||||
# available at build time. So, we work around this by having this "shim"
|
||||
# manifest that is identical except for the `core` dependency and forwards
|
||||
# to the same sources, which acts as the `compiler-builtins` Cargo entrypoint
|
||||
# for out of tree testing
|
||||
|
||||
[package]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.160"
|
||||
authors = ["Jorge Aparicio <japaricious@gmail.com>"]
|
||||
description = "Compiler intrinsics used by the Rust compiler."
|
||||
repository = "https://github.com/rust-lang/compiler-builtins"
|
||||
license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
links = "compiler-rt"
|
||||
|
||||
build = "../compiler-builtins/build.rs"
|
||||
|
||||
[lib]
|
||||
path = "../compiler-builtins/src/lib.rs"
|
||||
bench = false
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[build-dependencies]
|
||||
cc = { optional = true, version = "1.2" }
|
||||
|
||||
[features]
|
||||
default = ["compiler-builtins"]
|
||||
|
||||
# Enable compilation of C code in compiler-rt, filling in some more optimized
|
||||
# implementations and also filling in unimplemented intrinsics
|
||||
c = ["dep:cc"]
|
||||
|
||||
# Workaround for the Cranelift codegen backend. Disables any implementations
|
||||
# which use inline assembly and fall back to pure Rust versions (if available).
|
||||
no-asm = []
|
||||
|
||||
# Workaround for codegen backends which haven't yet implemented `f16` and
|
||||
# `f128` support. Disabled any intrinsics which use those types.
|
||||
no-f16-f128 = []
|
||||
|
||||
# Flag this library as the unstable compiler-builtins lib
|
||||
compiler-builtins = []
|
||||
|
||||
# Generate memory-related intrinsics like memcpy
|
||||
mem = []
|
||||
|
||||
# Mangle all names so this can be linked in with other versions or other
|
||||
# compiler-rt implementations. Also used for testing
|
||||
mangled-names = []
|
||||
|
||||
# Only used in the compiler's build system
|
||||
rustc-dep-of-std = ["compiler-builtins"]
|
||||
|
||||
# This makes certain traits and function specializations public that
|
||||
# are not normally public but are required by the `builtins-test`
|
||||
unstable-public-internals = []
|
||||
|
|
@ -6,7 +6,7 @@ publish = false
|
|||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"] }
|
||||
compiler_builtins = { path = "../builtins-shim", features = ["compiler-builtins"] }
|
||||
panic-handler = { path = "../crates/panic-handler" }
|
||||
|
||||
[features]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ rustc_apfloat = "0.2.2"
|
|||
iai-callgrind = { version = "0.14.1", optional = true }
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
path = "../compiler-builtins"
|
||||
path = "../builtins-shim"
|
||||
default-features = false
|
||||
features = ["unstable-public-internals"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(decl_macro)] // so we can use pub(super)
|
||||
#![feature(macro_metavar_expr_concat)]
|
||||
#![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))]
|
||||
|
||||
/// Translate a byte size to a Rust type.
|
||||
|
|
@ -87,7 +88,7 @@ test_op!(add, |left, right| left.wrapping_add(right));
|
|||
test_op!(clr, |left, right| left & !right);
|
||||
test_op!(xor, std::ops::BitXor::bitxor);
|
||||
test_op!(or, std::ops::BitOr::bitor);
|
||||
|
||||
use compiler_builtins::{foreach_bytes, foreach_ordering};
|
||||
compiler_builtins::foreach_cas!(cas::test);
|
||||
compiler_builtins::foreach_cas16!(test_cas16);
|
||||
compiler_builtins::foreach_swp!(swap::test);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ function run_icount_benchmarks() {
|
|||
# Disregard regressions after merge
|
||||
echo "Benchmarks completed with regressions; ignoring (not in a PR)"
|
||||
else
|
||||
./ci/ci-util.py handle-banch-regressions "$PR_NUMBER"
|
||||
./ci/ci-util.py handle-bench-regressions "$PR_NUMBER"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
# NOTE: Must be kept in sync with `../builtins-shim/Cargo.toml`.
|
||||
#
|
||||
# This manifest is actually used in-tree by rust-lang/rust,
|
||||
# `../builtins-shim/Cargo.toml` is used by out-of-tree testing. See the other
|
||||
# manifest for further details.
|
||||
|
||||
[package]
|
||||
authors = ["Jorge Aparicio <japaricious@gmail.com>"]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.160"
|
||||
license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/rust-lang/compiler-builtins"
|
||||
homepage = "https://github.com/rust-lang/compiler-builtins"
|
||||
documentation = "https://docs.rs/compiler_builtins"
|
||||
edition = "2024"
|
||||
authors = ["Jorge Aparicio <japaricious@gmail.com>"]
|
||||
description = "Compiler intrinsics used by the Rust compiler."
|
||||
repository = "https://github.com/rust-lang/compiler-builtins"
|
||||
license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
links = "compiler-rt"
|
||||
|
||||
[lib]
|
||||
|
|
@ -53,7 +57,3 @@ rustc-dep-of-std = ["compiler-builtins", "dep:core"]
|
|||
# This makes certain traits and function specializations public that
|
||||
# are not normally public but are required by the `builtins-test`
|
||||
unstable-public-internals = []
|
||||
|
||||
[lints.rust]
|
||||
# The cygwin config can be dropped after our benchmark toolchain is bumped
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)', 'cfg(target_os, values("cygwin"))'] }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
mod configure;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use configure::{Target, configure_aliases, configure_f16_f128};
|
||||
|
||||
|
|
@ -86,10 +83,6 @@ fn main() {
|
|||
{
|
||||
println!("cargo:rustc-cfg=kernel_user_helpers")
|
||||
}
|
||||
|
||||
if llvm_target[0].starts_with("aarch64") {
|
||||
generate_aarch64_outlined_atomics();
|
||||
}
|
||||
}
|
||||
|
||||
/// Run configuration for `libm` since it is included directly.
|
||||
|
|
@ -132,61 +125,6 @@ fn configure_libm(target: &Target) {
|
|||
println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\"");
|
||||
}
|
||||
|
||||
fn aarch64_symbol(ordering: Ordering) -> &'static str {
|
||||
match ordering {
|
||||
Ordering::Relaxed => "relax",
|
||||
Ordering::Acquire => "acq",
|
||||
Ordering::Release => "rel",
|
||||
Ordering::AcqRel => "acq_rel",
|
||||
_ => panic!("unknown symbol for {ordering:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items.
|
||||
/// Define them from the build script instead.
|
||||
/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros.
|
||||
fn generate_aarch64_outlined_atomics() {
|
||||
use std::fmt::Write;
|
||||
// #[macro_export] so that we can use this in tests
|
||||
let gen_macro =
|
||||
|name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n");
|
||||
|
||||
// Generate different macros for add/clr/eor/set so that we can test them separately.
|
||||
let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"];
|
||||
let mut macros = BTreeMap::new();
|
||||
for sym in sym_names {
|
||||
macros.insert(sym, gen_macro(sym));
|
||||
}
|
||||
|
||||
// Only CAS supports 16 bytes, and it has a different implementation that uses a different macro.
|
||||
let mut cas16 = gen_macro("cas16");
|
||||
|
||||
for ordering in [
|
||||
Ordering::Relaxed,
|
||||
Ordering::Acquire,
|
||||
Ordering::Release,
|
||||
Ordering::AcqRel,
|
||||
] {
|
||||
let sym_ordering = aarch64_symbol(ordering);
|
||||
for size in [1, 2, 4, 8] {
|
||||
for (sym, macro_) in &mut macros {
|
||||
let name = format!("__aarch64_{sym}{size}_{sym_ordering}");
|
||||
writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap();
|
||||
}
|
||||
}
|
||||
let name = format!("__aarch64_cas16_{sym_ordering}");
|
||||
writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap();
|
||||
}
|
||||
|
||||
let mut buf = String::new();
|
||||
for macro_def in macros.values().chain(std::iter::once(&cas16)) {
|
||||
buf += macro_def;
|
||||
buf += "}; }\n";
|
||||
}
|
||||
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap();
|
||||
}
|
||||
|
||||
/// Emit directives for features we expect to support that aren't in `Cargo.toml`.
|
||||
///
|
||||
/// These are mostly cfg elements emitted by this `build.rs`.
|
||||
|
|
|
|||
|
|
@ -262,8 +262,78 @@ macro_rules! or {
|
|||
};
|
||||
}
|
||||
|
||||
// See `generate_aarch64_outlined_atomics` in build.rs.
|
||||
include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs"));
|
||||
#[macro_export]
|
||||
macro_rules! foreach_ordering {
|
||||
($macro:path, $bytes:tt, $name:ident) => {
|
||||
$macro!( Relaxed, $bytes, ${concat($name, _relax)} );
|
||||
$macro!( Acquire, $bytes, ${concat($name, _acq)} );
|
||||
$macro!( Release, $bytes, ${concat($name, _rel)} );
|
||||
$macro!( AcqRel, $bytes, ${concat($name, _acq_rel)} );
|
||||
};
|
||||
($macro:path, $name:ident) => {
|
||||
$macro!( Relaxed, ${concat($name, _relax)} );
|
||||
$macro!( Acquire, ${concat($name, _acq)} );
|
||||
$macro!( Release, ${concat($name, _rel)} );
|
||||
$macro!( AcqRel, ${concat($name, _acq_rel)} );
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! foreach_bytes {
|
||||
($macro:path, $name:ident) => {
|
||||
foreach_ordering!( $macro, 1, ${concat(__aarch64_, $name, "1")} );
|
||||
foreach_ordering!( $macro, 2, ${concat(__aarch64_, $name, "2")} );
|
||||
foreach_ordering!( $macro, 4, ${concat(__aarch64_, $name, "4")} );
|
||||
foreach_ordering!( $macro, 8, ${concat(__aarch64_, $name, "8")} );
|
||||
};
|
||||
}
|
||||
|
||||
/// Generate different macros for cas/swp/add/clr/eor/set so that we can test them separately.
|
||||
#[macro_export]
|
||||
macro_rules! foreach_cas {
|
||||
($macro:path) => {
|
||||
foreach_bytes!($macro, cas);
|
||||
};
|
||||
}
|
||||
|
||||
/// Only CAS supports 16 bytes, and it has a different implementation that uses a different macro.
|
||||
#[macro_export]
|
||||
macro_rules! foreach_cas16 {
|
||||
($macro:path) => {
|
||||
foreach_ordering!($macro, __aarch64_cas16);
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! foreach_swp {
|
||||
($macro:path) => {
|
||||
foreach_bytes!($macro, swp);
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! foreach_ldadd {
|
||||
($macro:path) => {
|
||||
foreach_bytes!($macro, ldadd);
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! foreach_ldclr {
|
||||
($macro:path) => {
|
||||
foreach_bytes!($macro, ldclr);
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! foreach_ldeor {
|
||||
($macro:path) => {
|
||||
foreach_bytes!($macro, ldeor);
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! foreach_ldset {
|
||||
($macro:path) => {
|
||||
foreach_bytes!($macro, ldset);
|
||||
};
|
||||
}
|
||||
|
||||
foreach_cas!(compare_and_swap);
|
||||
foreach_cas16!(compare_and_swap_i128);
|
||||
foreach_swp!(swap);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#![feature(linkage)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(macro_metavar_expr_concat)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(f16_enabled, feature(f16))]
|
||||
#![cfg_attr(f128_enabled, feature(f128))]
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
[package]
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
categories = ["no-std"]
|
||||
description = "libm in pure Rust"
|
||||
documentation = "https://docs.rs/libm"
|
||||
keywords = ["libm", "math"]
|
||||
license = "MIT"
|
||||
name = "libm"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/rust-lang/compiler-builtins"
|
||||
version = "0.2.15"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
description = "libm in pure Rust"
|
||||
categories = ["no-std"]
|
||||
keywords = ["libm", "math"]
|
||||
repository = "https://github.com/rust-lang/compiler-builtins"
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
rust-version = "1.63"
|
||||
|
||||
|
|
|
|||
|
|
@ -82,22 +82,77 @@ mod tests {
|
|||
fn fmin_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
|
||||
let cases = [
|
||||
(F::ZERO, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ZERO, F::ONE, F::ZERO),
|
||||
(F::ONE, F::ZERO, F::ZERO),
|
||||
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
|
||||
(F::INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::ZERO, F::INFINITY, F::ZERO),
|
||||
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::ZERO, F::NAN, F::ZERO),
|
||||
(F::ZERO, F::NEG_NAN, F::ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
|
||||
(F::ONE, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::ONE, F::INFINITY, F::ONE),
|
||||
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::ONE, F::NAN, F::ONE),
|
||||
(F::ONE, F::NEG_NAN, F::ONE),
|
||||
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_ONE, F::NAN, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
|
||||
(F::INFINITY, F::ZERO, F::ZERO),
|
||||
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::INFINITY, F::ONE, F::ONE),
|
||||
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::INFINITY, F::NAN, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_NAN, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NAN, F::ONE, F::ONE),
|
||||
(F::NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::NEG_NAN, F::ZERO, F::ZERO),
|
||||
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_NAN, F::ONE, F::ONE),
|
||||
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
];
|
||||
|
||||
for (x, y, res) in cases {
|
||||
let val = f(x, y);
|
||||
assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y));
|
||||
}
|
||||
|
||||
// Ordering between zeros and NaNs does not matter
|
||||
assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO);
|
||||
assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
|
||||
assert!(f(F::NAN, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -125,22 +180,77 @@ mod tests {
|
|||
fn fmax_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
|
||||
let cases = [
|
||||
(F::ZERO, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ZERO, F::ONE, F::ONE),
|
||||
(F::ONE, F::ZERO, F::ONE),
|
||||
(F::ZERO, F::NEG_ONE, F::ZERO),
|
||||
(F::NEG_ONE, F::ZERO, F::ZERO),
|
||||
(F::INFINITY, F::ZERO, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::ZERO, F::INFINITY, F::INFINITY),
|
||||
(F::ZERO, F::NEG_INFINITY, F::ZERO),
|
||||
(F::ZERO, F::NAN, F::ZERO),
|
||||
(F::ZERO, F::NEG_NAN, F::ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::ONE, F::ONE),
|
||||
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
|
||||
(F::ONE, F::ZERO, F::ONE),
|
||||
(F::ONE, F::NEG_ZERO, F::ONE),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ONE, F::NEG_ONE, F::ONE),
|
||||
(F::ONE, F::INFINITY, F::INFINITY),
|
||||
(F::ONE, F::NEG_INFINITY, F::ONE),
|
||||
(F::ONE, F::NAN, F::ONE),
|
||||
(F::ONE, F::NEG_NAN, F::ONE),
|
||||
(F::NEG_ONE, F::ZERO, F::ZERO),
|
||||
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ONE, F::ONE, F::ONE),
|
||||
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NAN, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
|
||||
(F::INFINITY, F::ZERO, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
|
||||
(F::INFINITY, F::ONE, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_ONE, F::INFINITY),
|
||||
(F::INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NAN, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_NAN, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_INFINITY, F::ONE, F::ONE),
|
||||
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NAN, F::ONE, F::ONE),
|
||||
(F::NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::NEG_NAN, F::ZERO, F::ZERO),
|
||||
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_NAN, F::ONE, F::ONE),
|
||||
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
];
|
||||
|
||||
for (x, y, res) in cases {
|
||||
let val = f(x, y);
|
||||
assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y));
|
||||
}
|
||||
|
||||
// Ordering between zeros and NaNs does not matter
|
||||
assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO);
|
||||
assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
|
||||
assert!(f(F::NAN, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -74,24 +74,77 @@ mod tests {
|
|||
fn fminimum_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
|
||||
let cases = [
|
||||
(F::ZERO, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ZERO, F::ONE, F::ZERO),
|
||||
(F::ONE, F::ZERO, F::ZERO),
|
||||
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
|
||||
(F::INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
|
||||
(F::NAN, F::ZERO, F::NAN),
|
||||
(F::ZERO, F::NAN, F::NAN),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::ZERO, F::ONE, F::ZERO),
|
||||
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::ZERO, F::INFINITY, F::ZERO),
|
||||
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::ZERO, F::NAN, F::NAN),
|
||||
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_ZERO, F::NAN, F::NAN),
|
||||
(F::ONE, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::ONE, F::INFINITY, F::ONE),
|
||||
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::ONE, F::NAN, F::NAN),
|
||||
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_ONE, F::NAN, F::NAN),
|
||||
(F::INFINITY, F::ZERO, F::ZERO),
|
||||
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::INFINITY, F::ONE, F::ONE),
|
||||
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::INFINITY, F::NAN, F::NAN),
|
||||
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NAN, F::NAN),
|
||||
(F::NAN, F::ZERO, F::NAN),
|
||||
(F::NAN, F::NEG_ZERO, F::NAN),
|
||||
(F::NAN, F::ONE, F::NAN),
|
||||
(F::NAN, F::NEG_ONE, F::NAN),
|
||||
(F::NAN, F::INFINITY, F::NAN),
|
||||
(F::NAN, F::NEG_INFINITY, F::NAN),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
];
|
||||
|
||||
for (x, y, res) in cases {
|
||||
let val = f(x, y);
|
||||
assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y));
|
||||
}
|
||||
|
||||
// Ordering between NaNs does not matter
|
||||
assert!(f(F::NAN, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NAN).is_nan());
|
||||
assert!(f(F::ZERO, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::ONE, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::INFINITY, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::ZERO).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::ONE).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::INFINITY).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -119,24 +172,77 @@ mod tests {
|
|||
fn fmaximum_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
|
||||
let cases = [
|
||||
(F::ZERO, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ZERO, F::ONE, F::ONE),
|
||||
(F::ONE, F::ZERO, F::ONE),
|
||||
(F::ZERO, F::NEG_ONE, F::ZERO),
|
||||
(F::NEG_ONE, F::ZERO, F::ZERO),
|
||||
(F::INFINITY, F::ZERO, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NAN, F::ZERO, F::NAN),
|
||||
(F::ZERO, F::NAN, F::NAN),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::ZERO, F::NEG_ZERO, F::ZERO),
|
||||
(F::ZERO, F::ONE, F::ONE),
|
||||
(F::ZERO, F::NEG_ONE, F::ZERO),
|
||||
(F::ZERO, F::INFINITY, F::INFINITY),
|
||||
(F::ZERO, F::NEG_INFINITY, F::ZERO),
|
||||
(F::ZERO, F::NAN, F::NAN),
|
||||
(F::NEG_ZERO, F::ZERO, F::ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::ONE, F::ONE),
|
||||
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NAN, F::NAN),
|
||||
(F::ONE, F::ZERO, F::ONE),
|
||||
(F::ONE, F::NEG_ZERO, F::ONE),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ONE, F::NEG_ONE, F::ONE),
|
||||
(F::ONE, F::INFINITY, F::INFINITY),
|
||||
(F::ONE, F::NEG_INFINITY, F::ONE),
|
||||
(F::ONE, F::NAN, F::NAN),
|
||||
(F::NEG_ONE, F::ZERO, F::ZERO),
|
||||
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ONE, F::ONE, F::ONE),
|
||||
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NAN, F::NAN),
|
||||
(F::INFINITY, F::ZERO, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
|
||||
(F::INFINITY, F::ONE, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_ONE, F::INFINITY),
|
||||
(F::INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NAN, F::NAN),
|
||||
(F::NEG_INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_INFINITY, F::ONE, F::ONE),
|
||||
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NAN, F::NAN),
|
||||
(F::NAN, F::ZERO, F::NAN),
|
||||
(F::NAN, F::NEG_ZERO, F::NAN),
|
||||
(F::NAN, F::ONE, F::NAN),
|
||||
(F::NAN, F::NEG_ONE, F::NAN),
|
||||
(F::NAN, F::INFINITY, F::NAN),
|
||||
(F::NAN, F::NEG_INFINITY, F::NAN),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
];
|
||||
|
||||
for (x, y, res) in cases {
|
||||
let val = f(x, y);
|
||||
assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y));
|
||||
}
|
||||
|
||||
// Ordering between NaNs does not matter
|
||||
assert!(f(F::NAN, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NAN).is_nan());
|
||||
assert!(f(F::ZERO, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::ONE, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::INFINITY, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::ZERO).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::ONE).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::INFINITY).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -74,24 +74,77 @@ mod tests {
|
|||
fn fminimum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
|
||||
let cases = [
|
||||
(F::ZERO, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ZERO, F::ONE, F::ZERO),
|
||||
(F::ONE, F::ZERO, F::ZERO),
|
||||
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
|
||||
(F::INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::ZERO, F::NAN, F::ZERO),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::ZERO, F::ONE, F::ZERO),
|
||||
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::ZERO, F::INFINITY, F::ZERO),
|
||||
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::ZERO, F::NAN, F::ZERO),
|
||||
(F::ZERO, F::NEG_NAN, F::ZERO),
|
||||
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
|
||||
(F::ONE, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::ONE, F::INFINITY, F::ONE),
|
||||
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::ONE, F::NAN, F::ONE),
|
||||
(F::ONE, F::NEG_NAN, F::ONE),
|
||||
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_ONE, F::NAN, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
|
||||
(F::INFINITY, F::ZERO, F::ZERO),
|
||||
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::INFINITY, F::ONE, F::ONE),
|
||||
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::INFINITY, F::NAN, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_NAN, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NAN, F::ONE, F::ONE),
|
||||
(F::NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::NEG_NAN, F::ZERO, F::ZERO),
|
||||
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_NAN, F::ONE, F::ONE),
|
||||
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
];
|
||||
|
||||
for (x, y, res) in cases {
|
||||
let val = f(x, y);
|
||||
assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y));
|
||||
for (x, y, expected) in cases {
|
||||
let actual = f(x, y);
|
||||
assert_biteq!(actual, expected, "fminimum_num({}, {})", Hexf(x), Hexf(y));
|
||||
}
|
||||
|
||||
// Ordering between NaNs does not matter
|
||||
assert!(f(F::NAN, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -119,24 +172,77 @@ mod tests {
|
|||
fn fmaximum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
|
||||
let cases = [
|
||||
(F::ZERO, F::ZERO, F::ZERO),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ZERO, F::ONE, F::ONE),
|
||||
(F::ONE, F::ZERO, F::ONE),
|
||||
(F::ZERO, F::NEG_ONE, F::ZERO),
|
||||
(F::NEG_ONE, F::ZERO, F::ZERO),
|
||||
(F::INFINITY, F::ZERO, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::ZERO, F::NAN, F::ZERO),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::ZERO, F::NEG_ZERO, F::ZERO),
|
||||
(F::ZERO, F::ONE, F::ONE),
|
||||
(F::ZERO, F::NEG_ONE, F::ZERO),
|
||||
(F::ZERO, F::INFINITY, F::INFINITY),
|
||||
(F::ZERO, F::NEG_INFINITY, F::ZERO),
|
||||
(F::ZERO, F::NAN, F::ZERO),
|
||||
(F::ZERO, F::NEG_NAN, F::ZERO),
|
||||
(F::NEG_ZERO, F::ZERO, F::ZERO),
|
||||
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::ONE, F::ONE),
|
||||
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
|
||||
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
|
||||
(F::ONE, F::ZERO, F::ONE),
|
||||
(F::ONE, F::NEG_ZERO, F::ONE),
|
||||
(F::ONE, F::ONE, F::ONE),
|
||||
(F::ONE, F::NEG_ONE, F::ONE),
|
||||
(F::ONE, F::INFINITY, F::INFINITY),
|
||||
(F::ONE, F::NEG_INFINITY, F::ONE),
|
||||
(F::ONE, F::NAN, F::ONE),
|
||||
(F::ONE, F::NEG_NAN, F::ONE),
|
||||
(F::NEG_ONE, F::ZERO, F::ZERO),
|
||||
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_ONE, F::ONE, F::ONE),
|
||||
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NAN, F::NEG_ONE),
|
||||
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
|
||||
(F::INFINITY, F::ZERO, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
|
||||
(F::INFINITY, F::ONE, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_ONE, F::INFINITY),
|
||||
(F::INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
|
||||
(F::INFINITY, F::NAN, F::INFINITY),
|
||||
(F::INFINITY, F::NEG_NAN, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::ZERO, F::ZERO),
|
||||
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_INFINITY, F::ONE, F::ONE),
|
||||
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
|
||||
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
|
||||
(F::NAN, F::ZERO, F::ZERO),
|
||||
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NAN, F::ONE, F::ONE),
|
||||
(F::NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
(F::NAN, F::NAN, F::NAN),
|
||||
(F::NEG_NAN, F::ZERO, F::ZERO),
|
||||
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
|
||||
(F::NEG_NAN, F::ONE, F::ONE),
|
||||
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
|
||||
(F::NEG_NAN, F::INFINITY, F::INFINITY),
|
||||
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
|
||||
];
|
||||
|
||||
for (x, y, res) in cases {
|
||||
let val = f(x, y);
|
||||
assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y));
|
||||
for (x, y, expected) in cases {
|
||||
let actual = f(x, y);
|
||||
assert_biteq!(actual, expected, "fmaximum_num({}, {})", Hexf(x), Hexf(y));
|
||||
}
|
||||
|
||||
// Ordering between NaNs does not matter
|
||||
assert!(f(F::NAN, F::NEG_NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NAN).is_nan());
|
||||
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -19,6 +19,5 @@ use crate::support::Float;
|
|||
#[inline]
|
||||
pub fn fmax<F: Float>(x: F, y: F) -> F {
|
||||
let res = if x.is_nan() || x < y { y } else { x };
|
||||
// Canonicalize
|
||||
res * F::ONE
|
||||
res.canonicalize()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
//! Per the spec, returns the canonicalized result of:
|
||||
//! - `x` if `x > y`
|
||||
//! - `y` if `y > x`
|
||||
//! - +0.0 if x and y are zero with opposite signs
|
||||
//! - qNaN if either operation is NaN
|
||||
//! - Logic following +0.0 > -0.0
|
||||
//!
|
||||
//! Excluded from our implementation is sNaN handling.
|
||||
|
||||
|
|
@ -23,6 +23,5 @@ pub fn fmaximum<F: Float>(x: F, y: F) -> F {
|
|||
y
|
||||
};
|
||||
|
||||
// Canonicalize
|
||||
res * F::ONE
|
||||
res.canonicalize()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
//! Per the spec, returns:
|
||||
//! - `x` if `x > y`
|
||||
//! - `y` if `y > x`
|
||||
//! - Non-NaN if one operand is NaN
|
||||
//! - Logic following +0.0 > -0.0
|
||||
//! - +0.0 if x and y are zero with opposite signs
|
||||
//! - Either `x` or `y` if `x == y` and the signs are the same
|
||||
//! - qNaN if either operand is a NaN
|
||||
//! - Non-NaN if one operand is NaN
|
||||
//! - qNaN if both operands are NaNx
|
||||
//!
|
||||
//! Excluded from our implementation is sNaN handling.
|
||||
|
||||
|
|
@ -15,12 +15,15 @@ use crate::support::Float;
|
|||
|
||||
#[inline]
|
||||
pub fn fmaximum_num<F: Float>(x: F, y: F) -> F {
|
||||
let res = if x.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) {
|
||||
y
|
||||
} else {
|
||||
let res = if x > y || y.is_nan() {
|
||||
x
|
||||
} else if y > x || x.is_nan() {
|
||||
y
|
||||
} else if x.is_sign_positive() {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
};
|
||||
|
||||
// Canonicalize
|
||||
res * F::ONE
|
||||
res.canonicalize()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,5 @@ use crate::support::Float;
|
|||
#[inline]
|
||||
pub fn fmin<F: Float>(x: F, y: F) -> F {
|
||||
let res = if y.is_nan() || x < y { x } else { y };
|
||||
// Canonicalize
|
||||
res * F::ONE
|
||||
res.canonicalize()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
//! Per the spec, returns the canonicalized result of:
|
||||
//! - `x` if `x < y`
|
||||
//! - `y` if `y < x`
|
||||
//! - -0.0 if x and y are zero with opposite signs
|
||||
//! - qNaN if either operation is NaN
|
||||
//! - Logic following +0.0 > -0.0
|
||||
//!
|
||||
//! Excluded from our implementation is sNaN handling.
|
||||
|
||||
|
|
@ -23,6 +23,5 @@ pub fn fminimum<F: Float>(x: F, y: F) -> F {
|
|||
y
|
||||
};
|
||||
|
||||
// Canonicalize
|
||||
res * F::ONE
|
||||
res.canonicalize()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
//! Per the spec, returns:
|
||||
//! - `x` if `x < y`
|
||||
//! - `y` if `y < x`
|
||||
//! - Non-NaN if one operand is NaN
|
||||
//! - Logic following +0.0 > -0.0
|
||||
//! - -0.0 if x and y are zero with opposite signs
|
||||
//! - Either `x` or `y` if `x == y` and the signs are the same
|
||||
//! - qNaN if either operand is a NaN
|
||||
//! - Non-NaN if one operand is NaN
|
||||
//! - qNaN if both operands are NaNx
|
||||
//!
|
||||
//! Excluded from our implementation is sNaN handling.
|
||||
|
||||
|
|
@ -15,12 +15,15 @@ use crate::support::Float;
|
|||
|
||||
#[inline]
|
||||
pub fn fminimum_num<F: Float>(x: F, y: F) -> F {
|
||||
let res = if y.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) {
|
||||
x
|
||||
} else {
|
||||
let res = if x > y || x.is_nan() {
|
||||
y
|
||||
} else if y > x || y.is_nan() {
|
||||
x
|
||||
} else if x.is_sign_positive() {
|
||||
y
|
||||
} else {
|
||||
x
|
||||
};
|
||||
|
||||
// Canonicalize
|
||||
res * F::ONE
|
||||
res.canonicalize()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,6 +190,15 @@ pub trait Float:
|
|||
Self::ONE.copysign(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a best-effort attempt to canonicalize the number. Note that this is allowed
|
||||
/// to be a nop and does not always quiet sNaNs.
|
||||
fn canonicalize(self) -> Self {
|
||||
// FIXME: LLVM often removes this. We should determine whether we can remove the operation,
|
||||
// or switch to something based on `llvm.canonicalize` (which has crashes,
|
||||
// <https://github.com/llvm/llvm-project/issues/32650>).
|
||||
self * Self::ONE
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types).
|
||||
|
|
|
|||
|
|
@ -143,10 +143,12 @@ macro_rules! assert_biteq {
|
|||
let bits = $crate::support::Int::leading_zeros(l.to_bits() - l.to_bits());
|
||||
assert!(
|
||||
$crate::support::Float::biteq(l, r),
|
||||
"{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})",
|
||||
"{}\nl: {l:?} ({lb:#0width$x} {lh})\nr: {r:?} ({rb:#0width$x} {rh})",
|
||||
format_args!($($tt)*),
|
||||
lb = l.to_bits(),
|
||||
lh = $crate::support::Hexf(l),
|
||||
rb = r.to_bits(),
|
||||
rh = $crate::support::Hexf(r),
|
||||
width = ((bits / 4) + 2) as usize,
|
||||
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
df8102fe5f24f28a918660b0cd918d7331c3896e
|
||||
d087f112b7d1323446c7b39a8b616aee7fa56b3d
|
||||
|
|
|
|||
|
|
@ -149,8 +149,32 @@ pub const fn forget<T>(t: T) {
|
|||
|
||||
/// Like [`forget`], but also accepts unsized values.
|
||||
///
|
||||
/// This function is just a shim intended to be removed when the `unsized_locals` feature gets
|
||||
/// stabilized.
|
||||
/// While Rust does not permit unsized locals since its removal in [#111942] it is
|
||||
/// still possible to call functions with unsized values from a function argument
|
||||
/// or in-place construction.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(unsized_fn_params, forget_unsized)]
|
||||
/// #![allow(internal_features)]
|
||||
///
|
||||
/// use std::mem::forget_unsized;
|
||||
///
|
||||
/// pub fn in_place() {
|
||||
/// forget_unsized(*Box::<str>::from("str"));
|
||||
/// }
|
||||
///
|
||||
/// pub fn param(x: str) {
|
||||
/// forget_unsized(x);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This works because the compiler will alter these functions to pass the parameter
|
||||
/// by reference instead. This trick is necessary to support `Box<dyn FnOnce()>: FnOnce()`.
|
||||
/// See [#68304] and [#71170] for more information.
|
||||
///
|
||||
/// [#111942]: https://github.com/rust-lang/rust/issues/111942
|
||||
/// [#68304]: https://github.com/rust-lang/rust/issues/68304
|
||||
/// [#71170]: https://github.com/rust-lang/rust/pull/71170
|
||||
#[inline]
|
||||
#[unstable(feature = "forget_unsized", issue = "none")]
|
||||
pub fn forget_unsized<T: ?Sized>(t: T) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ use core::ops::{Add, Div, Mul, Sub};
|
|||
use std::f128::consts;
|
||||
use std::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
// Note these tolerances make sense around zero, but not for more extreme exponents.
|
||||
|
||||
/// Default tolerances. Works for values that should be near precise but not exact. Roughly
|
||||
|
|
@ -53,34 +55,6 @@ fn test_num_f128() {
|
|||
// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
|
||||
// the intrinsics.
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_min_nan() {
|
||||
assert_biteq!(f128::NAN.min(2.0), 2.0);
|
||||
assert_biteq!(2.0f128.min(f128::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_max_nan() {
|
||||
assert_biteq!(f128::NAN.max(2.0), 2.0);
|
||||
assert_biteq!(2.0f128.max(f128::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_minimum() {
|
||||
assert!(f128::NAN.minimum(2.0).is_nan());
|
||||
assert!(2.0f128.minimum(f128::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_maximum() {
|
||||
assert!(f128::NAN.maximum(2.0).is_nan());
|
||||
assert!(2.0f128.maximum(f128::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan() {
|
||||
let nan: f128 = f128::NAN;
|
||||
|
|
@ -232,98 +206,6 @@ fn test_classify() {
|
|||
assert_eq!(1e-4932f128.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_has_reliable_f128_math)]
|
||||
fn test_floor() {
|
||||
assert_biteq!(1.0f128.floor(), 1.0f128);
|
||||
assert_biteq!(1.3f128.floor(), 1.0f128);
|
||||
assert_biteq!(1.5f128.floor(), 1.0f128);
|
||||
assert_biteq!(1.7f128.floor(), 1.0f128);
|
||||
assert_biteq!(0.0f128.floor(), 0.0f128);
|
||||
assert_biteq!((-0.0f128).floor(), -0.0f128);
|
||||
assert_biteq!((-1.0f128).floor(), -1.0f128);
|
||||
assert_biteq!((-1.3f128).floor(), -2.0f128);
|
||||
assert_biteq!((-1.5f128).floor(), -2.0f128);
|
||||
assert_biteq!((-1.7f128).floor(), -2.0f128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_ceil() {
|
||||
assert_biteq!(1.0f128.ceil(), 1.0f128);
|
||||
assert_biteq!(1.3f128.ceil(), 2.0f128);
|
||||
assert_biteq!(1.5f128.ceil(), 2.0f128);
|
||||
assert_biteq!(1.7f128.ceil(), 2.0f128);
|
||||
assert_biteq!(0.0f128.ceil(), 0.0f128);
|
||||
assert_biteq!((-0.0f128).ceil(), -0.0f128);
|
||||
assert_biteq!((-1.0f128).ceil(), -1.0f128);
|
||||
assert_biteq!((-1.3f128).ceil(), -1.0f128);
|
||||
assert_biteq!((-1.5f128).ceil(), -1.0f128);
|
||||
assert_biteq!((-1.7f128).ceil(), -1.0f128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_round() {
|
||||
assert_biteq!(2.5f128.round(), 3.0f128);
|
||||
assert_biteq!(1.0f128.round(), 1.0f128);
|
||||
assert_biteq!(1.3f128.round(), 1.0f128);
|
||||
assert_biteq!(1.5f128.round(), 2.0f128);
|
||||
assert_biteq!(1.7f128.round(), 2.0f128);
|
||||
assert_biteq!(0.0f128.round(), 0.0f128);
|
||||
assert_biteq!((-0.0f128).round(), -0.0f128);
|
||||
assert_biteq!((-1.0f128).round(), -1.0f128);
|
||||
assert_biteq!((-1.3f128).round(), -1.0f128);
|
||||
assert_biteq!((-1.5f128).round(), -2.0f128);
|
||||
assert_biteq!((-1.7f128).round(), -2.0f128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_round_ties_even() {
|
||||
assert_biteq!(2.5f128.round_ties_even(), 2.0f128);
|
||||
assert_biteq!(1.0f128.round_ties_even(), 1.0f128);
|
||||
assert_biteq!(1.3f128.round_ties_even(), 1.0f128);
|
||||
assert_biteq!(1.5f128.round_ties_even(), 2.0f128);
|
||||
assert_biteq!(1.7f128.round_ties_even(), 2.0f128);
|
||||
assert_biteq!(0.0f128.round_ties_even(), 0.0f128);
|
||||
assert_biteq!((-0.0f128).round_ties_even(), -0.0f128);
|
||||
assert_biteq!((-1.0f128).round_ties_even(), -1.0f128);
|
||||
assert_biteq!((-1.3f128).round_ties_even(), -1.0f128);
|
||||
assert_biteq!((-1.5f128).round_ties_even(), -2.0f128);
|
||||
assert_biteq!((-1.7f128).round_ties_even(), -2.0f128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_trunc() {
|
||||
assert_biteq!(1.0f128.trunc(), 1.0f128);
|
||||
assert_biteq!(1.3f128.trunc(), 1.0f128);
|
||||
assert_biteq!(1.5f128.trunc(), 1.0f128);
|
||||
assert_biteq!(1.7f128.trunc(), 1.0f128);
|
||||
assert_biteq!(0.0f128.trunc(), 0.0f128);
|
||||
assert_biteq!((-0.0f128).trunc(), -0.0f128);
|
||||
assert_biteq!((-1.0f128).trunc(), -1.0f128);
|
||||
assert_biteq!((-1.3f128).trunc(), -1.0f128);
|
||||
assert_biteq!((-1.5f128).trunc(), -1.0f128);
|
||||
assert_biteq!((-1.7f128).trunc(), -1.0f128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_fract() {
|
||||
assert_biteq!(1.0f128.fract(), 0.0f128);
|
||||
assert_biteq!(1.3f128.fract(), 0.300000000000000000000000000000000039f128);
|
||||
assert_biteq!(1.5f128.fract(), 0.5f128);
|
||||
assert_biteq!(1.7f128.fract(), 0.7f128);
|
||||
assert_biteq!(0.0f128.fract(), 0.0f128);
|
||||
assert_biteq!((-0.0f128).fract(), 0.0f128);
|
||||
assert_biteq!((-1.0f128).fract(), 0.0f128);
|
||||
assert_biteq!((-1.3f128).fract(), -0.300000000000000000000000000000000039f128);
|
||||
assert_biteq!((-1.5f128).fract(), -0.5f128);
|
||||
assert_biteq!((-1.7f128).fract(), -0.699999999999999999999999999999999961f128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_abs() {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
use std::f16::consts;
|
||||
use std::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
/// Tolerance for results on the order of 10.0e-2
|
||||
#[allow(unused)]
|
||||
const TOL_N2: f16 = 0.0001;
|
||||
|
|
@ -49,34 +51,6 @@ fn test_num_f16() {
|
|||
// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
|
||||
// the intrinsics.
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_min_nan() {
|
||||
assert_biteq!(f16::NAN.min(2.0), 2.0);
|
||||
assert_biteq!(2.0f16.min(f16::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_max_nan() {
|
||||
assert_biteq!(f16::NAN.max(2.0), 2.0);
|
||||
assert_biteq!(2.0f16.max(f16::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_minimum() {
|
||||
assert!(f16::NAN.minimum(2.0).is_nan());
|
||||
assert!(2.0f16.minimum(f16::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_maximum() {
|
||||
assert!(f16::NAN.maximum(2.0).is_nan());
|
||||
assert!(2.0f16.maximum(f16::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan() {
|
||||
let nan: f16 = f16::NAN;
|
||||
|
|
@ -228,98 +202,6 @@ fn test_classify() {
|
|||
assert_eq!(1e-5f16.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_floor() {
|
||||
assert_biteq!(1.0f16.floor(), 1.0f16);
|
||||
assert_biteq!(1.3f16.floor(), 1.0f16);
|
||||
assert_biteq!(1.5f16.floor(), 1.0f16);
|
||||
assert_biteq!(1.7f16.floor(), 1.0f16);
|
||||
assert_biteq!(0.0f16.floor(), 0.0f16);
|
||||
assert_biteq!((-0.0f16).floor(), -0.0f16);
|
||||
assert_biteq!((-1.0f16).floor(), -1.0f16);
|
||||
assert_biteq!((-1.3f16).floor(), -2.0f16);
|
||||
assert_biteq!((-1.5f16).floor(), -2.0f16);
|
||||
assert_biteq!((-1.7f16).floor(), -2.0f16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_ceil() {
|
||||
assert_biteq!(1.0f16.ceil(), 1.0f16);
|
||||
assert_biteq!(1.3f16.ceil(), 2.0f16);
|
||||
assert_biteq!(1.5f16.ceil(), 2.0f16);
|
||||
assert_biteq!(1.7f16.ceil(), 2.0f16);
|
||||
assert_biteq!(0.0f16.ceil(), 0.0f16);
|
||||
assert_biteq!((-0.0f16).ceil(), -0.0f16);
|
||||
assert_biteq!((-1.0f16).ceil(), -1.0f16);
|
||||
assert_biteq!((-1.3f16).ceil(), -1.0f16);
|
||||
assert_biteq!((-1.5f16).ceil(), -1.0f16);
|
||||
assert_biteq!((-1.7f16).ceil(), -1.0f16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_round() {
|
||||
assert_biteq!(2.5f16.round(), 3.0f16);
|
||||
assert_biteq!(1.0f16.round(), 1.0f16);
|
||||
assert_biteq!(1.3f16.round(), 1.0f16);
|
||||
assert_biteq!(1.5f16.round(), 2.0f16);
|
||||
assert_biteq!(1.7f16.round(), 2.0f16);
|
||||
assert_biteq!(0.0f16.round(), 0.0f16);
|
||||
assert_biteq!((-0.0f16).round(), -0.0f16);
|
||||
assert_biteq!((-1.0f16).round(), -1.0f16);
|
||||
assert_biteq!((-1.3f16).round(), -1.0f16);
|
||||
assert_biteq!((-1.5f16).round(), -2.0f16);
|
||||
assert_biteq!((-1.7f16).round(), -2.0f16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_round_ties_even() {
|
||||
assert_biteq!(2.5f16.round_ties_even(), 2.0f16);
|
||||
assert_biteq!(1.0f16.round_ties_even(), 1.0f16);
|
||||
assert_biteq!(1.3f16.round_ties_even(), 1.0f16);
|
||||
assert_biteq!(1.5f16.round_ties_even(), 2.0f16);
|
||||
assert_biteq!(1.7f16.round_ties_even(), 2.0f16);
|
||||
assert_biteq!(0.0f16.round_ties_even(), 0.0f16);
|
||||
assert_biteq!((-0.0f16).round_ties_even(), -0.0f16);
|
||||
assert_biteq!((-1.0f16).round_ties_even(), -1.0f16);
|
||||
assert_biteq!((-1.3f16).round_ties_even(), -1.0f16);
|
||||
assert_biteq!((-1.5f16).round_ties_even(), -2.0f16);
|
||||
assert_biteq!((-1.7f16).round_ties_even(), -2.0f16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_trunc() {
|
||||
assert_biteq!(1.0f16.trunc(), 1.0f16);
|
||||
assert_biteq!(1.3f16.trunc(), 1.0f16);
|
||||
assert_biteq!(1.5f16.trunc(), 1.0f16);
|
||||
assert_biteq!(1.7f16.trunc(), 1.0f16);
|
||||
assert_biteq!(0.0f16.trunc(), 0.0f16);
|
||||
assert_biteq!((-0.0f16).trunc(), -0.0f16);
|
||||
assert_biteq!((-1.0f16).trunc(), -1.0f16);
|
||||
assert_biteq!((-1.3f16).trunc(), -1.0f16);
|
||||
assert_biteq!((-1.5f16).trunc(), -1.0f16);
|
||||
assert_biteq!((-1.7f16).trunc(), -1.0f16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_fract() {
|
||||
assert_biteq!(1.0f16.fract(), 0.0f16);
|
||||
assert_biteq!(1.3f16.fract(), 0.2998f16);
|
||||
assert_biteq!(1.5f16.fract(), 0.5f16);
|
||||
assert_biteq!(1.7f16.fract(), 0.7f16);
|
||||
assert_biteq!(0.0f16.fract(), 0.0f16);
|
||||
assert_biteq!((-0.0f16).fract(), 0.0f16);
|
||||
assert_biteq!((-1.0f16).fract(), 0.0f16);
|
||||
assert_biteq!((-1.3f16).fract(), -0.2998f16);
|
||||
assert_biteq!((-1.5f16).fract(), -0.5f16);
|
||||
assert_biteq!((-1.7f16).fract(), -0.7f16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_abs() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use core::f32;
|
|||
use core::f32::consts;
|
||||
use core::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
/// Smallest number
|
||||
const TINY_BITS: u32 = 0x1;
|
||||
|
||||
|
|
@ -33,30 +35,6 @@ fn test_num_f32() {
|
|||
super::test_num(10f32, 2f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_nan() {
|
||||
assert_biteq!(f32::NAN.min(2.0), 2.0);
|
||||
assert_biteq!(2.0f32.min(f32::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_nan() {
|
||||
assert_biteq!(f32::NAN.max(2.0), 2.0);
|
||||
assert_biteq!(2.0f32.max(f32::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_minimum() {
|
||||
assert!(f32::NAN.minimum(2.0).is_nan());
|
||||
assert!(2.0f32.minimum(f32::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_maximum() {
|
||||
assert!(f32::NAN.maximum(2.0).is_nan());
|
||||
assert!(2.0f32.maximum(f32::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan() {
|
||||
let nan: f32 = f32::NAN;
|
||||
|
|
@ -208,92 +186,6 @@ fn test_classify() {
|
|||
assert_eq!(1e-38f32.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_floor() {
|
||||
assert_biteq!(f32::math::floor(1.0f32), 1.0f32);
|
||||
assert_biteq!(f32::math::floor(1.3f32), 1.0f32);
|
||||
assert_biteq!(f32::math::floor(1.5f32), 1.0f32);
|
||||
assert_biteq!(f32::math::floor(1.7f32), 1.0f32);
|
||||
assert_biteq!(f32::math::floor(0.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::floor(-0.0f32), -0.0f32);
|
||||
assert_biteq!(f32::math::floor(-1.0f32), -1.0f32);
|
||||
assert_biteq!(f32::math::floor(-1.3f32), -2.0f32);
|
||||
assert_biteq!(f32::math::floor(-1.5f32), -2.0f32);
|
||||
assert_biteq!(f32::math::floor(-1.7f32), -2.0f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ceil() {
|
||||
assert_biteq!(f32::math::ceil(1.0f32), 1.0f32);
|
||||
assert_biteq!(f32::math::ceil(1.3f32), 2.0f32);
|
||||
assert_biteq!(f32::math::ceil(1.5f32), 2.0f32);
|
||||
assert_biteq!(f32::math::ceil(1.7f32), 2.0f32);
|
||||
assert_biteq!(f32::math::ceil(0.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::ceil(-0.0f32), -0.0f32);
|
||||
assert_biteq!(f32::math::ceil(-1.0f32), -1.0f32);
|
||||
assert_biteq!(f32::math::ceil(-1.3f32), -1.0f32);
|
||||
assert_biteq!(f32::math::ceil(-1.5f32), -1.0f32);
|
||||
assert_biteq!(f32::math::ceil(-1.7f32), -1.0f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round() {
|
||||
assert_biteq!(f32::math::round(2.5f32), 3.0f32);
|
||||
assert_biteq!(f32::math::round(1.0f32), 1.0f32);
|
||||
assert_biteq!(f32::math::round(1.3f32), 1.0f32);
|
||||
assert_biteq!(f32::math::round(1.5f32), 2.0f32);
|
||||
assert_biteq!(f32::math::round(1.7f32), 2.0f32);
|
||||
assert_biteq!(f32::math::round(0.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::round(-0.0f32), -0.0f32);
|
||||
assert_biteq!(f32::math::round(-1.0f32), -1.0f32);
|
||||
assert_biteq!(f32::math::round(-1.3f32), -1.0f32);
|
||||
assert_biteq!(f32::math::round(-1.5f32), -2.0f32);
|
||||
assert_biteq!(f32::math::round(-1.7f32), -2.0f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_ties_even() {
|
||||
assert_biteq!(f32::math::round_ties_even(2.5f32), 2.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(1.0f32), 1.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(1.3f32), 1.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(1.5f32), 2.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(1.7f32), 2.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(0.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(-0.0f32), -0.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(-1.0f32), -1.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(-1.3f32), -1.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(-1.5f32), -2.0f32);
|
||||
assert_biteq!(f32::math::round_ties_even(-1.7f32), -2.0f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trunc() {
|
||||
assert_biteq!(f32::math::trunc(1.0f32), 1.0f32);
|
||||
assert_biteq!(f32::math::trunc(1.3f32), 1.0f32);
|
||||
assert_biteq!(f32::math::trunc(1.5f32), 1.0f32);
|
||||
assert_biteq!(f32::math::trunc(1.7f32), 1.0f32);
|
||||
assert_biteq!(f32::math::trunc(0.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::trunc(-0.0f32), -0.0f32);
|
||||
assert_biteq!(f32::math::trunc(-1.0f32), -1.0f32);
|
||||
assert_biteq!(f32::math::trunc(-1.3f32), -1.0f32);
|
||||
assert_biteq!(f32::math::trunc(-1.5f32), -1.0f32);
|
||||
assert_biteq!(f32::math::trunc(-1.7f32), -1.0f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fract() {
|
||||
assert_biteq!(f32::math::fract(1.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::fract(1.3f32), 0.29999995f32);
|
||||
assert_biteq!(f32::math::fract(1.5f32), 0.5f32);
|
||||
assert_biteq!(f32::math::fract(1.7f32), 0.70000005f32);
|
||||
assert_biteq!(f32::math::fract(0.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::fract(-0.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::fract(-1.0f32), 0.0f32);
|
||||
assert_biteq!(f32::math::fract(-1.3f32), -0.29999995f32);
|
||||
assert_biteq!(f32::math::fract(-1.5f32), -0.5f32);
|
||||
assert_biteq!(f32::math::fract(-1.7f32), -0.70000005f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs() {
|
||||
assert_biteq!(f32::INFINITY.abs(), f32::INFINITY);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use core::f64;
|
|||
use core::f64::consts;
|
||||
use core::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
/// Smallest number
|
||||
const TINY_BITS: u64 = 0x1;
|
||||
|
||||
|
|
@ -28,18 +30,6 @@ fn test_num_f64() {
|
|||
super::test_num(10f64, 2f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_nan() {
|
||||
assert_biteq!(f64::NAN.min(2.0), 2.0);
|
||||
assert_biteq!(2.0f64.min(f64::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_nan() {
|
||||
assert_biteq!(f64::NAN.max(2.0), 2.0);
|
||||
assert_biteq!(2.0f64.max(f64::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan() {
|
||||
let nan: f64 = f64::NAN;
|
||||
|
|
@ -190,92 +180,6 @@ fn test_classify() {
|
|||
assert_eq!(1e-308f64.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_floor() {
|
||||
assert_biteq!(f64::math::floor(1.0f64), 1.0f64);
|
||||
assert_biteq!(f64::math::floor(1.3f64), 1.0f64);
|
||||
assert_biteq!(f64::math::floor(1.5f64), 1.0f64);
|
||||
assert_biteq!(f64::math::floor(1.7f64), 1.0f64);
|
||||
assert_biteq!(f64::math::floor(0.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::floor(-0.0f64), -0.0f64);
|
||||
assert_biteq!(f64::math::floor(-1.0f64), -1.0f64);
|
||||
assert_biteq!(f64::math::floor(-1.3f64), -2.0f64);
|
||||
assert_biteq!(f64::math::floor(-1.5f64), -2.0f64);
|
||||
assert_biteq!(f64::math::floor(-1.7f64), -2.0f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ceil() {
|
||||
assert_biteq!(f64::math::ceil(1.0f64), 1.0f64);
|
||||
assert_biteq!(f64::math::ceil(1.3f64), 2.0f64);
|
||||
assert_biteq!(f64::math::ceil(1.5f64), 2.0f64);
|
||||
assert_biteq!(f64::math::ceil(1.7f64), 2.0f64);
|
||||
assert_biteq!(f64::math::ceil(0.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::ceil(-0.0f64), -0.0f64);
|
||||
assert_biteq!(f64::math::ceil(-1.0f64), -1.0f64);
|
||||
assert_biteq!(f64::math::ceil(-1.3f64), -1.0f64);
|
||||
assert_biteq!(f64::math::ceil(-1.5f64), -1.0f64);
|
||||
assert_biteq!(f64::math::ceil(-1.7f64), -1.0f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round() {
|
||||
assert_biteq!(f64::math::round(2.5f64), 3.0f64);
|
||||
assert_biteq!(f64::math::round(1.0f64), 1.0f64);
|
||||
assert_biteq!(f64::math::round(1.3f64), 1.0f64);
|
||||
assert_biteq!(f64::math::round(1.5f64), 2.0f64);
|
||||
assert_biteq!(f64::math::round(1.7f64), 2.0f64);
|
||||
assert_biteq!(f64::math::round(0.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::round(-0.0f64), -0.0f64);
|
||||
assert_biteq!(f64::math::round(-1.0f64), -1.0f64);
|
||||
assert_biteq!(f64::math::round(-1.3f64), -1.0f64);
|
||||
assert_biteq!(f64::math::round(-1.5f64), -2.0f64);
|
||||
assert_biteq!(f64::math::round(-1.7f64), -2.0f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_ties_even() {
|
||||
assert_biteq!(f64::math::round_ties_even(2.5f64), 2.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(1.0f64), 1.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(1.3f64), 1.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(1.5f64), 2.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(1.7f64), 2.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(0.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(-0.0f64), -0.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(-1.0f64), -1.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(-1.3f64), -1.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(-1.5f64), -2.0f64);
|
||||
assert_biteq!(f64::math::round_ties_even(-1.7f64), -2.0f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trunc() {
|
||||
assert_biteq!(f64::math::trunc(1.0f64), 1.0f64);
|
||||
assert_biteq!(f64::math::trunc(1.3f64), 1.0f64);
|
||||
assert_biteq!(f64::math::trunc(1.5f64), 1.0f64);
|
||||
assert_biteq!(f64::math::trunc(1.7f64), 1.0f64);
|
||||
assert_biteq!(f64::math::trunc(0.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::trunc(-0.0f64), -0.0f64);
|
||||
assert_biteq!(f64::math::trunc(-1.0f64), -1.0f64);
|
||||
assert_biteq!(f64::math::trunc(-1.3f64), -1.0f64);
|
||||
assert_biteq!(f64::math::trunc(-1.5f64), -1.0f64);
|
||||
assert_biteq!(f64::math::trunc(-1.7f64), -1.0f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fract() {
|
||||
assert_biteq!(f64::math::fract(1.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::fract(1.3f64), 0.30000000000000004f64);
|
||||
assert_biteq!(f64::math::fract(1.5f64), 0.5f64);
|
||||
assert_biteq!(f64::math::fract(1.7f64), 0.7f64);
|
||||
assert_biteq!(f64::math::fract(0.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::fract(-0.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::fract(-1.0f64), 0.0f64);
|
||||
assert_biteq!(f64::math::fract(-1.3f64), -0.30000000000000004f64);
|
||||
assert_biteq!(f64::math::fract(-1.5f64), -0.5f64);
|
||||
assert_biteq!(f64::math::fract(-1.7f64), -0.69999999999999996f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs() {
|
||||
assert_biteq!(f64::INFINITY.abs(), f64::INFINITY);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,34 @@
|
|||
use std::fmt;
|
||||
use std::ops::{Add, Div, Mul, Rem, Sub};
|
||||
|
||||
/// Verify that floats are within a tolerance of each other, 1.0e-6 by default.
|
||||
macro_rules! assert_approx_eq {
|
||||
($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }};
|
||||
/// Set the default tolerance for float comparison based on the type.
|
||||
trait Approx {
|
||||
const LIM: Self;
|
||||
}
|
||||
|
||||
impl Approx for f16 {
|
||||
const LIM: Self = 1e-3;
|
||||
}
|
||||
impl Approx for f32 {
|
||||
const LIM: Self = 1e-6;
|
||||
}
|
||||
impl Approx for f64 {
|
||||
const LIM: Self = 1e-6;
|
||||
}
|
||||
impl Approx for f128 {
|
||||
const LIM: Self = 1e-9;
|
||||
}
|
||||
|
||||
/// Determine the tolerance for values of the argument type.
|
||||
const fn lim_for_ty<T: Approx + Copy>(_x: T) -> T {
|
||||
T::LIM
|
||||
}
|
||||
|
||||
// We have runtime ("rt") and const versions of these macros.
|
||||
|
||||
/// Verify that floats are within a tolerance of each other.
|
||||
macro_rules! assert_approx_eq_rt {
|
||||
($a:expr, $b:expr) => {{ assert_approx_eq_rt!($a, $b, $crate::floats::lim_for_ty($a)) }};
|
||||
($a:expr, $b:expr, $lim:expr) => {{
|
||||
let (a, b) = (&$a, &$b);
|
||||
let diff = (*a - *b).abs();
|
||||
|
|
@ -14,10 +39,18 @@ macro_rules! assert_approx_eq {
|
|||
);
|
||||
}};
|
||||
}
|
||||
macro_rules! assert_approx_eq_const {
|
||||
($a:expr, $b:expr) => {{ assert_approx_eq_const!($a, $b, $crate::floats::lim_for_ty($a)) }};
|
||||
($a:expr, $b:expr, $lim:expr) => {{
|
||||
let (a, b) = (&$a, &$b);
|
||||
let diff = (*a - *b).abs();
|
||||
assert!(diff <= $lim);
|
||||
}};
|
||||
}
|
||||
|
||||
/// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0`
|
||||
/// behavior, as well as to ensure exact NaN bitpatterns.
|
||||
macro_rules! assert_biteq {
|
||||
macro_rules! assert_biteq_rt {
|
||||
(@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{
|
||||
let l = $left;
|
||||
let r = $right;
|
||||
|
|
@ -41,31 +74,49 @@ macro_rules! assert_biteq {
|
|||
if !l.is_nan() && !r.is_nan() {
|
||||
// Also check that standard equality holds, since most tests use `assert_biteq` rather
|
||||
// than `assert_eq`.
|
||||
assert_eq!(l, r)
|
||||
assert_eq!(l, r);
|
||||
}
|
||||
}};
|
||||
($left:expr, $right:expr , $($tt:tt)*) => {
|
||||
assert_biteq!(@inner $left, $right, "\n", $($tt)*)
|
||||
assert_biteq_rt!(@inner $left, $right, "\n", $($tt)*)
|
||||
};
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
assert_biteq!(@inner $left, $right, "", "")
|
||||
assert_biteq_rt!(@inner $left, $right, "", "")
|
||||
};
|
||||
}
|
||||
macro_rules! assert_biteq_const {
|
||||
(@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{
|
||||
let l = $left;
|
||||
let r = $right;
|
||||
|
||||
// Hack to coerce left and right to the same type
|
||||
let mut _eq_ty = l;
|
||||
_eq_ty = r;
|
||||
|
||||
assert!(l.to_bits() == r.to_bits());
|
||||
|
||||
if !l.is_nan() && !r.is_nan() {
|
||||
// Also check that standard equality holds, since most tests use `assert_biteq` rather
|
||||
// than `assert_eq`.
|
||||
assert!(l == r);
|
||||
}
|
||||
}};
|
||||
($left:expr, $right:expr , $($tt:tt)*) => {
|
||||
assert_biteq_const!(@inner $left, $right, "\n", $($tt)*)
|
||||
};
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
assert_biteq_const!(@inner $left, $right, "", "")
|
||||
};
|
||||
}
|
||||
|
||||
mod const_asserts {
|
||||
// Shadow some assert implementations that would otherwise not compile in a const-context.
|
||||
// Every macro added here also needs to be added in the `float_test!` macro below.
|
||||
macro_rules! assert_eq {
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
std::assert!($left == $right)
|
||||
};
|
||||
($left:expr, $right:expr, $($arg:tt)+) => {
|
||||
std::assert!($left == $right, $($arg)+)
|
||||
};
|
||||
}
|
||||
// Use the runtime version by default.
|
||||
// This way, they can be shadowed by the const versions.
|
||||
pub(crate) use {assert_approx_eq_rt as assert_approx_eq, assert_biteq_rt as assert_biteq};
|
||||
|
||||
pub(crate) use assert_eq;
|
||||
}
|
||||
// Also make the const version available for re-exports.
|
||||
#[rustfmt::skip]
|
||||
pub(crate) use assert_biteq_const;
|
||||
pub(crate) use assert_approx_eq_const;
|
||||
|
||||
/// Generate float tests for all our float types, for compile-time and run-time behavior.
|
||||
///
|
||||
|
|
@ -84,6 +135,7 @@ mod const_asserts {
|
|||
/// /* write tests here, using `Float` as the type */
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
macro_rules! float_test {
|
||||
(
|
||||
name: $name:ident,
|
||||
|
|
@ -101,6 +153,8 @@ macro_rules! float_test {
|
|||
test<$fty:ident> $test:block
|
||||
) => {
|
||||
mod $name {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
$( $( #[$f16_meta] )+ )?
|
||||
fn test_f16() {
|
||||
|
|
@ -131,7 +185,14 @@ macro_rules! float_test {
|
|||
|
||||
$( $( #[$const_meta] )+ )?
|
||||
mod const_ {
|
||||
use $crate::floats::const_asserts::assert_eq;
|
||||
#[allow(unused)]
|
||||
use super::Approx;
|
||||
// Shadow the runtime versions of the macro with const-compatible versions.
|
||||
#[allow(unused)]
|
||||
use $crate::floats::{
|
||||
assert_approx_eq_const as assert_approx_eq,
|
||||
assert_biteq_const as assert_biteq,
|
||||
};
|
||||
|
||||
#[test]
|
||||
$( $( #[$f16_const_meta] )+ )?
|
||||
|
|
@ -196,29 +257,25 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).min(0.0), 0.0);
|
||||
assert!((0.0 as Float).min(0.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).min(-0.0), -0.0);
|
||||
assert!((-0.0 as Float).min(-0.0).is_sign_negative());
|
||||
assert_eq!((9.0 as Float).min(9.0), 9.0);
|
||||
assert_eq!((-9.0 as Float).min(0.0), -9.0);
|
||||
assert_eq!((0.0 as Float).min(9.0), 0.0);
|
||||
assert!((0.0 as Float).min(9.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).min(9.0), -0.0);
|
||||
assert!((-0.0 as Float).min(9.0).is_sign_negative());
|
||||
assert_eq!((-0.0 as Float).min(-9.0), -9.0);
|
||||
assert_eq!(Float::INFINITY.min(9.0), 9.0);
|
||||
assert_eq!((9.0 as Float).min(Float::INFINITY), 9.0);
|
||||
assert_eq!(Float::INFINITY.min(-9.0), -9.0);
|
||||
assert_eq!((-9.0 as Float).min(Float::INFINITY), -9.0);
|
||||
assert_eq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY);
|
||||
assert_eq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY);
|
||||
assert_eq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert_eq!(Float::NAN.min(9.0), 9.0);
|
||||
assert_eq!(Float::NAN.min(-9.0), -9.0);
|
||||
assert_eq!((9.0 as Float).min(Float::NAN), 9.0);
|
||||
assert_eq!((-9.0 as Float).min(Float::NAN), -9.0);
|
||||
assert_biteq!((0.0 as Float).min(0.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).min(-0.0), -0.0);
|
||||
assert_biteq!((9.0 as Float).min(9.0), 9.0);
|
||||
assert_biteq!((-9.0 as Float).min(0.0), -9.0);
|
||||
assert_biteq!((0.0 as Float).min(9.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).min(9.0), -0.0);
|
||||
assert_biteq!((-0.0 as Float).min(-9.0), -9.0);
|
||||
assert_biteq!(Float::INFINITY.min(9.0), 9.0);
|
||||
assert_biteq!((9.0 as Float).min(Float::INFINITY), 9.0);
|
||||
assert_biteq!(Float::INFINITY.min(-9.0), -9.0);
|
||||
assert_biteq!((-9.0 as Float).min(Float::INFINITY), -9.0);
|
||||
assert_biteq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY);
|
||||
assert_biteq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY);
|
||||
assert_biteq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::NAN.min(9.0), 9.0);
|
||||
assert_biteq!(Float::NAN.min(-9.0), -9.0);
|
||||
assert_biteq!((9.0 as Float).min(Float::NAN), 9.0);
|
||||
assert_biteq!((-9.0 as Float).min(Float::NAN), -9.0);
|
||||
assert!(Float::NAN.min(Float::NAN).is_nan());
|
||||
}
|
||||
}
|
||||
|
|
@ -230,32 +287,26 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).max(0.0), 0.0);
|
||||
assert!((0.0 as Float).max(0.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).max(-0.0), -0.0);
|
||||
assert!((-0.0 as Float).max(-0.0).is_sign_negative());
|
||||
assert_eq!((9.0 as Float).max(9.0), 9.0);
|
||||
assert_eq!((-9.0 as Float).max(0.0), 0.0);
|
||||
assert!((-9.0 as Float).max(0.0).is_sign_positive());
|
||||
assert_eq!((-9.0 as Float).max(-0.0), -0.0);
|
||||
assert!((-9.0 as Float).max(-0.0).is_sign_negative());
|
||||
assert_eq!((0.0 as Float).max(9.0), 9.0);
|
||||
assert_eq!((0.0 as Float).max(-9.0), 0.0);
|
||||
assert!((0.0 as Float).max(-9.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).max(-9.0), -0.0);
|
||||
assert!((-0.0 as Float).max(-9.0).is_sign_negative());
|
||||
assert_eq!(Float::INFINITY.max(9.0), Float::INFINITY);
|
||||
assert_eq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY);
|
||||
assert_eq!(Float::INFINITY.max(-9.0), Float::INFINITY);
|
||||
assert_eq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.max(9.0), 9.0);
|
||||
assert_eq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0);
|
||||
assert_eq!(Float::NEG_INFINITY.max(-9.0), -9.0);
|
||||
assert_eq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0);
|
||||
assert_eq!(Float::NAN.max(9.0), 9.0);
|
||||
assert_eq!(Float::NAN.max(-9.0), -9.0);
|
||||
assert_eq!((9.0 as Float).max(Float::NAN), 9.0);
|
||||
assert_eq!((-9.0 as Float).max(Float::NAN), -9.0);
|
||||
assert_biteq!((0.0 as Float).max(0.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).max(-0.0), -0.0);
|
||||
assert_biteq!((9.0 as Float).max(9.0), 9.0);
|
||||
assert_biteq!((-9.0 as Float).max(0.0), 0.0);
|
||||
assert_biteq!((-9.0 as Float).max(-0.0), -0.0);
|
||||
assert_biteq!((0.0 as Float).max(9.0), 9.0);
|
||||
assert_biteq!((0.0 as Float).max(-9.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).max(-9.0), -0.0);
|
||||
assert_biteq!(Float::INFINITY.max(9.0), Float::INFINITY);
|
||||
assert_biteq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY);
|
||||
assert_biteq!(Float::INFINITY.max(-9.0), Float::INFINITY);
|
||||
assert_biteq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.max(9.0), 9.0);
|
||||
assert_biteq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0);
|
||||
assert_biteq!(Float::NEG_INFINITY.max(-9.0), -9.0);
|
||||
assert_biteq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0);
|
||||
assert_biteq!(Float::NAN.max(9.0), 9.0);
|
||||
assert_biteq!(Float::NAN.max(-9.0), -9.0);
|
||||
assert_biteq!((9.0 as Float).max(Float::NAN), 9.0);
|
||||
assert_biteq!((-9.0 as Float).max(Float::NAN), -9.0);
|
||||
assert!(Float::NAN.max(Float::NAN).is_nan());
|
||||
}
|
||||
}
|
||||
|
|
@ -267,27 +318,22 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).minimum(0.0), 0.0);
|
||||
assert!((0.0 as Float).minimum(0.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).minimum(0.0), -0.0);
|
||||
assert!((-0.0 as Float).minimum(0.0).is_sign_negative());
|
||||
assert_eq!((-0.0 as Float).minimum(-0.0), -0.0);
|
||||
assert!((-0.0 as Float).minimum(-0.0).is_sign_negative());
|
||||
assert_eq!((9.0 as Float).minimum(9.0), 9.0);
|
||||
assert_eq!((-9.0 as Float).minimum(0.0), -9.0);
|
||||
assert_eq!((0.0 as Float).minimum(9.0), 0.0);
|
||||
assert!((0.0 as Float).minimum(9.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).minimum(9.0), -0.0);
|
||||
assert!((-0.0 as Float).minimum(9.0).is_sign_negative());
|
||||
assert_eq!((-0.0 as Float).minimum(-9.0), -9.0);
|
||||
assert_eq!(Float::INFINITY.minimum(9.0), 9.0);
|
||||
assert_eq!((9.0 as Float).minimum(Float::INFINITY), 9.0);
|
||||
assert_eq!(Float::INFINITY.minimum(-9.0), -9.0);
|
||||
assert_eq!((-9.0 as Float).minimum(Float::INFINITY), -9.0);
|
||||
assert_eq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY);
|
||||
assert_eq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY);
|
||||
assert_eq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert_biteq!((0.0 as Float).minimum(0.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).minimum(0.0), -0.0);
|
||||
assert_biteq!((-0.0 as Float).minimum(-0.0), -0.0);
|
||||
assert_biteq!((9.0 as Float).minimum(9.0), 9.0);
|
||||
assert_biteq!((-9.0 as Float).minimum(0.0), -9.0);
|
||||
assert_biteq!((0.0 as Float).minimum(9.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).minimum(9.0), -0.0);
|
||||
assert_biteq!((-0.0 as Float).minimum(-9.0), -9.0);
|
||||
assert_biteq!(Float::INFINITY.minimum(9.0), 9.0);
|
||||
assert_biteq!((9.0 as Float).minimum(Float::INFINITY), 9.0);
|
||||
assert_biteq!(Float::INFINITY.minimum(-9.0), -9.0);
|
||||
assert_biteq!((-9.0 as Float).minimum(Float::INFINITY), -9.0);
|
||||
assert_biteq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY);
|
||||
assert_biteq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY);
|
||||
assert_biteq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY);
|
||||
assert!(Float::NAN.minimum(9.0).is_nan());
|
||||
assert!(Float::NAN.minimum(-9.0).is_nan());
|
||||
assert!((9.0 as Float).minimum(Float::NAN).is_nan());
|
||||
|
|
@ -303,30 +349,23 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).maximum(0.0), 0.0);
|
||||
assert!((0.0 as Float).maximum(0.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).maximum(0.0), 0.0);
|
||||
assert!((-0.0 as Float).maximum(0.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).maximum(-0.0), -0.0);
|
||||
assert!((-0.0 as Float).maximum(-0.0).is_sign_negative());
|
||||
assert_eq!((9.0 as Float).maximum(9.0), 9.0);
|
||||
assert_eq!((-9.0 as Float).maximum(0.0), 0.0);
|
||||
assert!((-9.0 as Float).maximum(0.0).is_sign_positive());
|
||||
assert_eq!((-9.0 as Float).maximum(-0.0), -0.0);
|
||||
assert!((-9.0 as Float).maximum(-0.0).is_sign_negative());
|
||||
assert_eq!((0.0 as Float).maximum(9.0), 9.0);
|
||||
assert_eq!((0.0 as Float).maximum(-9.0), 0.0);
|
||||
assert!((0.0 as Float).maximum(-9.0).is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).maximum(-9.0), -0.0);
|
||||
assert!((-0.0 as Float).maximum(-9.0).is_sign_negative());
|
||||
assert_eq!(Float::INFINITY.maximum(9.0), Float::INFINITY);
|
||||
assert_eq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY);
|
||||
assert_eq!(Float::INFINITY.maximum(-9.0), Float::INFINITY);
|
||||
assert_eq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.maximum(9.0), 9.0);
|
||||
assert_eq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0);
|
||||
assert_eq!(Float::NEG_INFINITY.maximum(-9.0), -9.0);
|
||||
assert_eq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0);
|
||||
assert_biteq!((0.0 as Float).maximum(0.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).maximum(0.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).maximum(-0.0), -0.0);
|
||||
assert_biteq!((9.0 as Float).maximum(9.0), 9.0);
|
||||
assert_biteq!((-9.0 as Float).maximum(0.0), 0.0);
|
||||
assert_biteq!((-9.0 as Float).maximum(-0.0), -0.0);
|
||||
assert_biteq!((0.0 as Float).maximum(9.0), 9.0);
|
||||
assert_biteq!((0.0 as Float).maximum(-9.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).maximum(-9.0), -0.0);
|
||||
assert_biteq!(Float::INFINITY.maximum(9.0), Float::INFINITY);
|
||||
assert_biteq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY);
|
||||
assert_biteq!(Float::INFINITY.maximum(-9.0), Float::INFINITY);
|
||||
assert_biteq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.maximum(9.0), 9.0);
|
||||
assert_biteq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0);
|
||||
assert_biteq!(Float::NEG_INFINITY.maximum(-9.0), -9.0);
|
||||
assert_biteq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0);
|
||||
assert!(Float::NAN.maximum(9.0).is_nan());
|
||||
assert!(Float::NAN.maximum(-9.0).is_nan());
|
||||
assert!((9.0 as Float).maximum(Float::NAN).is_nan());
|
||||
|
|
@ -342,41 +381,43 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.5 as Float).midpoint(0.5), 0.5);
|
||||
assert_eq!((0.5 as Float).midpoint(2.5), 1.5);
|
||||
assert_eq!((3.0 as Float).midpoint(4.0), 3.5);
|
||||
assert_eq!((-3.0 as Float).midpoint(4.0), 0.5);
|
||||
assert_eq!((3.0 as Float).midpoint(-4.0), -0.5);
|
||||
assert_eq!((-3.0 as Float).midpoint(-4.0), -3.5);
|
||||
assert_eq!((0.0 as Float).midpoint(0.0), 0.0);
|
||||
assert_eq!((-0.0 as Float).midpoint(-0.0), -0.0);
|
||||
assert_eq!((-5.0 as Float).midpoint(5.0), 0.0);
|
||||
assert_eq!(Float::MAX.midpoint(Float::MIN), 0.0);
|
||||
assert_eq!(Float::MIN.midpoint(Float::MAX), -0.0);
|
||||
assert_eq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.);
|
||||
assert_eq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.);
|
||||
assert_eq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.);
|
||||
assert_eq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.);
|
||||
assert_eq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.);
|
||||
assert_eq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.);
|
||||
assert_eq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.);
|
||||
assert_eq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.);
|
||||
assert_eq!(Float::MAX.midpoint(Float::MAX), Float::MAX);
|
||||
assert_eq!(
|
||||
assert_biteq!((0.5 as Float).midpoint(0.5), 0.5);
|
||||
assert_biteq!((0.5 as Float).midpoint(2.5), 1.5);
|
||||
assert_biteq!((3.0 as Float).midpoint(4.0), 3.5);
|
||||
assert_biteq!((-3.0 as Float).midpoint(4.0), 0.5);
|
||||
assert_biteq!((3.0 as Float).midpoint(-4.0), -0.5);
|
||||
assert_biteq!((-3.0 as Float).midpoint(-4.0), -3.5);
|
||||
assert_biteq!((0.0 as Float).midpoint(0.0), 0.0);
|
||||
assert_biteq!((-0.0 as Float).midpoint(-0.0), -0.0);
|
||||
assert_biteq!((-5.0 as Float).midpoint(5.0), 0.0);
|
||||
assert_biteq!(Float::MAX.midpoint(Float::MIN), 0.0);
|
||||
assert_biteq!(Float::MIN.midpoint(Float::MAX), 0.0);
|
||||
assert_biteq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.);
|
||||
assert_biteq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.);
|
||||
assert_biteq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.);
|
||||
assert_biteq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.);
|
||||
assert_biteq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.);
|
||||
assert_biteq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.);
|
||||
assert_biteq!(Float::MAX.midpoint(Float::MAX), Float::MAX);
|
||||
assert_biteq!(
|
||||
(Float::MIN_POSITIVE).midpoint(Float::MIN_POSITIVE),
|
||||
Float::MIN_POSITIVE
|
||||
);
|
||||
assert_eq!(
|
||||
assert_biteq!(
|
||||
(-Float::MIN_POSITIVE).midpoint(-Float::MIN_POSITIVE),
|
||||
-Float::MIN_POSITIVE
|
||||
);
|
||||
assert_eq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5);
|
||||
assert_eq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5);
|
||||
assert_eq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY);
|
||||
assert_eq!(
|
||||
assert_biteq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5);
|
||||
assert_biteq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5);
|
||||
assert_biteq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY);
|
||||
assert_biteq!(
|
||||
Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY),
|
||||
Float::NEG_INFINITY
|
||||
);
|
||||
assert!(Float::NEG_INFINITY.midpoint(Float::INFINITY).is_nan());
|
||||
assert!(Float::INFINITY.midpoint(Float::NEG_INFINITY).is_nan());
|
||||
assert!(Float::NAN.midpoint(1.0).is_nan());
|
||||
assert!((1.0 as Float).midpoint(Float::NAN).is_nan());
|
||||
assert!(Float::NAN.midpoint(Float::NAN).is_nan());
|
||||
|
|
@ -410,7 +451,7 @@ float_test! {
|
|||
let naive = (large + small) / 2.0;
|
||||
let midpoint = large.midpoint(small);
|
||||
|
||||
assert_eq!(naive, midpoint);
|
||||
assert_biteq!(naive, midpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -423,10 +464,10 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((-1.0 as Float).abs(), 1.0);
|
||||
assert_eq!((1.0 as Float).abs(), 1.0);
|
||||
assert_eq!(Float::NEG_INFINITY.abs(), Float::INFINITY);
|
||||
assert_eq!(Float::INFINITY.abs(), Float::INFINITY);
|
||||
assert_biteq!((-1.0 as Float).abs(), 1.0);
|
||||
assert_biteq!((1.0 as Float).abs(), 1.0);
|
||||
assert_biteq!(Float::NEG_INFINITY.abs(), Float::INFINITY);
|
||||
assert_biteq!(Float::INFINITY.abs(), Float::INFINITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -437,10 +478,10 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((1.0 as Float).copysign(-2.0), -1.0);
|
||||
assert_eq!((-1.0 as Float).copysign(2.0), 1.0);
|
||||
assert_eq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY);
|
||||
assert_biteq!((1.0 as Float).copysign(-2.0), -1.0);
|
||||
assert_biteq!((-1.0 as Float).copysign(2.0), 1.0);
|
||||
assert_biteq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -453,7 +494,7 @@ float_test! {
|
|||
},
|
||||
test<Float> {
|
||||
assert!(Float::INFINITY.rem_euclid(42.0 as Float).is_nan());
|
||||
assert_eq!((42.0 as Float).rem_euclid(Float::INFINITY), (42.0 as Float));
|
||||
assert_biteq!((42.0 as Float).rem_euclid(Float::INFINITY), 42.0 as Float);
|
||||
assert!((42.0 as Float).rem_euclid(Float::NAN).is_nan());
|
||||
assert!(Float::INFINITY.rem_euclid(Float::INFINITY).is_nan());
|
||||
assert!(Float::INFINITY.rem_euclid(Float::NAN).is_nan());
|
||||
|
|
@ -469,7 +510,7 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0);
|
||||
assert_biteq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0);
|
||||
assert!((42.0 as Float).div_euclid(Float::NAN).is_nan());
|
||||
assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan());
|
||||
assert!(Float::INFINITY.div_euclid(Float::NAN).is_nan());
|
||||
|
|
@ -484,20 +525,25 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).floor(), 0.0);
|
||||
assert!((0.0 as Float).floor().is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).floor(), -0.0);
|
||||
assert!((-0.0 as Float).floor().is_sign_negative());
|
||||
assert_eq!((0.5 as Float).floor(), 0.0);
|
||||
assert_eq!((-0.5 as Float).floor(), -1.0);
|
||||
assert_eq!((1.5 as Float).floor(), 1.0);
|
||||
assert_eq!(Float::MAX.floor(), Float::MAX);
|
||||
assert_eq!(Float::MIN.floor(), Float::MIN);
|
||||
assert_eq!(Float::MIN_POSITIVE.floor(), 0.0);
|
||||
assert_eq!((-Float::MIN_POSITIVE).floor(), -1.0);
|
||||
assert_biteq!((1.0 as Float).floor(), 1.0);
|
||||
assert_biteq!((1.3 as Float).floor(), 1.0);
|
||||
assert_biteq!((1.5 as Float).floor(), 1.0);
|
||||
assert_biteq!((1.7 as Float).floor(), 1.0);
|
||||
assert_biteq!((0.5 as Float).floor(), 0.0);
|
||||
assert_biteq!((0.0 as Float).floor(), 0.0);
|
||||
assert_biteq!((-0.0 as Float).floor(), -0.0);
|
||||
assert_biteq!((-0.5 as Float).floor(), -1.0);
|
||||
assert_biteq!((-1.0 as Float).floor(), -1.0);
|
||||
assert_biteq!((-1.3 as Float).floor(), -2.0);
|
||||
assert_biteq!((-1.5 as Float).floor(), -2.0);
|
||||
assert_biteq!((-1.7 as Float).floor(), -2.0);
|
||||
assert_biteq!(Float::MAX.floor(), Float::MAX);
|
||||
assert_biteq!(Float::MIN.floor(), Float::MIN);
|
||||
assert_biteq!(Float::MIN_POSITIVE.floor(), 0.0);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).floor(), -1.0);
|
||||
assert!(Float::NAN.floor().is_nan());
|
||||
assert_eq!(Float::INFINITY.floor(), Float::INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::INFINITY.floor(), Float::INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -508,19 +554,25 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).ceil(), 0.0);
|
||||
assert!((0.0 as Float).ceil().is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).ceil(), 0.0);
|
||||
assert!((-0.0 as Float).ceil().is_sign_negative());
|
||||
assert_eq!((0.5 as Float).ceil(), 1.0);
|
||||
assert_eq!((-0.5 as Float).ceil(), 0.0);
|
||||
assert_eq!(Float::MAX.ceil(), Float::MAX);
|
||||
assert_eq!(Float::MIN.ceil(), Float::MIN);
|
||||
assert_eq!(Float::MIN_POSITIVE.ceil(), 1.0);
|
||||
assert_eq!((-Float::MIN_POSITIVE).ceil(), 0.0);
|
||||
assert_biteq!((1.0 as Float).ceil(), 1.0);
|
||||
assert_biteq!((1.3 as Float).ceil(), 2.0);
|
||||
assert_biteq!((1.5 as Float).ceil(), 2.0);
|
||||
assert_biteq!((1.7 as Float).ceil(), 2.0);
|
||||
assert_biteq!((0.5 as Float).ceil(), 1.0);
|
||||
assert_biteq!((0.0 as Float).ceil(), 0.0);
|
||||
assert_biteq!((-0.0 as Float).ceil(), -0.0);
|
||||
assert_biteq!((-0.5 as Float).ceil(), -0.0);
|
||||
assert_biteq!((-1.0 as Float).ceil(), -1.0);
|
||||
assert_biteq!((-1.3 as Float).ceil(), -1.0);
|
||||
assert_biteq!((-1.5 as Float).ceil(), -1.0);
|
||||
assert_biteq!((-1.7 as Float).ceil(), -1.0);
|
||||
assert_biteq!(Float::MAX.ceil(), Float::MAX);
|
||||
assert_biteq!(Float::MIN.ceil(), Float::MIN);
|
||||
assert_biteq!(Float::MIN_POSITIVE.ceil(), 1.0);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).ceil(), -0.0);
|
||||
assert!(Float::NAN.ceil().is_nan());
|
||||
assert_eq!(Float::INFINITY.ceil(), Float::INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::INFINITY.ceil(), Float::INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -531,19 +583,26 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).round(), 0.0);
|
||||
assert!((0.0 as Float).round().is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).round(), -0.0);
|
||||
assert!((-0.0 as Float).round().is_sign_negative());
|
||||
assert_eq!((0.5 as Float).round(), 1.0);
|
||||
assert_eq!((-0.5 as Float).round(), -1.0);
|
||||
assert_eq!(Float::MAX.round(), Float::MAX);
|
||||
assert_eq!(Float::MIN.round(), Float::MIN);
|
||||
assert_eq!(Float::MIN_POSITIVE.round(), 0.0);
|
||||
assert_eq!((-Float::MIN_POSITIVE).round(), 0.0);
|
||||
assert_biteq!((2.5 as Float).round(), 3.0);
|
||||
assert_biteq!((1.0 as Float).round(), 1.0);
|
||||
assert_biteq!((1.3 as Float).round(), 1.0);
|
||||
assert_biteq!((1.5 as Float).round(), 2.0);
|
||||
assert_biteq!((1.7 as Float).round(), 2.0);
|
||||
assert_biteq!((0.5 as Float).round(), 1.0);
|
||||
assert_biteq!((0.0 as Float).round(), 0.0);
|
||||
assert_biteq!((-0.0 as Float).round(), -0.0);
|
||||
assert_biteq!((-0.5 as Float).round(), -1.0);
|
||||
assert_biteq!((-1.0 as Float).round(), -1.0);
|
||||
assert_biteq!((-1.3 as Float).round(), -1.0);
|
||||
assert_biteq!((-1.5 as Float).round(), -2.0);
|
||||
assert_biteq!((-1.7 as Float).round(), -2.0);
|
||||
assert_biteq!(Float::MAX.round(), Float::MAX);
|
||||
assert_biteq!(Float::MIN.round(), Float::MIN);
|
||||
assert_biteq!(Float::MIN_POSITIVE.round(), 0.0);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).round(), -0.0);
|
||||
assert!(Float::NAN.round().is_nan());
|
||||
assert_eq!(Float::INFINITY.round(), Float::INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::INFINITY.round(), Float::INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -554,21 +613,26 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).round_ties_even(), 0.0);
|
||||
assert!((0.0 as Float).round_ties_even().is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).round_ties_even(), -0.0);
|
||||
assert!((-0.0 as Float).round_ties_even().is_sign_negative());
|
||||
assert_eq!((0.5 as Float).round_ties_even(), 0.0);
|
||||
assert!((0.5 as Float).round_ties_even().is_sign_positive());
|
||||
assert_eq!((-0.5 as Float).round_ties_even(), -0.0);
|
||||
assert!((-0.5 as Float).round_ties_even().is_sign_negative());
|
||||
assert_eq!(Float::MAX.round_ties_even(), Float::MAX);
|
||||
assert_eq!(Float::MIN.round_ties_even(), Float::MIN);
|
||||
assert_eq!(Float::MIN_POSITIVE.round_ties_even(), 0.0);
|
||||
assert_eq!((-Float::MIN_POSITIVE).round_ties_even(), 0.0);
|
||||
assert_biteq!((2.5 as Float).round_ties_even(), 2.0);
|
||||
assert_biteq!((1.0 as Float).round_ties_even(), 1.0);
|
||||
assert_biteq!((1.3 as Float).round_ties_even(), 1.0);
|
||||
assert_biteq!((1.5 as Float).round_ties_even(), 2.0);
|
||||
assert_biteq!((1.7 as Float).round_ties_even(), 2.0);
|
||||
assert_biteq!((0.5 as Float).round_ties_even(), 0.0);
|
||||
assert_biteq!((0.0 as Float).round_ties_even(), 0.0);
|
||||
assert_biteq!((-0.0 as Float).round_ties_even(), -0.0);
|
||||
assert_biteq!((-0.5 as Float).round_ties_even(), -0.0);
|
||||
assert_biteq!((-1.0 as Float).round_ties_even(), -1.0);
|
||||
assert_biteq!((-1.3 as Float).round_ties_even(), -1.0);
|
||||
assert_biteq!((-1.5 as Float).round_ties_even(), -2.0);
|
||||
assert_biteq!((-1.7 as Float).round_ties_even(), -2.0);
|
||||
assert_biteq!(Float::MAX.round_ties_even(), Float::MAX);
|
||||
assert_biteq!(Float::MIN.round_ties_even(), Float::MIN);
|
||||
assert_biteq!(Float::MIN_POSITIVE.round_ties_even(), 0.0);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).round_ties_even(), -0.0);
|
||||
assert!(Float::NAN.round_ties_even().is_nan());
|
||||
assert_eq!(Float::INFINITY.round_ties_even(), Float::INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::INFINITY.round_ties_even(), Float::INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -579,21 +643,25 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).trunc(), 0.0);
|
||||
assert!((0.0 as Float).trunc().is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).trunc(), -0.0);
|
||||
assert!((-0.0 as Float).trunc().is_sign_negative());
|
||||
assert_eq!((0.5 as Float).trunc(), 0.0);
|
||||
assert!((0.5 as Float).trunc().is_sign_positive());
|
||||
assert_eq!((-0.5 as Float).trunc(), -0.0);
|
||||
assert!((-0.5 as Float).trunc().is_sign_negative());
|
||||
assert_eq!(Float::MAX.trunc(), Float::MAX);
|
||||
assert_eq!(Float::MIN.trunc(), Float::MIN);
|
||||
assert_eq!(Float::MIN_POSITIVE.trunc(), 0.0);
|
||||
assert_eq!((-Float::MIN_POSITIVE).trunc(), 0.0);
|
||||
assert_biteq!((1.0 as Float).trunc(), 1.0);
|
||||
assert_biteq!((1.3 as Float).trunc(), 1.0);
|
||||
assert_biteq!((1.5 as Float).trunc(), 1.0);
|
||||
assert_biteq!((1.7 as Float).trunc(), 1.0);
|
||||
assert_biteq!((0.5 as Float).trunc(), 0.0);
|
||||
assert_biteq!((0.0 as Float).trunc(), 0.0);
|
||||
assert_biteq!((-0.0 as Float).trunc(), -0.0);
|
||||
assert_biteq!((-0.5 as Float).trunc(), -0.0);
|
||||
assert_biteq!((-1.0 as Float).trunc(), -1.0);
|
||||
assert_biteq!((-1.3 as Float).trunc(), -1.0);
|
||||
assert_biteq!((-1.5 as Float).trunc(), -1.0);
|
||||
assert_biteq!((-1.7 as Float).trunc(), -1.0);
|
||||
assert_biteq!(Float::MAX.trunc(), Float::MAX);
|
||||
assert_biteq!(Float::MIN.trunc(), Float::MIN);
|
||||
assert_biteq!(Float::MIN_POSITIVE.trunc(), 0.0);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).trunc(), -0.0);
|
||||
assert!(Float::NAN.trunc().is_nan());
|
||||
assert_eq!(Float::INFINITY.trunc(), Float::INFINITY);
|
||||
assert_eq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY);
|
||||
assert_biteq!(Float::INFINITY.trunc(), Float::INFINITY);
|
||||
assert_biteq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -604,19 +672,23 @@ float_test! {
|
|||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
assert_eq!((0.0 as Float).fract(), 0.0);
|
||||
assert!((0.0 as Float).fract().is_sign_positive());
|
||||
assert_eq!((-0.0 as Float).fract(), 0.0);
|
||||
assert!((-0.0 as Float).fract().is_sign_positive());
|
||||
assert_eq!((0.5 as Float).fract(), 0.5);
|
||||
assert!((0.5 as Float).fract().is_sign_positive());
|
||||
assert_eq!((-0.5 as Float).fract(), -0.5);
|
||||
assert!((-0.5 as Float).fract().is_sign_negative());
|
||||
assert_eq!(Float::MAX.fract(), 0.0);
|
||||
assert_eq!(Float::MIN.fract(), 0.0);
|
||||
assert_eq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE);
|
||||
assert_biteq!((1.0 as Float).fract(), 0.0);
|
||||
assert_approx_eq!((1.3 as Float).fract(), 0.3); // rounding differs between float types
|
||||
assert_biteq!((1.5 as Float).fract(), 0.5);
|
||||
assert_approx_eq!((1.7 as Float).fract(), 0.7);
|
||||
assert_biteq!((0.5 as Float).fract(), 0.5);
|
||||
assert_biteq!((0.0 as Float).fract(), 0.0);
|
||||
assert_biteq!((-0.0 as Float).fract(), 0.0);
|
||||
assert_biteq!((-0.5 as Float).fract(), -0.5);
|
||||
assert_biteq!((-1.0 as Float).fract(), 0.0);
|
||||
assert_approx_eq!((-1.3 as Float).fract(), -0.3); // rounding differs between float types
|
||||
assert_biteq!((-1.5 as Float).fract(), -0.5);
|
||||
assert_approx_eq!((-1.7 as Float).fract(), -0.7);
|
||||
assert_biteq!(Float::MAX.fract(), 0.0);
|
||||
assert_biteq!(Float::MIN.fract(), 0.0);
|
||||
assert_biteq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE);
|
||||
assert!(Float::MIN_POSITIVE.fract().is_sign_positive());
|
||||
assert_eq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE);
|
||||
assert_biteq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE);
|
||||
assert!((-Float::MIN_POSITIVE).fract().is_sign_negative());
|
||||
assert!(Float::NAN.fract().is_nan());
|
||||
assert!(Float::INFINITY.fract().is_nan());
|
||||
|
|
|
|||
|
|
@ -653,7 +653,6 @@ fn thin_box() {
|
|||
// if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
|
||||
// * Constructing a `ThinBox` without consuming and deallocating a `Box`
|
||||
// requires either the unstable `Unsize` marker trait,
|
||||
// or the unstable `unsized_locals` language feature,
|
||||
// or taking `&dyn T` and restricting to `T: Copy`.
|
||||
|
||||
use std::alloc::*;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::bstr::ByteStr;
|
||||
use crate::ffi::OsStr;
|
||||
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
|
||||
use crate::os::net::linux_ext;
|
||||
|
|
@ -61,7 +62,7 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s
|
|||
enum AddressKind<'a> {
|
||||
Unnamed,
|
||||
Pathname(&'a Path),
|
||||
Abstract(&'a [u8]),
|
||||
Abstract(&'a ByteStr),
|
||||
}
|
||||
|
||||
/// An address associated with a Unix socket.
|
||||
|
|
@ -245,7 +246,7 @@ impl SocketAddr {
|
|||
{
|
||||
AddressKind::Unnamed
|
||||
} else if self.addr.sun_path[0] == 0 {
|
||||
AddressKind::Abstract(&path[1..len])
|
||||
AddressKind::Abstract(ByteStr::from_bytes(&path[1..len]))
|
||||
} else {
|
||||
AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
|
||||
}
|
||||
|
|
@ -260,7 +261,7 @@ impl Sealed for SocketAddr {}
|
|||
#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
|
||||
impl linux_ext::addr::SocketAddrExt for SocketAddr {
|
||||
fn as_abstract_name(&self) -> Option<&[u8]> {
|
||||
if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
|
||||
if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None }
|
||||
}
|
||||
|
||||
fn from_abstract_name<N>(name: N) -> crate::io::Result<Self>
|
||||
|
|
@ -295,7 +296,7 @@ impl fmt::Debug for SocketAddr {
|
|||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.address() {
|
||||
AddressKind::Unnamed => write!(fmt, "(unnamed)"),
|
||||
AddressKind::Abstract(name) => write!(fmt, "\"{}\" (abstract)", name.escape_ascii()),
|
||||
AddressKind::Abstract(name) => write!(fmt, "{name:?} (abstract)"),
|
||||
AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -411,6 +411,15 @@ fn test_unix_datagram_timeout_zero_duration() {
|
|||
assert_eq!(err.kind(), ErrorKind::InvalidInput);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[test]
|
||||
fn abstract_socket_addr_debug() {
|
||||
assert_eq!(
|
||||
r#""\0hello world\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff" (abstract)"#,
|
||||
format!("{:?}", SocketAddr::from_abstract_name(b"\0hello world\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff").unwrap()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn abstract_namespace_not_allowed_connect() {
|
||||
assert!(UnixStream::connect("\0asdf").is_err());
|
||||
|
|
|
|||
|
|
@ -156,8 +156,8 @@ a new unstable feature:
|
|||
[`incomplete_features` lint]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#incomplete-features
|
||||
|
||||
```rust ignore
|
||||
/// Allows unsized rvalues at arguments and parameters.
|
||||
(incomplete, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), None),
|
||||
/// Allows deref patterns.
|
||||
(incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None),
|
||||
```
|
||||
|
||||
To avoid [semantic merge conflicts], please use `CURRENT_RUSTC_VERSION` instead of `1.70` or
|
||||
|
|
|
|||
|
|
@ -581,7 +581,9 @@ For this rust code:
|
|||
|
||||
```rust
|
||||
/// ```
|
||||
/// #![allow(dead_code)]
|
||||
/// let x = 12;
|
||||
/// Ok(())
|
||||
/// ```
|
||||
pub trait Trait {}
|
||||
```
|
||||
|
|
@ -590,10 +592,10 @@ The generated output (formatted) will look like this:
|
|||
|
||||
```json
|
||||
{
|
||||
"format_version": 1,
|
||||
"format_version": 2,
|
||||
"doctests": [
|
||||
{
|
||||
"file": "foo.rs",
|
||||
"file": "src/lib.rs",
|
||||
"line": 1,
|
||||
"doctest_attributes": {
|
||||
"original": "",
|
||||
|
|
@ -609,9 +611,17 @@ The generated output (formatted) will look like this:
|
|||
"added_css_classes": [],
|
||||
"unknown": []
|
||||
},
|
||||
"original_code": "let x = 12;",
|
||||
"doctest_code": "#![allow(unused)]\nfn main() {\nlet x = 12;\n}",
|
||||
"name": "foo.rs - Trait (line 1)"
|
||||
"original_code": "#![allow(dead_code)]\nlet x = 12;\nOk(())",
|
||||
"doctest_code": {
|
||||
"crate_level": "#![allow(unused)]\n#![allow(dead_code)]\n\n",
|
||||
"code": "let x = 12;\nOk(())",
|
||||
"wrapper": {
|
||||
"before": "fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
|
||||
"after": "\n} _inner().unwrap() }",
|
||||
"returns_result": true
|
||||
}
|
||||
},
|
||||
"name": "src/lib.rs - (line 1)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -624,6 +634,10 @@ The generated output (formatted) will look like this:
|
|||
* `doctest_attributes` contains computed information about the attributes used on the doctests. For more information about doctest attributes, take a look [here](write-documentation/documentation-tests.html#attributes).
|
||||
* `original_code` is the code as written in the source code before rustdoc modifies it.
|
||||
* `doctest_code` is the code modified by rustdoc that will be run. If there is a fatal syntax error, this field will not be present.
|
||||
* `crate_level` is the crate level code (like attributes or `extern crate`) that will be added at the top-level of the generated doctest.
|
||||
* `code` is "naked" doctest without anything from `crate_level` and `wrapper` content.
|
||||
* `wrapper` contains extra code that will be added before and after `code`.
|
||||
* `returns_result` is a boolean. If `true`, it means that the doctest returns a `Result` type.
|
||||
* `name` is the name generated by rustdoc which represents this doctest.
|
||||
|
||||
### html
|
||||
|
|
|
|||
|
|
@ -1,175 +0,0 @@
|
|||
# `unsized_locals`
|
||||
|
||||
The tracking issue for this feature is: [#48055]
|
||||
|
||||
[#48055]: https://github.com/rust-lang/rust/issues/48055
|
||||
|
||||
------------------------
|
||||
|
||||
This implements [RFC1909]. When turned on, you can have unsized arguments and locals:
|
||||
|
||||
[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md
|
||||
|
||||
```rust
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
fn main() {
|
||||
let x: Box<dyn Any> = Box::new(42);
|
||||
let x: dyn Any = *x;
|
||||
// ^ unsized local variable
|
||||
// ^^ unsized temporary
|
||||
foo(x);
|
||||
}
|
||||
|
||||
fn foo(_: dyn Any) {}
|
||||
// ^^^^^^ unsized argument
|
||||
```
|
||||
|
||||
The RFC still forbids the following unsized expressions:
|
||||
|
||||
```rust,compile_fail
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
struct MyStruct<T: ?Sized> {
|
||||
content: T,
|
||||
}
|
||||
|
||||
struct MyTupleStruct<T: ?Sized>(T);
|
||||
|
||||
fn answer() -> Box<dyn Any> {
|
||||
Box::new(42)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// You CANNOT have unsized statics.
|
||||
static X: dyn Any = *answer(); // ERROR
|
||||
const Y: dyn Any = *answer(); // ERROR
|
||||
|
||||
// You CANNOT have struct initialized unsized.
|
||||
MyStruct { content: *answer() }; // ERROR
|
||||
MyTupleStruct(*answer()); // ERROR
|
||||
(42, *answer()); // ERROR
|
||||
|
||||
// You CANNOT have unsized return types.
|
||||
fn my_function() -> dyn Any { *answer() } // ERROR
|
||||
|
||||
// You CAN have unsized local variables...
|
||||
let mut x: dyn Any = *answer(); // OK
|
||||
// ...but you CANNOT reassign to them.
|
||||
x = *answer(); // ERROR
|
||||
|
||||
// You CANNOT even initialize them separately.
|
||||
let y: dyn Any; // OK
|
||||
y = *answer(); // ERROR
|
||||
|
||||
// Not mentioned in the RFC, but by-move captured variables are also Sized.
|
||||
let x: dyn Any = *answer();
|
||||
(move || { // ERROR
|
||||
let y = x;
|
||||
})();
|
||||
|
||||
// You CAN create a closure with unsized arguments,
|
||||
// but you CANNOT call it.
|
||||
// This is an implementation detail and may be changed in the future.
|
||||
let f = |x: dyn Any| {};
|
||||
f(*answer()); // ERROR
|
||||
}
|
||||
```
|
||||
|
||||
## By-value trait objects
|
||||
|
||||
With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.
|
||||
|
||||
```rust
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
trait Foo {
|
||||
fn foo(self) {}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Foo for T {}
|
||||
|
||||
fn main() {
|
||||
let slice: Box<[i32]> = Box::new([1, 2, 3]);
|
||||
<[i32] as Foo>::foo(*slice);
|
||||
}
|
||||
```
|
||||
|
||||
And `Foo` will also be object-safe.
|
||||
|
||||
```rust
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
trait Foo {
|
||||
fn foo(self) {}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Foo for T {}
|
||||
|
||||
fn main () {
|
||||
let slice: Box<dyn Foo> = Box::new([1, 2, 3]);
|
||||
// doesn't compile yet
|
||||
<dyn Foo as Foo>::foo(*slice);
|
||||
}
|
||||
```
|
||||
|
||||
One of the objectives of this feature is to allow `Box<dyn FnOnce>`.
|
||||
|
||||
## Variable length arrays
|
||||
|
||||
The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`.
|
||||
|
||||
```rust,ignore (not-yet-implemented)
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
fn mergesort<T: Ord>(a: &mut [T]) {
|
||||
let mut tmp = [T; dyn a.len()];
|
||||
// ...
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut a = [3, 1, 5, 6];
|
||||
mergesort(&mut a);
|
||||
assert_eq!(a, [1, 3, 5, 6]);
|
||||
}
|
||||
```
|
||||
|
||||
VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`.
|
||||
|
||||
## Advisory on stack usage
|
||||
|
||||
It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are:
|
||||
|
||||
- When you need a by-value trait objects.
|
||||
- When you really need a fast allocation of small temporary arrays.
|
||||
|
||||
Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code
|
||||
|
||||
```rust
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
fn main() {
|
||||
let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
|
||||
let _x = {{{{{{{{{{*x}}}}}}}}}};
|
||||
}
|
||||
```
|
||||
|
||||
and the code
|
||||
|
||||
```rust
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
fn main() {
|
||||
for _ in 0..10 {
|
||||
let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
|
||||
let _x = *x;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
will unnecessarily extend the stack frame.
|
||||
|
|
@ -1053,14 +1053,14 @@ fn doctest_run_fn(
|
|||
let report_unused_externs = |uext| {
|
||||
unused_externs.lock().unwrap().push(uext);
|
||||
};
|
||||
let (full_test_code, full_test_line_offset) = doctest.generate_unique_doctest(
|
||||
let (wrapped, full_test_line_offset) = doctest.generate_unique_doctest(
|
||||
&scraped_test.text,
|
||||
scraped_test.langstr.test_harness,
|
||||
&global_opts,
|
||||
Some(&global_opts.crate_name),
|
||||
);
|
||||
let runnable_test = RunnableDocTest {
|
||||
full_test_code,
|
||||
full_test_code: wrapped.to_string(),
|
||||
full_test_line_offset,
|
||||
test_opts,
|
||||
global_opts,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
//! This module contains the logic to extract doctests and output a JSON containing this
|
||||
//! information.
|
||||
|
||||
use rustc_span::edition::Edition;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::make::DocTestWrapResult;
|
||||
use super::{BuildDocTestBuilder, ScrapedDocTest};
|
||||
use crate::config::Options as RustdocOptions;
|
||||
use crate::html::markdown;
|
||||
|
|
@ -14,7 +16,7 @@ use crate::html::markdown;
|
|||
/// This integer is incremented with every breaking change to the API,
|
||||
/// and is returned along with the JSON blob into the `format_version` root field.
|
||||
/// Consuming code should assert that this value matches the format version(s) that it supports.
|
||||
const FORMAT_VERSION: u32 = 1;
|
||||
const FORMAT_VERSION: u32 = 2;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct ExtractedDocTests {
|
||||
|
|
@ -34,7 +36,16 @@ impl ExtractedDocTests {
|
|||
options: &RustdocOptions,
|
||||
) {
|
||||
let edition = scraped_test.edition(options);
|
||||
self.add_test_with_edition(scraped_test, opts, edition)
|
||||
}
|
||||
|
||||
/// This method is used by unit tests to not have to provide a `RustdocOptions`.
|
||||
pub(crate) fn add_test_with_edition(
|
||||
&mut self,
|
||||
scraped_test: ScrapedDocTest,
|
||||
opts: &super::GlobalTestOptions,
|
||||
edition: Edition,
|
||||
) {
|
||||
let ScrapedDocTest { filename, line, langstr, text, name, global_crate_attrs, .. } =
|
||||
scraped_test;
|
||||
|
||||
|
|
@ -44,8 +55,7 @@ impl ExtractedDocTests {
|
|||
.edition(edition)
|
||||
.lang_str(&langstr)
|
||||
.build(None);
|
||||
|
||||
let (full_test_code, size) = doctest.generate_unique_doctest(
|
||||
let (wrapped, _size) = doctest.generate_unique_doctest(
|
||||
&text,
|
||||
langstr.test_harness,
|
||||
opts,
|
||||
|
|
@ -55,11 +65,46 @@ impl ExtractedDocTests {
|
|||
file: filename.prefer_remapped_unconditionaly().to_string(),
|
||||
line,
|
||||
doctest_attributes: langstr.into(),
|
||||
doctest_code: if size != 0 { Some(full_test_code) } else { None },
|
||||
doctest_code: match wrapped {
|
||||
DocTestWrapResult::Valid { crate_level_code, wrapper, code } => Some(DocTest {
|
||||
crate_level: crate_level_code,
|
||||
code,
|
||||
wrapper: wrapper.map(
|
||||
|super::make::WrapperInfo { before, after, returns_result, .. }| {
|
||||
WrapperInfo { before, after, returns_result }
|
||||
},
|
||||
),
|
||||
}),
|
||||
DocTestWrapResult::SyntaxError { .. } => None,
|
||||
},
|
||||
original_code: text,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn doctests(&self) -> &[ExtractedDocTest] {
|
||||
&self.doctests
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct WrapperInfo {
|
||||
before: String,
|
||||
after: String,
|
||||
returns_result: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct DocTest {
|
||||
crate_level: String,
|
||||
code: String,
|
||||
/// This field can be `None` if one of the following conditions is true:
|
||||
///
|
||||
/// * The doctest's codeblock has the `test_harness` attribute.
|
||||
/// * The doctest has a `main` function.
|
||||
/// * The doctest has the `![no_std]` attribute.
|
||||
pub(crate) wrapper: Option<WrapperInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
@ -69,7 +114,7 @@ pub(crate) struct ExtractedDocTest {
|
|||
doctest_attributes: LangString,
|
||||
original_code: String,
|
||||
/// `None` if the code syntax is invalid.
|
||||
doctest_code: Option<String>,
|
||||
pub(crate) doctest_code: Option<DocTest>,
|
||||
name: String,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,6 +196,80 @@ pub(crate) struct DocTestBuilder {
|
|||
pub(crate) can_be_merged: bool,
|
||||
}
|
||||
|
||||
/// Contains needed information for doctest to be correctly generated with expected "wrapping".
|
||||
pub(crate) struct WrapperInfo {
|
||||
pub(crate) before: String,
|
||||
pub(crate) after: String,
|
||||
pub(crate) returns_result: bool,
|
||||
insert_indent_space: bool,
|
||||
}
|
||||
|
||||
impl WrapperInfo {
|
||||
fn len(&self) -> usize {
|
||||
self.before.len() + self.after.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains a doctest information. Can be converted into code with the `to_string()` method.
|
||||
pub(crate) enum DocTestWrapResult {
|
||||
Valid {
|
||||
crate_level_code: String,
|
||||
/// This field can be `None` if one of the following conditions is true:
|
||||
///
|
||||
/// * The doctest's codeblock has the `test_harness` attribute.
|
||||
/// * The doctest has a `main` function.
|
||||
/// * The doctest has the `![no_std]` attribute.
|
||||
wrapper: Option<WrapperInfo>,
|
||||
/// Contains the doctest processed code without the wrappers (which are stored in the
|
||||
/// `wrapper` field).
|
||||
code: String,
|
||||
},
|
||||
/// Contains the original source code.
|
||||
SyntaxError(String),
|
||||
}
|
||||
|
||||
impl std::string::ToString for DocTestWrapResult {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::SyntaxError(s) => s.clone(),
|
||||
Self::Valid { crate_level_code, wrapper, code } => {
|
||||
let mut prog_len = code.len() + crate_level_code.len();
|
||||
if let Some(wrapper) = wrapper {
|
||||
prog_len += wrapper.len();
|
||||
if wrapper.insert_indent_space {
|
||||
prog_len += code.lines().count() * 4;
|
||||
}
|
||||
}
|
||||
let mut prog = String::with_capacity(prog_len);
|
||||
|
||||
prog.push_str(crate_level_code);
|
||||
if let Some(wrapper) = wrapper {
|
||||
prog.push_str(&wrapper.before);
|
||||
|
||||
// add extra 4 spaces for each line to offset the code block
|
||||
if wrapper.insert_indent_space {
|
||||
write!(
|
||||
prog,
|
||||
"{}",
|
||||
fmt::from_fn(|f| code
|
||||
.lines()
|
||||
.map(|line| fmt::from_fn(move |f| write!(f, " {line}")))
|
||||
.joined("\n", f))
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
prog.push_str(code);
|
||||
}
|
||||
prog.push_str(&wrapper.after);
|
||||
} else {
|
||||
prog.push_str(code);
|
||||
}
|
||||
prog
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DocTestBuilder {
|
||||
fn invalid(
|
||||
global_crate_attrs: Vec<String>,
|
||||
|
|
@ -228,50 +302,49 @@ impl DocTestBuilder {
|
|||
dont_insert_main: bool,
|
||||
opts: &GlobalTestOptions,
|
||||
crate_name: Option<&str>,
|
||||
) -> (String, usize) {
|
||||
) -> (DocTestWrapResult, usize) {
|
||||
if self.invalid_ast {
|
||||
// If the AST failed to compile, no need to go generate a complete doctest, the error
|
||||
// will be better this way.
|
||||
debug!("invalid AST:\n{test_code}");
|
||||
return (test_code.to_string(), 0);
|
||||
return (DocTestWrapResult::SyntaxError(test_code.to_string()), 0);
|
||||
}
|
||||
let mut line_offset = 0;
|
||||
let mut prog = String::new();
|
||||
let everything_else = self.everything_else.trim();
|
||||
|
||||
let mut crate_level_code = String::new();
|
||||
let processed_code = self.everything_else.trim();
|
||||
if self.global_crate_attrs.is_empty() {
|
||||
// If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some
|
||||
// lints that are commonly triggered in doctests. The crate-level test attributes are
|
||||
// commonly used to make tests fail in case they trigger warnings, so having this there in
|
||||
// that case may cause some tests to pass when they shouldn't have.
|
||||
prog.push_str("#![allow(unused)]\n");
|
||||
crate_level_code.push_str("#![allow(unused)]\n");
|
||||
line_offset += 1;
|
||||
}
|
||||
|
||||
// Next, any attributes that came from #![doc(test(attr(...)))].
|
||||
for attr in &self.global_crate_attrs {
|
||||
prog.push_str(&format!("#![{attr}]\n"));
|
||||
crate_level_code.push_str(&format!("#![{attr}]\n"));
|
||||
line_offset += 1;
|
||||
}
|
||||
|
||||
// Now push any outer attributes from the example, assuming they
|
||||
// are intended to be crate attributes.
|
||||
if !self.crate_attrs.is_empty() {
|
||||
prog.push_str(&self.crate_attrs);
|
||||
crate_level_code.push_str(&self.crate_attrs);
|
||||
if !self.crate_attrs.ends_with('\n') {
|
||||
prog.push('\n');
|
||||
crate_level_code.push('\n');
|
||||
}
|
||||
}
|
||||
if !self.maybe_crate_attrs.is_empty() {
|
||||
prog.push_str(&self.maybe_crate_attrs);
|
||||
crate_level_code.push_str(&self.maybe_crate_attrs);
|
||||
if !self.maybe_crate_attrs.ends_with('\n') {
|
||||
prog.push('\n');
|
||||
crate_level_code.push('\n');
|
||||
}
|
||||
}
|
||||
if !self.crates.is_empty() {
|
||||
prog.push_str(&self.crates);
|
||||
crate_level_code.push_str(&self.crates);
|
||||
if !self.crates.ends_with('\n') {
|
||||
prog.push('\n');
|
||||
crate_level_code.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,17 +362,20 @@ impl DocTestBuilder {
|
|||
{
|
||||
// rustdoc implicitly inserts an `extern crate` item for the own crate
|
||||
// which may be unused, so we need to allow the lint.
|
||||
prog.push_str("#[allow(unused_extern_crates)]\n");
|
||||
crate_level_code.push_str("#[allow(unused_extern_crates)]\n");
|
||||
|
||||
prog.push_str(&format!("extern crate r#{crate_name};\n"));
|
||||
crate_level_code.push_str(&format!("extern crate r#{crate_name};\n"));
|
||||
line_offset += 1;
|
||||
}
|
||||
|
||||
// FIXME: This code cannot yet handle no_std test cases yet
|
||||
if dont_insert_main || self.has_main_fn || prog.contains("![no_std]") {
|
||||
prog.push_str(everything_else);
|
||||
let wrapper = if dont_insert_main
|
||||
|| self.has_main_fn
|
||||
|| crate_level_code.contains("![no_std]")
|
||||
{
|
||||
None
|
||||
} else {
|
||||
let returns_result = everything_else.ends_with("(())");
|
||||
let returns_result = processed_code.ends_with("(())");
|
||||
// Give each doctest main function a unique name.
|
||||
// This is for example needed for the tooling around `-C instrument-coverage`.
|
||||
let inner_fn_name = if let Some(ref test_id) = self.test_id {
|
||||
|
|
@ -333,28 +409,22 @@ impl DocTestBuilder {
|
|||
// /// ``` <- end of the inner main
|
||||
line_offset += 1;
|
||||
|
||||
prog.push_str(&main_pre);
|
||||
Some(WrapperInfo {
|
||||
before: main_pre,
|
||||
after: main_post,
|
||||
returns_result,
|
||||
insert_indent_space: opts.insert_indent_space,
|
||||
})
|
||||
};
|
||||
|
||||
// add extra 4 spaces for each line to offset the code block
|
||||
if opts.insert_indent_space {
|
||||
write!(
|
||||
prog,
|
||||
"{}",
|
||||
fmt::from_fn(|f| everything_else
|
||||
.lines()
|
||||
.map(|line| fmt::from_fn(move |f| write!(f, " {line}")))
|
||||
.joined("\n", f))
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
prog.push_str(everything_else);
|
||||
};
|
||||
prog.push_str(&main_post);
|
||||
}
|
||||
|
||||
debug!("final doctest:\n{prog}");
|
||||
|
||||
(prog, line_offset)
|
||||
(
|
||||
DocTestWrapResult::Valid {
|
||||
code: processed_code.to_string(),
|
||||
wrapper,
|
||||
crate_level_code,
|
||||
},
|
||||
line_offset,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use super::{BuildDocTestBuilder, GlobalTestOptions};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{DUMMY_SP, FileName};
|
||||
|
||||
use super::extracted::ExtractedDocTests;
|
||||
use super::{BuildDocTestBuilder, GlobalTestOptions, ScrapedDocTest};
|
||||
use crate::html::markdown::LangString;
|
||||
|
||||
fn make_test(
|
||||
test_code: &str,
|
||||
|
|
@ -19,9 +24,9 @@ fn make_test(
|
|||
builder = builder.test_id(test_id.to_string());
|
||||
}
|
||||
let doctest = builder.build(None);
|
||||
let (code, line_offset) =
|
||||
let (wrapped, line_offset) =
|
||||
doctest.generate_unique_doctest(test_code, dont_insert_main, opts, crate_name);
|
||||
(code, line_offset)
|
||||
(wrapped.to_string(), line_offset)
|
||||
}
|
||||
|
||||
/// Default [`GlobalTestOptions`] for these unit tests.
|
||||
|
|
@ -461,3 +466,51 @@ pub mod outer_module {
|
|||
let (output, len) = make_test(input, None, false, &opts, Vec::new(), None);
|
||||
assert_eq!((output, len), (expected, 2));
|
||||
}
|
||||
|
||||
fn get_extracted_doctests(code: &str) -> ExtractedDocTests {
|
||||
let opts = default_global_opts("");
|
||||
let mut extractor = ExtractedDocTests::new();
|
||||
extractor.add_test_with_edition(
|
||||
ScrapedDocTest::new(
|
||||
FileName::Custom(String::new()),
|
||||
0,
|
||||
Vec::new(),
|
||||
LangString::default(),
|
||||
code.to_string(),
|
||||
DUMMY_SP,
|
||||
Vec::new(),
|
||||
),
|
||||
&opts,
|
||||
Edition::Edition2018,
|
||||
);
|
||||
extractor
|
||||
}
|
||||
|
||||
// Test that `extracted::DocTest::wrapper` is `None` if the doctest has a `main` function.
|
||||
#[test]
|
||||
fn test_extracted_doctest_wrapper_field() {
|
||||
let extractor = get_extracted_doctests("fn main() {}");
|
||||
|
||||
assert_eq!(extractor.doctests().len(), 1);
|
||||
let doctest_code = extractor.doctests()[0].doctest_code.as_ref().unwrap();
|
||||
assert!(doctest_code.wrapper.is_none());
|
||||
}
|
||||
|
||||
// Test that `ExtractedDocTest::doctest_code` is `None` if the doctest has syntax error.
|
||||
#[test]
|
||||
fn test_extracted_doctest_doctest_code_field() {
|
||||
let extractor = get_extracted_doctests("let x +=");
|
||||
|
||||
assert_eq!(extractor.doctests().len(), 1);
|
||||
assert!(extractor.doctests()[0].doctest_code.is_none());
|
||||
}
|
||||
|
||||
// Test that `extracted::DocTest::wrapper` is `Some` if the doctest needs wrapping.
|
||||
#[test]
|
||||
fn test_extracted_doctest_wrapper_field_with_info() {
|
||||
let extractor = get_extracted_doctests("let x = 12;");
|
||||
|
||||
assert_eq!(extractor.doctests().len(), 1);
|
||||
let doctest_code = extractor.doctests()[0].doctest_code.as_ref().unwrap();
|
||||
assert!(doctest_code.wrapper.is_some());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -307,7 +307,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
|
|||
builder = builder.crate_name(krate);
|
||||
}
|
||||
let doctest = builder.build(None);
|
||||
let (test, _) = doctest.generate_unique_doctest(&test, false, &opts, krate);
|
||||
let (wrapped, _) = doctest.generate_unique_doctest(&test, false, &opts, krate);
|
||||
let test = wrapped.to_string();
|
||||
let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" };
|
||||
|
||||
let test_escaped = small_url_encode(test);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
//@ normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR"
|
||||
//@ normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR"
|
||||
#![allow(unused, incomplete_features)]
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::large_stack_frames)]
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
use std::hint::black_box;
|
||||
|
||||
|
|
@ -11,11 +10,6 @@ fn generic<T: Default>() {
|
|||
black_box(&x);
|
||||
}
|
||||
|
||||
fn unsized_local() {
|
||||
let x: dyn std::fmt::Display = *(Box::new(1) as Box<dyn std::fmt::Display>);
|
||||
black_box(&x);
|
||||
}
|
||||
|
||||
struct ArrayDefault<const N: usize>([u8; N]);
|
||||
|
||||
impl<const N: usize> Default for ArrayDefault<N> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: this function may allocate 250$PTR bytes on the stack
|
||||
--> tests/ui/large_stack_frames.rs:27:4
|
||||
--> tests/ui/large_stack_frames.rs:21:4
|
||||
|
|
||||
LL | fn many_small_arrays() {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -13,7 +13,7 @@ LL | let x5 = [0u8; 500_000];
|
|||
= help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]`
|
||||
|
||||
error: this function may allocate 1000000 bytes on the stack
|
||||
--> tests/ui/large_stack_frames.rs:38:4
|
||||
--> tests/ui/large_stack_frames.rs:32:4
|
||||
|
|
||||
LL | fn large_return_value() -> ArrayDefault<1_000_000> {
|
||||
| ^^^^^^^^^^^^^^^^^^ ----------------------- this is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>`
|
||||
|
|
@ -21,7 +21,7 @@ LL | fn large_return_value() -> ArrayDefault<1_000_000> {
|
|||
= note: 1000000 bytes is larger than Clippy's configured `stack-size-threshold` of 512000
|
||||
|
||||
error: this function may allocate 100$PTR bytes on the stack
|
||||
--> tests/ui/large_stack_frames.rs:44:4
|
||||
--> tests/ui/large_stack_frames.rs:38:4
|
||||
|
|
||||
LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) {
|
||||
| ^^^^^^^^^^^^ - `x` is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>`
|
||||
|
|
@ -29,7 +29,7 @@ LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) {
|
|||
= note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000
|
||||
|
||||
error: this function may allocate 100$PTR bytes on the stack
|
||||
--> tests/ui/large_stack_frames.rs:51:13
|
||||
--> tests/ui/large_stack_frames.rs:45:13
|
||||
|
|
||||
LL | let f = || black_box(&[0u8; 1_000_000]);
|
||||
| ^^^^^^^^^^^^^^----------------^
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
#![feature(unsized_locals)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn main() {
|
||||
pub trait Foo {
|
||||
fn foo(self) -> String;
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl Foo for A {
|
||||
fn foo(self) -> String {
|
||||
format!("hello")
|
||||
}
|
||||
}
|
||||
|
||||
let x = *(Box::new(A) as Box<dyn Foo>); //~ERROR: unsized locals are not supported
|
||||
assert_eq!(x.foo(), format!("hello"));
|
||||
|
||||
// I'm not sure whether we want this to work
|
||||
let x = Box::new(A) as Box<dyn Foo>;
|
||||
assert_eq!(x.foo(), format!("hello"));
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
error: unsupported operation: unsized locals are not supported
|
||||
--> tests/fail/unsized-local.rs:LL:CC
|
||||
|
|
||||
LL | let x = *(Box::new(A) as Box<dyn Foo>);
|
||||
| ^ unsized locals are not supported
|
||||
|
|
||||
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at tests/fail/unsized-local.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -754,7 +754,6 @@ ui/consts/issue-46553.rs
|
|||
ui/consts/issue-47789.rs
|
||||
ui/consts/issue-50439.rs
|
||||
ui/consts/issue-52023-array-size-pointer-cast.rs
|
||||
ui/consts/issue-54224.rs
|
||||
ui/consts/issue-54348.rs
|
||||
ui/consts/issue-54387.rs
|
||||
ui/consts/issue-54582.rs
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
#![allow(internal_features)]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
// CHECK-LABEL: emptyfn:
|
||||
#[no_mangle]
|
||||
|
|
@ -357,27 +357,3 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
|
|||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// CHECK-LABEL: unsized_local
|
||||
#[no_mangle]
|
||||
pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) {
|
||||
let n = if l { 1 } else { 2 };
|
||||
let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from
|
||||
f(&mut a);
|
||||
|
||||
// This function allocates a slice as a local variable in its stack
|
||||
// frame. Since the size is not a compile-time constant, an array
|
||||
// alloca is required, and the function is protected by both the
|
||||
// `strong` and `basic` heuristic.
|
||||
|
||||
// We should have a __security_check_cookie call in `all`, `strong` and `basic` modes but
|
||||
// LLVM does not support generating stack protectors in functions with funclet
|
||||
// based EH personalities.
|
||||
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// basic-NOT: __security_check_cookie
|
||||
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@
|
|||
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
// CHECK-LABEL: emptyfn:
|
||||
#[no_mangle]
|
||||
|
|
@ -365,27 +364,3 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
|
|||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// CHECK-LABEL: unsized_local
|
||||
#[no_mangle]
|
||||
pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) {
|
||||
let n = if l { 1 } else { 2 };
|
||||
let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from
|
||||
f(&mut a);
|
||||
|
||||
// This function allocates a slice as a local variable in its stack
|
||||
// frame. Since the size is not a compile-time constant, an array
|
||||
// alloca is required, and the function is protected by both the
|
||||
// `strong` and `basic` heuristic.
|
||||
|
||||
// We should have a __security_check_cookie call in `all`, `strong` and `basic` modes but
|
||||
// LLVM does not support generating stack protectors in functions with funclet
|
||||
// based EH personalities.
|
||||
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// basic-NOT: __security_check_cookie
|
||||
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
// See comments on https://github.com/rust-lang/rust/issues/114903.
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
#![allow(internal_features)]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
// CHECK-LABEL: emptyfn{{:|\[}}
|
||||
#[no_mangle]
|
||||
|
|
@ -343,22 +343,3 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
|
|||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// CHECK-LABEL: unsized_local{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) {
|
||||
let n = if l { 1 } else { 2 };
|
||||
let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from
|
||||
f(&mut a);
|
||||
|
||||
// This function allocates a slice as a local variable in its stack
|
||||
// frame. Since the size is not a compile-time constant, an array
|
||||
// alloca is required, and the function is protected by both the
|
||||
// `strong` and `basic` heuristic.
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// basic: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
#![allow(internal_features)]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::hint;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
// CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]]
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
//@ known-bug: #79409
|
||||
|
||||
#![feature(extern_types)]
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
extern {
|
||||
type Device;
|
||||
}
|
||||
|
||||
unsafe fn make_device() -> Box<Device> {
|
||||
Box::from_raw(0 as *mut _)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let d: Device = unsafe { *make_device() };
|
||||
}
|
||||
11
tests/rustdoc-ui/extract-doctests-result.rs
Normal file
11
tests/rustdoc-ui/extract-doctests-result.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Test to ensure that it generates expected output for `--output-format=doctest` command-line
|
||||
// flag.
|
||||
|
||||
//@ compile-flags:-Z unstable-options --output-format=doctest
|
||||
//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
|
||||
//@ check-pass
|
||||
|
||||
//! ```
|
||||
//! let x = 12;
|
||||
//! Ok(())
|
||||
//! ```
|
||||
1
tests/rustdoc-ui/extract-doctests-result.stdout
Normal file
1
tests/rustdoc-ui/extract-doctests-result.stdout
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests-result.rs","line":8,"doctest_attributes":{"original":"","should_panic":false,"no_run":false,"ignore":"None","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nOk(())","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nOk(())","wrapper":{"before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n","after":"\n} _inner().unwrap() }","returns_result":true}},"name":"$DIR/extract-doctests-result.rs - (line 8)"}]}
|
||||
|
|
@ -1 +1 @@
|
|||
{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]}
|
||||
{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nlet y = 14;","wrapper":{"before":"fn main() {\n","after":"\n}","returns_result":false}},"name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]}
|
||||
22
tests/ui/associated-types/associated-type-call.fixed
Normal file
22
tests/ui/associated-types/associated-type-call.fixed
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// issue: <https://github.com/rust-lang/rust/issues/142473>
|
||||
//
|
||||
//@ run-rustfix
|
||||
#![allow(unused)]
|
||||
struct T();
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
|
||||
fn f();
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
type Assoc = T;
|
||||
|
||||
fn f() {
|
||||
T();
|
||||
//~^ ERROR no associated item named `Assoc` found for unit type `()` in the current scope
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
22
tests/ui/associated-types/associated-type-call.rs
Normal file
22
tests/ui/associated-types/associated-type-call.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// issue: <https://github.com/rust-lang/rust/issues/142473>
|
||||
//
|
||||
//@ run-rustfix
|
||||
#![allow(unused)]
|
||||
struct T();
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
|
||||
fn f();
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
type Assoc = T;
|
||||
|
||||
fn f() {
|
||||
<Self>::Assoc();
|
||||
//~^ ERROR no associated item named `Assoc` found for unit type `()` in the current scope
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
15
tests/ui/associated-types/associated-type-call.stderr
Normal file
15
tests/ui/associated-types/associated-type-call.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
error[E0599]: no associated item named `Assoc` found for unit type `()` in the current scope
|
||||
--> $DIR/associated-type-call.rs:17:17
|
||||
|
|
||||
LL | <Self>::Assoc();
|
||||
| ^^^^^ associated item not found in `()`
|
||||
|
|
||||
help: to construct a value of type `T`, use the explicit path
|
||||
|
|
||||
LL - <Self>::Assoc();
|
||||
LL + T();
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
||||
|
|
@ -6,7 +6,6 @@ LL | let x = t.get();
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `<T as Get>::Value`
|
||||
= note: all local variables must have a statically known size
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn foo<T:Get>(t: T) where <T as Get>::Value: Sized {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
//@ edition: 2021
|
||||
|
||||
#![feature(unsized_fn_params, unsized_locals)]
|
||||
//~^ WARN the feature `unsized_locals` is incomplete
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
|
||||
//~^ ERROR the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
|
||||
//~^ ERROR the size for values of type `dyn Future<Output = T> + Unpin` cannot be known at compilation time
|
||||
(&mut f).await
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/awaiting-unsized-param.rs:3:31
|
||||
|
|
||||
LL | #![feature(unsized_fn_params, unsized_locals)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time
|
||||
--> $DIR/awaiting-unsized-param.rs:8:17
|
||||
error[E0277]: the size for values of type `dyn Future<Output = T> + Unpin` cannot be known at compilation time
|
||||
--> $DIR/awaiting-unsized-param.rs:7:17
|
||||
|
|
||||
LL | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T {
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + Unpin + 'static)`
|
||||
= note: all values captured by value by a closure must have a statically known size
|
||||
= help: the trait `Sized` is not implemented for `dyn Future<Output = T> + Unpin`
|
||||
= note: all local variables must have a statically known size
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
//@ edition: 2021
|
||||
|
||||
#![feature(unsized_locals)]
|
||||
//~^ WARN the feature `unsized_locals` is incomplete
|
||||
|
||||
async fn f() {}
|
||||
|
||||
async fn g(x: Box<dyn std::fmt::Display>) {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/unsized-across-await.rs:3:12
|
||||
|
|
||||
LL | #![feature(unsized_locals)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time
|
||||
--> $DIR/unsized-across-await.rs:9:9
|
||||
--> $DIR/unsized-across-await.rs:6:9
|
||||
|
|
||||
LL | let _x = *x;
|
||||
| ^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `dyn std::fmt::Display`
|
||||
= note: all values live across `await` must have a statically known size
|
||||
= note: all local variables must have a statically known size
|
||||
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
|
||||
|
|
||||
LL - let _x = *x;
|
||||
LL + let _x = x;
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
//@ only-x86_64
|
||||
|
||||
fn efiapi(f: extern "efiapi" fn(usize, ...)) {
|
||||
//~^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
//~^ ERROR: unstable
|
||||
f(22, 44);
|
||||
}
|
||||
fn sysv(f: extern "sysv64" fn(usize, ...)) {
|
||||
//~^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
//~^ ERROR: unstable
|
||||
f(22, 44);
|
||||
}
|
||||
fn win(f: extern "win64" fn(usize, ...)) {
|
||||
//~^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
//~^ ERROR: unstable
|
||||
f(22, 44);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
error[E0658]: C-variadic functions with the "efiapi" calling convention are unstable
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14
|
||||
|
|
||||
LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
|
||||
|
|
@ -8,7 +8,7 @@ LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
|
|||
= help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
error[E0658]: C-variadic functions with the "sysv64" calling convention are unstable
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:7:12
|
||||
|
|
||||
LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
|
||||
|
|
@ -18,7 +18,7 @@ LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
|
|||
= help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
error[E0658]: C-variadic functions with the "win64" calling convention are unstable
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11
|
||||
|
|
||||
LL | fn win(f: extern "win64" fn(usize, ...)) {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ use minicore::*;
|
|||
|
||||
extern "stdcall" {
|
||||
fn printf(_: *const u8, ...);
|
||||
//~^ ERROR: C-variadic function must have a compatible calling convention,
|
||||
// like C, cdecl, win64, sysv64 or efiapi
|
||||
//~^ ERROR: C-variadic functions with the "stdcall" calling convention are not supported
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`
|
||||
error[E0045]: C-variadic functions with the "stdcall" calling convention are not supported
|
||||
--> $DIR/variadic-ffi-1.rs:11:5
|
||||
|
|
||||
LL | fn printf(_: *const u8, ...);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
|
||||
|
||||
error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied
|
||||
--> $DIR/variadic-ffi-1.rs:24:9
|
||||
--> $DIR/variadic-ffi-1.rs:23:9
|
||||
|
|
||||
LL | foo();
|
||||
| ^^^-- two arguments of type `isize` and `u8` are missing
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/variadic-ffi-1.rs:17:8
|
||||
--> $DIR/variadic-ffi-1.rs:16:8
|
||||
|
|
||||
LL | fn foo(f: isize, x: u8, ...);
|
||||
| ^^^ - -
|
||||
|
|
@ -21,13 +21,13 @@ LL | foo(/* isize */, /* u8 */);
|
|||
| +++++++++++++++++++++
|
||||
|
||||
error[E0060]: this function takes at least 2 arguments but 1 argument was supplied
|
||||
--> $DIR/variadic-ffi-1.rs:25:9
|
||||
--> $DIR/variadic-ffi-1.rs:24:9
|
||||
|
|
||||
LL | foo(1);
|
||||
| ^^^--- argument #2 of type `u8` is missing
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/variadic-ffi-1.rs:17:8
|
||||
--> $DIR/variadic-ffi-1.rs:16:8
|
||||
|
|
||||
LL | fn foo(f: isize, x: u8, ...);
|
||||
| ^^^ -
|
||||
|
|
@ -37,7 +37,7 @@ LL | foo(1, /* u8 */);
|
|||
| ++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/variadic-ffi-1.rs:27:56
|
||||
--> $DIR/variadic-ffi-1.rs:26:56
|
||||
|
|
||||
LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
|
||||
| ------------------------------------- ^^^ expected non-variadic fn, found variadic function
|
||||
|
|
@ -48,7 +48,7 @@ LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
|
|||
found fn item `unsafe extern "C" fn(_, _, ...) {foo}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/variadic-ffi-1.rs:28:54
|
||||
--> $DIR/variadic-ffi-1.rs:27:54
|
||||
|
|
||||
LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar;
|
||||
| ----------------------------------- ^^^ expected variadic fn, found non-variadic function
|
||||
|
|
@ -59,7 +59,7 @@ LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar;
|
|||
found fn item `extern "C" fn(_, _) {bar}`
|
||||
|
||||
error[E0617]: can't pass `f32` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:30:19
|
||||
--> $DIR/variadic-ffi-1.rs:29:19
|
||||
|
|
||||
LL | foo(1, 2, 3f32);
|
||||
| ^^^^
|
||||
|
|
@ -70,7 +70,7 @@ LL | foo(1, 2, 3f32 as c_double);
|
|||
| +++++++++++
|
||||
|
||||
error[E0617]: can't pass `bool` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:31:19
|
||||
--> $DIR/variadic-ffi-1.rs:30:19
|
||||
|
|
||||
LL | foo(1, 2, true);
|
||||
| ^^^^
|
||||
|
|
@ -81,7 +81,7 @@ LL | foo(1, 2, true as c_int);
|
|||
| ++++++++
|
||||
|
||||
error[E0617]: can't pass `i8` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:32:19
|
||||
--> $DIR/variadic-ffi-1.rs:31:19
|
||||
|
|
||||
LL | foo(1, 2, 1i8);
|
||||
| ^^^
|
||||
|
|
@ -92,7 +92,7 @@ LL | foo(1, 2, 1i8 as c_int);
|
|||
| ++++++++
|
||||
|
||||
error[E0617]: can't pass `u8` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:33:19
|
||||
--> $DIR/variadic-ffi-1.rs:32:19
|
||||
|
|
||||
LL | foo(1, 2, 1u8);
|
||||
| ^^^
|
||||
|
|
@ -103,7 +103,7 @@ LL | foo(1, 2, 1u8 as c_uint);
|
|||
| +++++++++
|
||||
|
||||
error[E0617]: can't pass `i16` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:34:19
|
||||
--> $DIR/variadic-ffi-1.rs:33:19
|
||||
|
|
||||
LL | foo(1, 2, 1i16);
|
||||
| ^^^^
|
||||
|
|
@ -114,7 +114,7 @@ LL | foo(1, 2, 1i16 as c_int);
|
|||
| ++++++++
|
||||
|
||||
error[E0617]: can't pass `u16` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:35:19
|
||||
--> $DIR/variadic-ffi-1.rs:34:19
|
||||
|
|
||||
LL | foo(1, 2, 1u16);
|
||||
| ^^^^
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#![feature(extended_varargs_abi_support)]
|
||||
|
||||
fn baz(f: extern "Rust" fn(usize, ...)) {
|
||||
//~^ ERROR: C-variadic function must have a compatible calling convention,
|
||||
// like C, cdecl, system, aapcs, win64, sysv64 or efiapi
|
||||
//~^ ERROR: C-variadic functions with the "Rust" calling convention are not supported
|
||||
f(22, 44);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`
|
||||
error[E0045]: C-variadic functions with the "Rust" calling convention are not supported
|
||||
--> $DIR/variadic-ffi-2.rs:3:11
|
||||
|
|
||||
LL | fn baz(f: extern "Rust" fn(usize, ...)) {
|
||||
|
|
|
|||
|
|
@ -38,4 +38,4 @@ type WithTransparentTraitObject =
|
|||
//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798]
|
||||
|
||||
type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...);
|
||||
//~^ ERROR C-variadic function must have a compatible calling convention, like `C`
|
||||
//~^ ERROR C-variadic functions with the "C-cmse-nonsecure-call" calling convention are not supported
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ LL | extern "C-cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTranspa
|
|||
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
|
||||
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
|
||||
|
||||
error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`
|
||||
error[E0045]: C-variadic functions with the "C-cmse-nonsecure-call" calling convention are not supported
|
||||
--> $DIR/generics.rs:40:20
|
||||
|
|
||||
LL | type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const B: *mut i32 = &mut 4; //~ ERROR mutable references are not allowed
|
|||
const B2: Option<&mut i32> = None;
|
||||
|
||||
// Not ok, can't prove that no mutable allocation ends up in final value
|
||||
const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR temporary value dropped while borrowed
|
||||
const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR mutable references are not allowed
|
||||
|
||||
const fn helper(x: &mut i32) -> Option<&mut i32> { Some(x) }
|
||||
const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed
|
||||
|
|
|
|||
|
|
@ -4,15 +4,11 @@ error[E0764]: mutable references are not allowed in the final value of constants
|
|||
LL | const B: *mut i32 = &mut 4;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/mut_ref_in_final.rs:21:40
|
||||
error[E0764]: mutable references are not allowed in the final value of constants
|
||||
--> $DIR/mut_ref_in_final.rs:21:35
|
||||
|
|
||||
LL | const B3: Option<&mut i32> = Some(&mut 42);
|
||||
| ----------^^-
|
||||
| | | |
|
||||
| | | temporary value is freed at the end of this statement
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| using this value as a constant requires that borrow lasts for `'static`
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/mut_ref_in_final.rs:24:42
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub const X: [u8; 3] = *b"ABC";
|
||||
pub const Y: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[X]);
|
||||
|
||||
|
||||
pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]);
|
||||
//~^ ERROR temporary value dropped while borrowed
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/issue-54224.rs:1:39
|
||||
|
|
||||
LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]);
|
||||
| ------^^^^^^^^^-
|
||||
| | | |
|
||||
| | | temporary value is freed at the end of this statement
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| using this value as a constant requires that borrow lasts for `'static`
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/issue-54224.rs:9:57
|
||||
|
|
||||
LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]);
|
||||
| ---------------^^^^^^^^^-
|
||||
| | | |
|
||||
| | | temporary value is freed at the end of this statement
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| using this value as a constant requires that borrow lasts for `'static`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0716`.
|
||||
|
|
@ -3,10 +3,11 @@
|
|||
#![allow(unconditional_panic)]
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::identity;
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
// We do not promote mutable references.
|
||||
static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed
|
||||
static mut TEST1: &mut [i32] = identity(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed
|
||||
|
||||
static mut TEST2: &'static mut [i32] = {
|
||||
let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:9:50
|
||||
--> $DIR/promote-not.rs:10:46
|
||||
|
|
||||
LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
|
||||
| ----------^^^^^^^^^-
|
||||
| | | |
|
||||
| | | temporary value is freed at the end of this statement
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| using this value as a static requires that borrow lasts for `'static`
|
||||
LL | static mut TEST1: &mut [i32] = identity(&mut [1, 2, 3]);
|
||||
| --------------^^^^^^^^^-
|
||||
| | | |
|
||||
| | | temporary value is freed at the end of this statement
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| using this value as a static requires that borrow lasts for `'static`
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:12:18
|
||||
--> $DIR/promote-not.rs:13:18
|
||||
|
|
||||
LL | let x = &mut [1,2,3];
|
||||
| ^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -19,7 +19,7 @@ LL | };
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:34:29
|
||||
--> $DIR/promote-not.rs:35:29
|
||||
|
|
||||
LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -29,7 +29,7 @@ LL | };
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:40:29
|
||||
--> $DIR/promote-not.rs:41:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
|
||||
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -39,7 +39,7 @@ LL | };
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0493]: destructor of `String` cannot be evaluated at compile-time
|
||||
--> $DIR/promote-not.rs:47:14
|
||||
--> $DIR/promote-not.rs:48:14
|
||||
|
|
||||
LL | let x = &String::new();
|
||||
| ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants
|
||||
|
|
@ -48,7 +48,7 @@ LL | };
|
|||
| - value is dropped here
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:59:33
|
||||
--> $DIR/promote-not.rs:60:33
|
||||
|
|
||||
LL | let _x: &'static u32 = &mk_panic();
|
||||
| ------------ ^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -58,7 +58,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:21:32
|
||||
--> $DIR/promote-not.rs:22:32
|
||||
|
|
||||
LL | let _x: &'static () = &foo();
|
||||
| ----------- ^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -68,7 +68,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:29:29
|
||||
--> $DIR/promote-not.rs:30:29
|
||||
|
|
||||
LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -78,7 +78,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:65:29
|
||||
--> $DIR/promote-not.rs:66:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(Cell::new(1), 2).0;
|
||||
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -89,7 +89,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:66:29
|
||||
--> $DIR/promote-not.rs:67:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
|
||||
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -100,7 +100,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:69:29
|
||||
--> $DIR/promote-not.rs:70:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(1/0);
|
||||
| ---------- ^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -111,7 +111,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:70:29
|
||||
--> $DIR/promote-not.rs:71:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(1/(1-1));
|
||||
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -122,7 +122,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:71:29
|
||||
--> $DIR/promote-not.rs:72:29
|
||||
|
|
||||
LL | let _val: &'static _ = &((1+1)/(1-1));
|
||||
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -133,7 +133,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:72:29
|
||||
--> $DIR/promote-not.rs:73:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(i32::MIN/-1);
|
||||
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -144,7 +144,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:73:29
|
||||
--> $DIR/promote-not.rs:74:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(i32::MIN/(0-1));
|
||||
| ---------- ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -155,7 +155,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:74:29
|
||||
--> $DIR/promote-not.rs:75:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(-128i8/-1);
|
||||
| ---------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -166,7 +166,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:75:29
|
||||
--> $DIR/promote-not.rs:76:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(1%0);
|
||||
| ---------- ^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -177,7 +177,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:76:29
|
||||
--> $DIR/promote-not.rs:77:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(1%(1-1));
|
||||
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -188,7 +188,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:77:29
|
||||
--> $DIR/promote-not.rs:78:29
|
||||
|
|
||||
LL | let _val: &'static _ = &([1,2,3][4]+1);
|
||||
| ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -199,7 +199,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:81:29
|
||||
--> $DIR/promote-not.rs:82:29
|
||||
|
|
||||
LL | let _val: &'static _ = &TEST_DROP;
|
||||
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -210,7 +210,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:83:29
|
||||
--> $DIR/promote-not.rs:84:29
|
||||
|
|
||||
LL | let _val: &'static _ = &&TEST_DROP;
|
||||
| ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -221,7 +221,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:83:30
|
||||
--> $DIR/promote-not.rs:84:30
|
||||
|
|
||||
LL | let _val: &'static _ = &&TEST_DROP;
|
||||
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -232,7 +232,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:86:29
|
||||
--> $DIR/promote-not.rs:87:29
|
||||
|
|
||||
LL | let _val: &'static _ = &(&TEST_DROP,);
|
||||
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -243,7 +243,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:86:31
|
||||
--> $DIR/promote-not.rs:87:31
|
||||
|
|
||||
LL | let _val: &'static _ = &(&TEST_DROP,);
|
||||
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -254,7 +254,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:89:29
|
||||
--> $DIR/promote-not.rs:90:29
|
||||
|
|
||||
LL | let _val: &'static _ = &[&TEST_DROP; 1];
|
||||
| ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
@ -265,7 +265,7 @@ LL | }
|
|||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:89:31
|
||||
--> $DIR/promote-not.rs:90:31
|
||||
|
|
||||
LL | let _val: &'static _ = &[&TEST_DROP; 1];
|
||||
| ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement
|
||||
|
|
@ -274,7 +274,7 @@ LL | let _val: &'static _ = &[&TEST_DROP; 1];
|
|||
| type annotation requires that borrow lasts for `'static`
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promote-not.rs:98:26
|
||||
--> $DIR/promote-not.rs:99:26
|
||||
|
|
||||
LL | let x: &'static _ = &UnionWithCell { f1: 0 };
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ fn main() {
|
|||
// Disallow impls which relates lifetimes in the coroutine interior
|
||||
let gen = #[coroutine] move || {
|
||||
let a = A(&mut true, &mut true, No);
|
||||
//~^ ERROR temporary value dropped while borrowed
|
||||
//~| ERROR temporary value dropped while borrowed
|
||||
//~^ ERROR borrow may still be in use when coroutine yields
|
||||
//~| ERROR borrow may still be in use when coroutine yields
|
||||
yield;
|
||||
assert_foo(a);
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue