diff --git a/Cargo.lock b/Cargo.lock index 624a4226bd69a..fd6fa99881b9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4314,6 +4314,7 @@ dependencies = [ "rustc_arena", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 114b9835b98cf..4ace80a73444b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -308,7 +308,6 @@ impl ParenthesizedArgs { } } -use crate::AstDeref; pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId}; /// Modifiers on a trait bound like `~const`, `?` and `!`. @@ -2349,7 +2348,7 @@ impl Ty { pub fn is_maybe_parenthesised_infer(&self) -> bool { match &self.kind { TyKind::Infer => true, - TyKind::Paren(inner) => inner.ast_deref().is_maybe_parenthesised_infer(), + TyKind::Paren(inner) => inner.is_maybe_parenthesised_infer(), _ => false, } } diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 7f98e7ba8a615..21de7ff7719b6 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -13,34 +13,6 @@ use crate::{ Ty, Variant, Visibility, WherePredicate, }; -/// A utility trait to reduce boilerplate. -/// Standard `Deref(Mut)` cannot be reused due to coherence. -pub trait AstDeref { - type Target; - fn ast_deref(&self) -> &Self::Target; - fn ast_deref_mut(&mut self) -> &mut Self::Target; -} - -macro_rules! impl_not_ast_deref { - ($($T:ty),+ $(,)?) => { - $( - impl !AstDeref for $T {} - )+ - }; -} - -impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt); - -impl AstDeref for P { - type Target = T; - fn ast_deref(&self) -> &Self::Target { - self - } - fn ast_deref_mut(&mut self) -> &mut Self::Target { - self - } -} - /// A trait for AST nodes having an ID. pub trait HasNodeId { fn node_id(&self) -> NodeId; @@ -81,12 +53,12 @@ impl_has_node_id!( WherePredicate, ); -impl> HasNodeId for T { +impl HasNodeId for P { fn node_id(&self) -> NodeId { - self.ast_deref().node_id() + (**self).node_id() } fn node_id_mut(&mut self) -> &mut NodeId { - self.ast_deref_mut().node_id_mut() + (**self).node_id_mut() } } @@ -138,21 +110,21 @@ impl_has_tokens_none!( WherePredicate ); -impl> HasTokens for T { +impl HasTokens for Option { fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.ast_deref().tokens() + self.as_ref().and_then(|inner| inner.tokens()) } fn tokens_mut(&mut self) -> Option<&mut Option> { - self.ast_deref_mut().tokens_mut() + self.as_mut().and_then(|inner| inner.tokens_mut()) } } -impl HasTokens for Option { +impl HasTokens for P { fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.as_ref().and_then(|inner| inner.tokens()) + (**self).tokens() } fn tokens_mut(&mut self) -> Option<&mut Option> { - self.as_mut().and_then(|inner| inner.tokens_mut()) + (**self).tokens_mut() } } @@ -273,13 +245,13 @@ impl_has_attrs!( ); impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); -impl> HasAttrs for T { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS; +impl HasAttrs for P { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; fn attrs(&self) -> &[Attribute] { - self.ast_deref().attrs() + (**self).attrs() } fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { - self.ast_deref_mut().visit_attrs(f) + (**self).visit_attrs(f); } } @@ -343,13 +315,22 @@ impl AstNodeWrapper { } } -impl AstDeref for AstNodeWrapper { - type Target = Wrapped; - fn ast_deref(&self) -> &Self::Target { - &self.wrapped +impl HasNodeId for AstNodeWrapper { + fn node_id(&self) -> NodeId { + self.wrapped.node_id() + } + fn node_id_mut(&mut self) -> &mut NodeId { + self.wrapped.node_id_mut() + } +} + +impl HasAttrs for AstNodeWrapper { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS; + fn attrs(&self) -> &[Attribute] { + self.wrapped.attrs() } - fn ast_deref_mut(&mut self) -> &mut Self::Target { - &mut self.wrapped + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { + self.wrapped.visit_attrs(f); } } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index e572ec99dabf3..c08622cac864a 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -46,7 +46,7 @@ pub mod tokenstream; pub mod visit; pub use self::ast::*; -pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; +pub use self::ast_traits::{AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 0913dc91a5342..f3ac932e1b7e9 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -8,7 +8,7 @@ use std::env::VarError; use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; +use rustc_ast::{ExprKind, GenericArg, Mutability}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use thin_vec::thin_vec; @@ -148,13 +148,13 @@ pub(crate) fn expand_env<'cx>( cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { span, var: *symbol, - var_expr: var_expr.ast_deref(), + var_expr: &var_expr, }) } else { cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { span, var: *symbol, - var_expr: var_expr.ast_deref(), + var_expr: &var_expr, }) } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index e866b8962551a..9018d78b00aeb 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1109,6 +1109,43 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, old); } + sym::minimumf32 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = fx.bcx.ins().fmin(a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); + ret.write_cvalue(fx, val); + } + sym::minimumf64 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = fx.bcx.ins().fmin(a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); + ret.write_cvalue(fx, val); + } + sym::maximumf32 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = fx.bcx.ins().fmax(a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); + ret.write_cvalue(fx, val); + } + sym::maximumf64 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = fx.bcx.ins().fmax(a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); + ret.write_cvalue(fx, val); + } + sym::minnumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 2ed5ec4381edf..9caceca92957a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -74,8 +74,44 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::fabsf64 => "fabs", sym::minnumf32 => "fminf", sym::minnumf64 => "fmin", + sym::minimumf32 => "fminimumf", + sym::minimumf64 => "fminimum", + sym::minimumf128 => { + // GCC doesn't have the intrinsic we want so we use the compiler-builtins one + // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html + let f128_type = cx.type_f128(); + return Some(cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + cx.context.new_parameter(None, f128_type, "a"), + cx.context.new_parameter(None, f128_type, "b"), + ], + "fminimumf128", + false, + )); + } sym::maxnumf32 => "fmaxf", sym::maxnumf64 => "fmax", + sym::maximumf32 => "fmaximumf", + sym::maximumf64 => "fmaximum", + sym::maximumf128 => { + // GCC doesn't have the intrinsic we want so we use the compiler-builtins one + // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html + let f128_type = cx.type_f128(); + return Some(cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + cx.context.new_parameter(None, f128_type, "a"), + cx.context.new_parameter(None, f128_type, "b"), + ], + "fmaximumf128", + false, + )); + } sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", sym::copysignf128 => "copysignl", diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ed50515b70716..b0d8e11d1fb57 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1009,11 +1009,27 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64); ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128); + ifn!("llvm.minimum.f16", fn(t_f16, t_f16) -> t_f16); + ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64); + // There are issues on x86_64 and aarch64 with the f128 variant. + // - https://github.com/llvm/llvm-project/issues/139380 + // - https://github.com/llvm/llvm-project/issues/139381 + // ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128); + ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16); ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32); ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64); ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128); + ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16); + ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64); + // There are issues on x86_64 and aarch64 with the f128 variant. + // - https://github.com/llvm/llvm-project/issues/139380 + // - https://github.com/llvm/llvm-project/issues/139381 + // ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128); + ifn!("llvm.floor.f16", fn(t_f16) -> t_f16); ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index bfaad8f2f1ef0..5ca5737529229 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -103,11 +103,23 @@ fn get_simple_intrinsic<'ll>( sym::minnumf64 => "llvm.minnum.f64", sym::minnumf128 => "llvm.minnum.f128", + sym::minimumf16 => "llvm.minimum.f16", + sym::minimumf32 => "llvm.minimum.f32", + sym::minimumf64 => "llvm.minimum.f64", + // There are issues on x86_64 and aarch64 with the f128 variant, + // let's instead use the instrinsic fallback body. + // sym::minimumf128 => "llvm.minimum.f128", sym::maxnumf16 => "llvm.maxnum.f16", sym::maxnumf32 => "llvm.maxnum.f32", sym::maxnumf64 => "llvm.maxnum.f64", sym::maxnumf128 => "llvm.maxnum.f128", + sym::maximumf16 => "llvm.maximum.f16", + sym::maximumf32 => "llvm.maximum.f32", + sym::maximumf64 => "llvm.maximum.f64", + // There are issues on x86_64 and aarch64 with the f128 variant, + // let's instead use the instrinsic fallback body. + // sym::maximumf128 => "llvm.maximum.f128", sym::copysignf16 => "llvm.copysign.f16", sym::copysignf32 => "llvm.copysign.f32", sym::copysignf64 => "llvm.copysign.f64", diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 04a8ed1e0f1e9..090b2a692cfc3 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -493,11 +493,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::minnumf64 => self.float_min_intrinsic::(args, dest)?, sym::minnumf128 => self.float_min_intrinsic::(args, dest)?, + sym::minimumf16 => self.float_minimum_intrinsic::(args, dest)?, + sym::minimumf32 => self.float_minimum_intrinsic::(args, dest)?, + sym::minimumf64 => self.float_minimum_intrinsic::(args, dest)?, + sym::minimumf128 => self.float_minimum_intrinsic::(args, dest)?, + sym::maxnumf16 => self.float_max_intrinsic::(args, dest)?, sym::maxnumf32 => self.float_max_intrinsic::(args, dest)?, sym::maxnumf64 => self.float_max_intrinsic::(args, dest)?, sym::maxnumf128 => self.float_max_intrinsic::(args, dest)?, + sym::maximumf16 => self.float_maximum_intrinsic::(args, dest)?, + sym::maximumf32 => self.float_maximum_intrinsic::(args, dest)?, + sym::maximumf64 => self.float_maximum_intrinsic::(args, dest)?, + sym::maximumf128 => self.float_maximum_intrinsic::(args, dest)?, + sym::copysignf16 => self.float_copysign_intrinsic::(args, dest)?, sym::copysignf32 => self.float_copysign_intrinsic::(args, dest)?, sym::copysignf64 => self.float_copysign_intrinsic::(args, dest)?, @@ -830,6 +840,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } + fn float_minimum_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let res = a.minimum(b); + let res = self.adjust_nan(res, &[a, b]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_maximum_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let res = a.maximum(b); + let res = self.adjust_nan(res, &[a, b]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + fn float_copysign_intrinsic( &mut self, args: &[OpTy<'tcx, M::Provenance>], diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index d4853d1357f30..81d4d59ee0451 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,4 +1,3 @@ -use std::ops::Deref; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; @@ -1117,7 +1116,6 @@ enum AddSemicolon { /// of functionality used by `InvocationCollector`. trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { type OutputTy = SmallVec<[Self; 1]>; - type AttrsTy: Deref = ast::AttrVec; type ItemKind = ItemKind; const KIND: AstFragmentKind; fn to_annotatable(self) -> Annotatable; @@ -1134,7 +1132,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn is_mac_call(&self) -> bool { false } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { unreachable!() } fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item)> { @@ -1189,7 +1187,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let node = self.into_inner(); match node.kind { ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1345,7 +1343,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let item = self.wrapped.into_inner(); match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1386,7 +1384,7 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let item = self.wrapped.into_inner(); match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1427,7 +1425,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitImplItem fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let item = self.wrapped.into_inner(); match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1465,7 +1463,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let node = self.into_inner(); match node.kind { ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1579,7 +1577,6 @@ impl InvocationCollectorNode for ast::Arm { } impl InvocationCollectorNode for ast::Stmt { - type AttrsTy = ast::AttrVec; const KIND: AstFragmentKind = AstFragmentKind::Stmts; fn to_annotatable(self) -> Annotatable { Annotatable::Stmt(P(self)) @@ -1599,7 +1596,7 @@ impl InvocationCollectorNode for ast::Stmt { StmtKind::Let(..) | StmtKind::Empty => false, } } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { // We pull macro invocations (both attributes and fn-like macro calls) out of their // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. let (add_semicolon, mac, attrs) = match self.kind { @@ -1693,7 +1690,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ast::TyKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let node = self.into_inner(); match node.kind { TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), @@ -1717,7 +1714,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, PatKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let node = self.into_inner(); match node.kind { PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), @@ -1728,7 +1725,6 @@ impl InvocationCollectorNode for P { impl InvocationCollectorNode for P { type OutputTy = P; - type AttrsTy = ast::AttrVec; const KIND: AstFragmentKind = AstFragmentKind::Expr; fn to_annotatable(self) -> Annotatable { Annotatable::Expr(self) @@ -1745,7 +1741,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let node = self.into_inner(); match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1757,7 +1753,6 @@ impl InvocationCollectorNode for P { struct OptExprTag; impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { type OutputTy = Option>; - type AttrsTy = ast::AttrVec; const KIND: AstFragmentKind = AstFragmentKind::OptExpr; fn to_annotatable(self) -> Annotatable { Annotatable::Expr(self.wrapped) @@ -1772,7 +1767,7 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let node = self.wrapped.into_inner(); match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1794,7 +1789,6 @@ impl DummyAstNode for MethodReceiverTag { } impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> { type OutputTy = Self; - type AttrsTy = ast::AttrVec; const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr; fn descr() -> &'static str { "an expression" @@ -1811,7 +1805,7 @@ impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { let node = self.wrapped.into_inner(); match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 692784bf1714d..9fd158ad154d8 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -103,10 +103,18 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::minnumf32 | sym::minnumf64 | sym::minnumf128 + | sym::minimumf16 + | sym::minimumf32 + | sym::minimumf64 + | sym::minimumf128 | sym::maxnumf16 | sym::maxnumf32 | sym::maxnumf64 | sym::maxnumf128 + | sym::maximumf16 + | sym::maximumf32 + | sym::maximumf64 + | sym::maximumf128 | sym::rustc_peek | sym::type_name | sym::forget @@ -374,11 +382,21 @@ pub(crate) fn check_intrinsic_type( sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::maximumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::maximumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 0fcc3d8f6b3aa..a97e0eaa9c631 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -11,6 +11,7 @@ pulldown-cmark = { version = "0.11", features = ["html"], default-features = fal rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 74daad0839469..0b16983c2c794 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -5,6 +5,7 @@ use rustc_ast::{ self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, }; use rustc_ast_pretty::pprust; +use rustc_attr_data_structures::{self as attr, Stability}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; @@ -110,6 +111,7 @@ pub(crate) struct ImportSuggestion { pub via_import: bool, /// An extra note that should be issued if this item is suggested pub note: Option, + pub is_stable: bool, } /// Adjust the impl span so that just the `impl` keyword is taken by removing @@ -1172,13 +1174,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ThinVec::::new(), true, start_did.is_local() || !self.tcx.is_doc_hidden(start_did), + true, )]; let mut worklist_via_import = vec![]; - while let Some((in_module, path_segments, accessible, doc_visible)) = match worklist.pop() { - None => worklist_via_import.pop(), - Some(x) => Some(x), - } { + while let Some((in_module, path_segments, accessible, doc_visible, is_stable)) = + match worklist.pop() { + None => worklist_via_import.pop(), + Some(x) => Some(x), + } + { let in_module_is_extern = !in_module.def_id().is_local(); in_module.for_each_child(self, |this, ident, ns, name_binding| { // Avoid non-importable candidates. @@ -1258,6 +1263,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { candidates.remove(idx); } + let is_stable = if is_stable + && let Some(did) = did + && this.is_stable(did, path.span) + { + true + } else { + false + }; + + // Rreplace unstable suggestions if we meet a new stable one, + // and do nothing if any other situation. For example, if we + // meet `std::ops::Range` after `std::range::legacy::Range`, + // we will remove the latter and then insert the former. + if is_stable + && let Some(idx) = candidates + .iter() + .position(|v: &ImportSuggestion| v.did == did && !v.is_stable) + { + candidates.remove(idx); + } + if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { // See if we're recommending TryFrom, TryInto, or FromIterator and add // a note about editions @@ -1289,6 +1315,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { doc_visible: child_doc_visible, note, via_import, + is_stable, }); } } @@ -1315,8 +1342,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !is_extern_crate_that_also_appears_in_prelude || alias_import { // add the module to the lookup if seen_modules.insert(module.def_id()) { - if via_import { &mut worklist_via_import } else { &mut worklist } - .push((module, path_segments, child_accessible, child_doc_visible)); + if via_import { &mut worklist_via_import } else { &mut worklist }.push( + ( + module, + path_segments, + child_accessible, + child_doc_visible, + is_stable && this.is_stable(module.def_id(), name_binding.span), + ), + ); } } } @@ -1326,6 +1360,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { candidates } + fn is_stable(&self, did: DefId, span: Span) -> bool { + if did.is_local() { + return true; + } + + match self.tcx.lookup_stability(did) { + Some(Stability { + level: attr::StabilityLevel::Unstable { implied_by, .. }, + feature, + .. + }) => { + if span.allows_unstable(feature) { + true + } else if self.tcx.features().enabled(feature) { + true + } else if let Some(implied_by) = implied_by + && self.tcx.features().enabled(implied_by) + { + true + } else { + false + } + } + Some(_) => true, + None => false, + } + } + /// When name resolution fails, this method can be used to look up candidate /// entities with the expected name. It allows filtering them using the /// supplied predicate (which should be used to only accept the types of diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d4fe446cc9f76..b538be34f31f1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2501,6 +2501,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { doc_visible, note: None, via_import: false, + is_stable: true, }, )); } else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8df211b0840ec..3a95447308a90 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1301,6 +1301,10 @@ symbols! { match_beginning_vert, match_default_bindings, matches_macro, + maximumf128, + maximumf16, + maximumf32, + maximumf64, maxnumf128, maxnumf16, maxnumf32, @@ -1335,6 +1339,10 @@ symbols! { min_generic_const_args, min_specialization, min_type_alias_impl_trait, + minimumf128, + minimumf16, + minimumf32, + minimumf64, minnumf128, minnumf16, minnumf32, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 686cd4da33879..c7220fe7c4acf 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3907,7 +3907,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { } } -/// Returns the minimum of two `f16` values. +/// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3920,7 +3920,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { #[rustc_intrinsic] pub const fn minnumf16(x: f16, y: f16) -> f16; -/// Returns the minimum of two `f32` values. +/// Returns the minimum (IEEE 754-2008 minNum) of two `f32` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3934,7 +3934,7 @@ pub const fn minnumf16(x: f16, y: f16) -> f16; #[rustc_intrinsic] pub const fn minnumf32(x: f32, y: f32) -> f32; -/// Returns the minimum of two `f64` values. +/// Returns the minimum (IEEE 754-2008 minNum) of two `f64` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3948,7 +3948,7 @@ pub const fn minnumf32(x: f32, y: f32) -> f32; #[rustc_intrinsic] pub const fn minnumf64(x: f64, y: f64) -> f64; -/// Returns the minimum of two `f128` values. +/// Returns the minimum (IEEE 754-2008 minNum) of two `f128` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3961,7 +3961,91 @@ pub const fn minnumf64(x: f64, y: f64) -> f64; #[rustc_intrinsic] pub const fn minnumf128(x: f128, y: f128) -> f128; -/// Returns the maximum of two `f16` values. +/// Returns the minimum (IEEE 754-2019 minimum) of two `f16` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn minimumf16(x: f16, y: f16) -> f16 { + if x < y { + x + } else if y < x { + y + } else if x == y { + if x.is_sign_negative() && y.is_sign_positive() { x } else { y } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + x + y + } +} + +/// Returns the minimum (IEEE 754-2019 minimum) of two `f32` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn minimumf32(x: f32, y: f32) -> f32 { + if x < y { + x + } else if y < x { + y + } else if x == y { + if x.is_sign_negative() && y.is_sign_positive() { x } else { y } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + x + y + } +} + +/// Returns the minimum (IEEE 754-2019 minimum) of two `f64` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn minimumf64(x: f64, y: f64) -> f64 { + if x < y { + x + } else if y < x { + y + } else if x == y { + if x.is_sign_negative() && y.is_sign_positive() { x } else { y } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + x + y + } +} + +/// Returns the minimum (IEEE 754-2019 minimum) of two `f128` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn minimumf128(x: f128, y: f128) -> f128 { + if x < y { + x + } else if y < x { + y + } else if x == y { + if x.is_sign_negative() && y.is_sign_positive() { x } else { y } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + x + y + } +} + +/// Returns the maximum (IEEE 754-2008 maxNum) of two `f16` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3974,7 +4058,7 @@ pub const fn minnumf128(x: f128, y: f128) -> f128; #[rustc_intrinsic] pub const fn maxnumf16(x: f16, y: f16) -> f16; -/// Returns the maximum of two `f32` values. +/// Returns the maximum (IEEE 754-2008 maxNum) of two `f32` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -3988,7 +4072,7 @@ pub const fn maxnumf16(x: f16, y: f16) -> f16; #[rustc_intrinsic] pub const fn maxnumf32(x: f32, y: f32) -> f32; -/// Returns the maximum of two `f64` values. +/// Returns the maximum (IEEE 754-2008 maxNum) of two `f64` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -4002,7 +4086,7 @@ pub const fn maxnumf32(x: f32, y: f32) -> f32; #[rustc_intrinsic] pub const fn maxnumf64(x: f64, y: f64) -> f64; -/// Returns the maximum of two `f128` values. +/// Returns the maximum (IEEE 754-2008 maxNum) of two `f128` values. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -4015,6 +4099,86 @@ pub const fn maxnumf64(x: f64, y: f64) -> f64; #[rustc_intrinsic] pub const fn maxnumf128(x: f128, y: f128) -> f128; +/// Returns the maximum (IEEE 754-2019 maximum) of two `f16` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn maximumf16(x: f16, y: f16) -> f16 { + if x > y { + x + } else if y > x { + y + } else if x == y { + if x.is_sign_positive() && y.is_sign_negative() { x } else { y } + } else { + x + y + } +} + +/// Returns the maximum (IEEE 754-2019 maximum) of two `f32` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn maximumf32(x: f32, y: f32) -> f32 { + if x > y { + x + } else if y > x { + y + } else if x == y { + if x.is_sign_positive() && y.is_sign_negative() { x } else { y } + } else { + x + y + } +} + +/// Returns the maximum (IEEE 754-2019 maximum) of two `f64` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn maximumf64(x: f64, y: f64) -> f64 { + if x > y { + x + } else if y > x { + y + } else if x == y { + if x.is_sign_positive() && y.is_sign_negative() { x } else { y } + } else { + x + y + } +} + +/// Returns the maximum (IEEE 754-2019 maximum) of two `f128` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const fn maximumf128(x: f128, y: f128) -> f128 { + if x > y { + x + } else if y > x { + y + } else if x == y { + if x.is_sign_positive() && y.is_sign_negative() { x } else { y } + } else { + x + y + } +} + /// Returns the absolute value of an `f16`. /// /// The stabilized version of this intrinsic is diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index b1119d4899bab..8020b36c6fa6e 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -757,15 +757,7 @@ impl f128 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn maximum(self, other: f128) -> f128 { - if self > other { - self - } else if other > self { - other - } else if self == other { - if self.is_sign_positive() && other.is_sign_negative() { self } else { other } - } else { - self + other - } + intrinsics::maximumf128(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -798,16 +790,7 @@ impl f128 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn minimum(self, other: f128) -> f128 { - if self < other { - self - } else if other < self { - other - } else if self == other { - if self.is_sign_negative() && other.is_sign_positive() { self } else { other } - } else { - // At least one input is NaN. Use `+` to perform NaN propagation and quieting. - self + other - } + intrinsics::minimumf128(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 54e38d9e1a6f1..68201400a1d5d 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -746,15 +746,7 @@ impl f16 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn maximum(self, other: f16) -> f16 { - if self > other { - self - } else if other > self { - other - } else if self == other { - if self.is_sign_positive() && other.is_sign_negative() { self } else { other } - } else { - self + other - } + intrinsics::maximumf16(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -786,16 +778,7 @@ impl f16 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn minimum(self, other: f16) -> f16 { - if self < other { - self - } else if other < self { - other - } else if self == other { - if self.is_sign_negative() && other.is_sign_positive() { self } else { other } - } else { - // At least one input is NaN. Use `+` to perform NaN propagation and quieting. - self + other - } + intrinsics::minimumf16(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index e66fd3bb52b86..da241785d6427 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -944,15 +944,7 @@ impl f32 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn maximum(self, other: f32) -> f32 { - if self > other { - self - } else if other > self { - other - } else if self == other { - if self.is_sign_positive() && other.is_sign_negative() { self } else { other } - } else { - self + other - } + intrinsics::maximumf32(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -979,16 +971,7 @@ impl f32 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn minimum(self, other: f32) -> f32 { - if self < other { - self - } else if other < self { - other - } else if self == other { - if self.is_sign_negative() && other.is_sign_positive() { self } else { other } - } else { - // At least one input is NaN. Use `+` to perform NaN propagation and quieting. - self + other - } + intrinsics::minimumf32(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 2d791437b2825..c8544771a9047 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -962,15 +962,7 @@ impl f64 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn maximum(self, other: f64) -> f64 { - if self > other { - self - } else if other > self { - other - } else if self == other { - if self.is_sign_positive() && other.is_sign_negative() { self } else { other } - } else { - self + other - } + intrinsics::maximumf64(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -997,16 +989,7 @@ impl f64 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn minimum(self, other: f64) -> f64 { - if self < other { - self - } else if other < self { - other - } else if self == other { - if self.is_sign_negative() && other.is_sign_positive() { self } else { other } - } else { - // At least one input is NaN. Use `+` to perform NaN propagation and quieting. - self + other - } + intrinsics::minimumf64(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 18c03b4a6f89c..0fb5c0bac7562 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -373,7 +373,7 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_constructors)] + /// #![feature(duration_constructors_lite)] /// use std::time::Duration; /// /// let duration = Duration::from_hours(6); @@ -381,7 +381,7 @@ impl Duration { /// assert_eq!(6 * 60 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_constructors", issue = "120301")] + #[unstable(feature = "duration_constructors_lite", issue = "140881")] #[must_use] #[inline] pub const fn from_hours(hours: u64) -> Duration { @@ -401,7 +401,7 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_constructors)] + /// #![feature(duration_constructors_lite)] /// use std::time::Duration; /// /// let duration = Duration::from_mins(10); @@ -409,7 +409,7 @@ impl Duration { /// assert_eq!(10 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_constructors", issue = "120301")] + #[unstable(feature = "duration_constructors_lite", issue = "140881")] #[must_use] #[inline] pub const fn from_mins(mins: u64) -> Duration { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index a71c4139308aa..0575375cf4f08 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -24,6 +24,7 @@ #![feature(dec2flt)] #![feature(duration_constants)] #![feature(duration_constructors)] +#![feature(duration_constructors_lite)] #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] diff --git a/library/coretests/tests/time.rs b/library/coretests/tests/time.rs index fe7bb11c67589..bb98e59bf5a2b 100644 --- a/library/coretests/tests/time.rs +++ b/library/coretests/tests/time.rs @@ -46,16 +46,25 @@ fn from_weeks_overflow() { } #[test] -fn constructors() { +fn constructor_weeks() { assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60)); assert_eq!(Duration::from_weeks(0), Duration::ZERO); +} +#[test] +fn constructor_days() { assert_eq!(Duration::from_days(1), Duration::from_secs(86_400)); assert_eq!(Duration::from_days(0), Duration::ZERO); +} +#[test] +fn constructor_hours() { assert_eq!(Duration::from_hours(1), Duration::from_secs(3_600)); assert_eq!(Duration::from_hours(0), Duration::ZERO); +} +#[test] +fn constructor_minutes() { assert_eq!(Duration::from_mins(1), Duration::from_secs(60)); assert_eq!(Duration::from_mins(0), Duration::ZERO); } diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index cdad3bd46fab6..05ab1b6eddefb 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -220,9 +220,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -236,13 +236,13 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fd-lock" -version = "4.0.2" +version = "4.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 0.38.40", - "windows-sys 0.52.0", + "rustix", + "windows-sys 0.59.0", ] [[package]] @@ -347,9 +347,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libredox" @@ -362,12 +362,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - [[package]] name = "linux-raw-sys" version = "0.9.3" @@ -583,19 +577,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "rustix" -version = "0.38.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", -] - [[package]] name = "rustix" version = "1.0.2" @@ -605,7 +586,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.9.3", + "linux-raw-sys", "windows-sys 0.59.0", ] @@ -745,7 +726,7 @@ dependencies = [ "fastrand", "getrandom", "once_cell", - "rustix 1.0.2", + "rustix", "windows-sys 0.59.0", ] @@ -1182,13 +1163,12 @@ dependencies = [ [[package]] name = "xattr" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "linux-raw-sys 0.4.14", - "rustix 0.38.40", + "rustix", ] [[package]] diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 28c035daa5d50..9ed5b519b6ea4 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -40,6 +40,14 @@ if [ -z "${PR_CI_JOB:-}" ]; then else python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri fi +# We re-run the test suite for a chance to find bugs in the intrinsic fallback bodies and in MIR +# optimizations. This can miss UB, so we only run the "pass" tests. We need to enable debug +# assertions as `-O` disables them but some tests rely on them. We also set a cfg flag so tests can +# adjust their expectations if needed. This can change the output of the tests so we ignore that, +# we only ensure that all assertions still pass. +MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \ + MIRI_SKIP_UI_CHECKS=1 \ + python3 "$X_PY" test --stage 2 src/tools/miri -- tests/{pass,panic} # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. case $HOST_TARGET in diff --git a/src/doc/unstable-book/src/library-features/duration-constructors-lite.md b/src/doc/unstable-book/src/library-features/duration-constructors-lite.md new file mode 100644 index 0000000000000..5238b84f77646 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/duration-constructors-lite.md @@ -0,0 +1,11 @@ +# `duration_constructors_lite` + +The tracking issue for this feature is: [#140881] + +[#140881]: https://github.com/rust-lang/rust/issues/140881 + +------------------------ + +Add the methods `from_mins`, `from_hours` to `Duration`. + +For `from_days` and `from_weeks` see [`duration_constructors`](https://github.com/rust-lang/rust/issues/120301). diff --git a/src/doc/unstable-book/src/library-features/duration-constructors.md b/src/doc/unstable-book/src/library-features/duration-constructors.md index 098519c7c9037..49ad78d196138 100644 --- a/src/doc/unstable-book/src/library-features/duration-constructors.md +++ b/src/doc/unstable-book/src/library-features/duration-constructors.md @@ -6,4 +6,5 @@ The tracking issue for this feature is: [#120301] ------------------------ -Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`. +Add the methods `from_days` and `from_weeks` to `Duration`. +For `from_mins` and `from_hours` see [duration-constructors-lite.md](./duration-constructors-lite.md) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index a78cc9d931980..b692ddab4ffc8 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -393,6 +393,9 @@ to Miri failing to detect cases of undefined behavior in a program. disables the randomization of the next thread to be picked, instead fixing a round-robin schedule. Note however that other aspects of Miri's concurrency behavior are still randomize; use `-Zmiri-deterministic-concurrency` to disable them all. +* `-Zmiri-force-intrinsic-fallback` forces the use of the "fallback" body for all intrinsics that + have one. This is useful to test the fallback bodies, but should not be used otherwise. It is + **unsound** since the fallback body might not be checking for all UB. * `-Zmiri-native-lib=` is an experimental flag for providing support for calling native functions from inside the interpreter via FFI. The flag is supported only on Unix systems. Functions not provided by that file are still executed via the usual Miri shims. diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 69aa035fdc3df..f249b58aeb663 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -584,6 +584,8 @@ fn main() { } else if arg == "-Zmiri-ignore-leaks" { miri_config.ignore_leaks = true; miri_config.collect_leak_backtraces = false; + } else if arg == "-Zmiri-force-intrinsic-fallback" { + miri_config.force_intrinsic_fallback = true; } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; } else if arg == "-Zmiri-permissive-provenance" { diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index bb5e5d7ee8146..a90c6ab9d40e9 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -165,6 +165,8 @@ pub struct MiriConfig { pub address_reuse_cross_thread_rate: f64, /// Round Robin scheduling with no preemption. pub fixed_scheduling: bool, + /// Always prefer the intrinsic fallback body over the native Miri implementation. + pub force_intrinsic_fallback: bool, } impl Default for MiriConfig { @@ -203,6 +205,7 @@ impl Default for MiriConfig { address_reuse_rate: 0.5, address_reuse_cross_thread_rate: 0.1, fixed_scheduling: false, + force_intrinsic_fallback: false, } } } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 3334c0b5edf96..982fbc318110e 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -28,6 +28,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); + // Force use of fallback body, if available. + if this.machine.force_intrinsic_fallback + && !this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden + { + return interp_ok(Some(ty::Instance { + def: ty::InstanceKind::Item(instance.def_id()), + args: instance.args, + })); + } + // See if the core engine can handle this intrinsic. if this.eval_intrinsic(instance, args, dest, ret)? { return interp_ok(None); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 6060d41dac594..dbde415170c31 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -614,6 +614,9 @@ pub struct MiriMachine<'tcx> { /// Cache for `mangle_internal_symbol`. pub(crate) mangle_internal_symbol_cache: FxHashMap<&'static str, String>, + + /// Always prefer the intrinsic fallback body over the native Miri implementation. + pub force_intrinsic_fallback: bool, } impl<'tcx> MiriMachine<'tcx> { @@ -770,6 +773,7 @@ impl<'tcx> MiriMachine<'tcx> { reject_in_isolation_warned: Default::default(), int2ptr_warned: Default::default(), mangle_internal_symbol_cache: Default::default(), + force_intrinsic_fallback: config.force_intrinsic_fallback, } } @@ -946,6 +950,7 @@ impl VisitProvenance for MiriMachine<'_> { reject_in_isolation_warned: _, int2ptr_warned: _, mangle_internal_symbol_cache: _, + force_intrinsic_fallback: _, } = self; threads.visit_provenance(visit); diff --git a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs index 89289a25d50a3..913c3cde272d8 100644 --- a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs @@ -33,20 +33,24 @@ fn main() { assert_eq!(intrinsics::likely(false), false); assert_eq!(intrinsics::unlikely(true), true); - let mut saw_true = false; - let mut saw_false = false; + // Skip this test when we use the fallback bodies, as that one is deterministic. + // (CI sets `--cfg force_intrinsic_fallback` together with `-Zmiri-force-intrinsic-fallback`.) + if !cfg!(force_intrinsic_fallback) { + let mut saw_true = false; + let mut saw_false = false; - for _ in 0..50 { - if intrinsics::is_val_statically_known(0) { - saw_true = true; - } else { - saw_false = true; + for _ in 0..50 { + if intrinsics::is_val_statically_known(0) { + saw_true = true; + } else { + saw_false = true; + } } + assert!( + saw_true && saw_false, + "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!" + ); } - assert!( - saw_true && saw_false, - "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!" - ); intrinsics::forget(Bomb); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 706d04484f6fe..f9ff392126616 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -5789,7 +5789,7 @@ The tracking issue for this feature is: [#120301] ------------------------ -Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`. +Add the methods `from_days` and `from_weeks` to `Duration`. "##, default_severity: Severity::Allow, warn_since: None, diff --git a/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.rs b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.rs new file mode 100644 index 0000000000000..aa7178271a792 --- /dev/null +++ b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.rs @@ -0,0 +1,3 @@ +fn main() { + const _: Range = 0..1; //~ ERROR cannot find type `Range` in this scope +} diff --git a/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr new file mode 100644 index 0000000000000..9e4314a0699d8 --- /dev/null +++ b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr @@ -0,0 +1,20 @@ +error[E0412]: cannot find type `Range` in this scope + --> $DIR/sugg-stable-import-first-issue-140240.rs:2:14 + | +LL | const _: Range = 0..1; + | ^^^^^ not found in this scope + | +help: consider importing one of these structs + | +LL + use std::collections::btree_map::Range; + | +LL + use std::collections::btree_set::Range; + | +LL + use std::ops::Range; + | +LL + use std::range::Range; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index 55a8d580a8b7b..b24e754a4ec98 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -127,13 +127,13 @@ fn special_characters() { } fn punch_card() -> impl std::fmt::Debug { - ..=..=.. .. .. .. .. .. .. .. .. .. .. ..=.. .. - ..=.. ..=.. .. .. .. .. .. .. .. .. ..=..=..=.. - ..=.. ..=.. ..=.. ..=.. .. ..=..=.. .. ..=.. .. + ..=..=.. .. .. .. .. .. .. .. .. .. .. .. .. .. + ..=.. ..=.. .. .. .. .. .. .. .. .. .. ..=.. .. + ..=.. ..=.. ..=.. ..=.. .. ..=..=.. ..=..=..=.. ..=..=.. .. ..=.. ..=.. ..=.. .. .. .. ..=.. .. ..=.. ..=.. ..=.. ..=.. .. ..=.. .. .. ..=.. .. ..=.. ..=.. ..=.. ..=.. .. .. ..=.. .. ..=.. .. - ..=.. ..=.. .. ..=..=.. ..=..=.. .. .. ..=.. .. + ..=.. ..=.. .. ..=..=.. ..=..=.. .. .. ..=..=.. } fn r#match() {