diff --git a/Cargo.lock b/Cargo.lock index 9a5ba74174948..05d77ec0c8fc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1848,9 +1848,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75e31ae4eaa0e45e17ee2b6b9e3ed969c3c6ff12bb4c2e352c42493f4ebb706" +checksum = "29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff" dependencies = [ "ammonia", "anyhow", diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 5d6f791f13719..550524e652af7 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -543,9 +543,12 @@ impl<'a, 'b> Context<'a, 'b> { let idx = self.args.len(); self.arg_types.push(Vec::new()); self.arg_unique_types.push(Vec::new()); - self.args.push( - self.ecx.expr_ident(self.fmtsp, Ident::new(name, self.fmtsp)), - ); + let span = if self.is_literal { + *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + } else { + self.fmtsp + }; + self.args.push(self.ecx.expr_ident(span, Ident::new(name, span))); self.names.insert(name, idx); self.verify_arg_type(Exact(idx), ty) } else { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a468d09c2d93d..f801f845ac16c 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -259,6 +259,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} InlineAsmArch::Hexagon => {} + InlineAsmArch::Mips => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -505,6 +506,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", @@ -551,6 +554,7 @@ fn modifier_to_llvm( } } InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, @@ -603,6 +607,8 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll cx.type_vector(cx.type_i64(), 2) } InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), @@ -700,6 +706,12 @@ fn llvm_fixup_input( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()), + _ => value, + }, _ => value, } } @@ -768,6 +780,13 @@ fn llvm_fixup_output( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), + Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()), + _ => value, + }, _ => value, } } @@ -831,6 +850,12 @@ fn llvm_fixup_output_type( layout.llvm_type(cx) } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), + Primitive::F32 => cx.type_i32(), + _ => layout.llvm_type(cx), + }, _ => layout.llvm_type(cx), } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 23a3be1a2f2e8..27061acd5afd4 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -21,7 +21,6 @@ use rustc_target::abi::{self, Align, Size}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::CStr; -use std::iter::TrustedLen; use std::ops::{Deref, Range}; use std::ptr; use tracing::debug; @@ -179,7 +178,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, v: &'ll Value, else_llbb: &'ll BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ) { let switch = unsafe { llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, cases.len() as c_uint) }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 456e9c7ce75fa..f14493e604368 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -12,7 +12,6 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![recursion_limit = "256"] use back::write::{create_informational_target_machine, create_target_machine}; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8568bd64f4c4f..d4f3bf3779784 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -6,7 +6,6 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![feature(associated_type_bounds)] #![recursion_limit = "256"] diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 5142922260a57..b35b0f24208b2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::Ty; use rustc_target::abi::{Abi, Align, Scalar, Size}; use rustc_target::spec::HasTargetSpec; -use std::iter::TrustedLen; use std::ops::Range; #[derive(Copy, Clone)] @@ -60,7 +59,7 @@ pub trait BuilderMethods<'a, 'tcx>: &mut self, v: Self::Value, else_llbb: Self::BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ); fn invoke( &mut self, diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 6452bda293ef5..17b9e1ee7e8ba 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -584,6 +584,9 @@ declare_features! ( /// Allows non trivial generic constants which have to be manually propageted upwards. (active, const_evaluatable_checked, "1.48.0", Some(76560), None), + /// Allows basic arithmetic on floating point types in a `const fn`. + (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 637ef4c17ebc8..492afa54445bc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2675,7 +2675,7 @@ impl<'tcx> ClosureKind { } } - /// Returns `true` if this a type that impls this closure kind + /// Returns `true` if a type that impls this closure kind /// must also implement `other`. pub fn extends(self, other: ty::ClosureKind) -> bool { match (self, other) { diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 496e620dd9df6..1d74108585360 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -112,6 +112,30 @@ impl NonConstOp for Abort { } } +#[derive(Debug)] +pub struct FloatingPointOp; +impl NonConstOp for FloatingPointOp { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_fn_floating_point_arithmetic) + } else { + Status::Allowed + } + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_floating_point_arithmetic, + span, + &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), + ) + .emit(); + } +} + #[derive(Debug)] pub struct NonPrimitiveOp; impl NonConstOp for NonPrimitiveOp { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index dc28ba46d7cbb..73725c7b98eee 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -540,8 +540,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Rvalue::UnaryOp(_, ref operand) => { let ty = operand.ty(self.body, self.tcx); - if !(ty.is_integral() || ty.is_bool()) { - self.check_op(ops::NonPrimitiveOp) + if is_int_bool_or_char(ty) { + // Int, bool, and char operations are fine. + } else if ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); } } @@ -550,7 +554,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { let lhs_ty = lhs.ty(self.body, self.tcx); let rhs_ty = rhs.ty(self.body, self.tcx); - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { + if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) { + // Int, bool, and char operations are fine. + } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { assert_eq!(lhs_ty, rhs_ty); assert!( op == BinOp::Eq @@ -563,12 +569,15 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { ); self.check_op(ops::RawPtrComparison); - } - - if !(lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char()) - || !(rhs_ty.is_integral() || rhs_ty.is_bool() || rhs_ty.is_char()) - { - self.check_op(ops::NonPrimitiveOp) + } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!( + self.span, + "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}", + lhs_ty, + rhs_ty + ); } } } @@ -867,3 +876,7 @@ fn place_as_reborrow( } }) } + +fn is_int_bool_or_char(ty: Ty<'_>) -> bool { + ty.is_bool() || ty.is_integral() || ty.is_char() +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2d5c6451d1a52..4447564c8b4c5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -351,6 +351,7 @@ symbols! { const_evaluatable_checked, const_extern_fn, const_fn, + const_fn_floating_point_arithmetic, const_fn_transmute, const_fn_union, const_generics, diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs new file mode 100644 index 0000000000000..638c52d97f1e3 --- /dev/null +++ b/compiler/rustc_target/src/asm/mips.rs @@ -0,0 +1,132 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Mips MipsInlineAsmRegClass { + reg, + freg, + } +} + +impl MipsInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg => types! { _: I8, I16, I32, F32; }, + Self::freg => types! { _: F32; }, + } + } +} + +// The reserved registers are somewhat taken from . +def_regs! { + Mips MipsInlineAsmReg MipsInlineAsmRegClass { + v0: reg = ["$2", "$v0"], + v1: reg = ["$3", "$v1"], + a0: reg = ["$4", "$a0"], + a1: reg = ["$5", "$a1"], + a2: reg = ["$6", "$a2"], + a3: reg = ["$7", "$a3"], + // FIXME: Reserve $t0, $t1 if in mips16 mode. + t0: reg = ["$8", "$t0"], + t1: reg = ["$9", "$t1"], + t2: reg = ["$10", "$t2"], + t3: reg = ["$11", "$t3"], + t4: reg = ["$12", "$t4"], + t5: reg = ["$13", "$t5"], + t6: reg = ["$14", "$t6"], + t7: reg = ["$15", "$t7"], + s0: reg = ["$16", "$s0"], + s1: reg = ["$17", "$s1"], + s2: reg = ["$18", "$s2"], + s3: reg = ["$19", "$s3"], + s4: reg = ["$20", "$s4"], + s5: reg = ["$21", "$s5"], + s6: reg = ["$22", "$s6"], + s7: reg = ["$23", "$s7"], + t8: reg = ["$24", "$t8"], + t9: reg = ["$25", "$t9"], + f0: freg = ["$f0"], + f1: freg = ["$f1"], + f2: freg = ["$f2"], + f3: freg = ["$f3"], + f4: freg = ["$f4"], + f5: freg = ["$f5"], + f6: freg = ["$f6"], + f7: freg = ["$f7"], + f8: freg = ["$f8"], + f9: freg = ["$f9"], + f10: freg = ["$f10"], + f11: freg = ["$f11"], + f12: freg = ["$f12"], + f13: freg = ["$f13"], + f14: freg = ["$f14"], + f15: freg = ["$f15"], + f16: freg = ["$f16"], + f17: freg = ["$f17"], + f18: freg = ["$f18"], + f19: freg = ["$f19"], + f20: freg = ["$f20"], + f21: freg = ["$f21"], + f22: freg = ["$f22"], + f23: freg = ["$f23"], + f24: freg = ["$f24"], + f25: freg = ["$f25"], + f26: freg = ["$f26"], + f27: freg = ["$f27"], + f28: freg = ["$f28"], + f29: freg = ["$f29"], + f30: freg = ["$f30"], + f31: freg = ["$f31"], + #error = ["$0", "$zero"] => + "constant zero cannot be used as an operand for inline asm", + #error = ["$1", "$at"] => + "reserved for assembler (Assembler Temp)", + #error = ["$26", "$k0"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$27", "$k1"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$28", "$gp"] => + "the global pointer cannot be used as an operand for inline asm", + #error = ["$29", "$sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["$30", "$s8", "$fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["$31", "$ra"] => + "the return address register cannot be used as an operand for inline asm", + } +} + +impl MipsInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index c22644bf813a4..e2f8e91fa9574 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -152,6 +152,7 @@ macro_rules! types { mod aarch64; mod arm; mod hexagon; +mod mips; mod nvptx; mod riscv; mod x86; @@ -159,6 +160,7 @@ mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; +pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -173,6 +175,7 @@ pub enum InlineAsmArch { RiscV64, Nvptx64, Hexagon, + Mips, } impl FromStr for InlineAsmArch { @@ -188,6 +191,7 @@ impl FromStr for InlineAsmArch { "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), "hexagon" => Ok(Self::Hexagon), + "mips" => Ok(Self::Mips), _ => Err(()), } } @@ -201,6 +205,7 @@ pub enum InlineAsmReg { RiscV(RiscVInlineAsmReg), Nvptx(NvptxInlineAsmReg), Hexagon(HexagonInlineAsmReg), + Mips(MipsInlineAsmReg), } impl InlineAsmReg { @@ -211,6 +216,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -221,6 +227,7 @@ impl InlineAsmReg { Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), + Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), } } @@ -252,6 +259,9 @@ impl InlineAsmReg { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) } + InlineAsmArch::Mips => { + Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?) + } }) } @@ -269,6 +279,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), Self::Hexagon(r) => r.emit(out, arch, modifier), + Self::Mips(r) => r.emit(out, arch, modifier), } } @@ -279,6 +290,7 @@ impl InlineAsmReg { Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), + Self::Mips(_) => cb(self), } } } @@ -291,6 +303,7 @@ pub enum InlineAsmRegClass { RiscV(RiscVInlineAsmRegClass), Nvptx(NvptxInlineAsmRegClass), Hexagon(HexagonInlineAsmRegClass), + Mips(MipsInlineAsmRegClass), } impl InlineAsmRegClass { @@ -302,6 +315,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.name(), Self::Nvptx(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -316,6 +330,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), + Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), } } @@ -337,6 +352,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_modifier(arch, ty), Self::Nvptx(r) => r.suggest_modifier(arch, ty), Self::Hexagon(r) => r.suggest_modifier(arch, ty), + Self::Mips(r) => r.suggest_modifier(arch, ty), } } @@ -354,6 +370,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.default_modifier(arch), Self::Nvptx(r) => r.default_modifier(arch), Self::Hexagon(r) => r.default_modifier(arch), + Self::Mips(r) => r.default_modifier(arch), } } @@ -370,6 +387,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.supported_types(arch), Self::Nvptx(r) => r.supported_types(arch), Self::Hexagon(r) => r.supported_types(arch), + Self::Mips(r) => r.supported_types(arch), } } @@ -391,6 +409,7 @@ impl InlineAsmRegClass { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) } + InlineAsmArch::Mips => Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?), }) }) } @@ -405,6 +424,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.valid_modifiers(arch), Self::Nvptx(r) => r.valid_modifiers(arch), Self::Hexagon(r) => r.valid_modifiers(arch), + Self::Mips(r) => r.valid_modifiers(arch), } } } @@ -545,5 +565,10 @@ pub fn allocatable_registers( hexagon::fill_reg_map(arch, has_feature, target, &mut map); map } + InlineAsmArch::Mips => { + let mut map = mips::regclass_map(); + mips::fill_reg_map(arch, has_feature, target, &mut map); + map + } } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 63ca6e517d214..30fb87b022645 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -82,6 +82,7 @@ #![feature(const_pin)] #![feature(const_fn_union)] #![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] #![feature(const_generics)] #![feature(const_option)] #![feature(const_precise_live_drops)] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 546edef7f5753..f4f7a84f2ef3c 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -319,6 +319,13 @@ pub(super) trait SplitIter: DoubleEndedIterator { /// /// This struct is created by the [`split`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split(|num| num % 3 == 0); +/// ``` +/// /// [`split`]: ../../std/primitive.slice.html#method.split /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -434,6 +441,15 @@ impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} /// /// This struct is created by the [`split_inclusive`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split_inclusive(|num| num % 3 == 0); +/// ``` +/// /// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "split_inclusive", issue = "72360")] @@ -539,6 +555,13 @@ impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool /// /// This struct is created by the [`split_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_mut(|num| *num % 3 == 0); +/// ``` +/// /// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -661,6 +684,15 @@ impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} /// /// This struct is created by the [`split_inclusive_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); +/// ``` +/// /// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "split_inclusive", issue = "72360")] @@ -775,6 +807,13 @@ impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b /// /// This struct is created by the [`rsplit`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit(|num| *num == 0); +/// ``` +/// /// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit /// [slices]: ../../std/primitive.slice.html #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -854,6 +893,13 @@ impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} /// /// This struct is created by the [`rsplit_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit_mut(|num| *num == 0); +/// ``` +/// /// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -966,6 +1012,13 @@ impl> Iterator for GenericSplitN { /// /// This struct is created by the [`splitn`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn(2, |num| *num % 3 == 0); +/// ``` +/// /// [`splitn`]: ../../std/primitive.slice.html#method.splitn /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -999,6 +1052,13 @@ where /// /// This struct is created by the [`rsplitn`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// ``` +/// /// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -1031,6 +1091,13 @@ where /// /// This struct is created by the [`splitn_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// /// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -1064,6 +1131,13 @@ where /// /// This struct is created by the [`rsplitn_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// /// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] @@ -1100,6 +1174,13 @@ forward_iterator! { RSplitNMut: T, &'a mut [T] } /// /// This struct is created by the [`windows`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['r', 'u', 's', 't']; +/// let iter = slice.windows(2); +/// ``` +/// /// [`windows`]: ../../std/primitive.slice.html#method.windows /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -1239,6 +1320,13 @@ unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { /// /// This struct is created by the [`chunks`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks(2); +/// ``` +/// /// [`chunks`]: ../../std/primitive.slice.html#method.chunks /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -1400,6 +1488,13 @@ unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { /// /// This struct is created by the [`chunks_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_mut(2); +/// ``` +/// /// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -1559,6 +1654,13 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { /// /// This struct is created by the [`chunks_exact`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact(2); +/// ``` +/// /// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact /// [`remainder`]: ChunksExact::remainder /// [slices]: ../../std/primitive.slice.html @@ -1708,6 +1810,13 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { /// /// This struct is created by the [`chunks_exact_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact_mut(2); +/// ``` +/// /// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut /// [`into_remainder`]: ChunksExactMut::into_remainder /// [slices]: ../../std/primitive.slice.html @@ -1850,6 +1959,15 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { /// /// This struct is created by the [`array_windows`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(array_windows)] +/// +/// let slice = [0, 1, 2, 3]; +/// let iter = slice.array_windows::<2>(); +/// ``` +/// /// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows /// [slices]: ../../std/primitive.slice.html #[derive(Debug, Clone, Copy)] @@ -1962,6 +2080,15 @@ impl ExactSizeIterator for ArrayWindows<'_, T, N> { /// /// This struct is created by the [`array_chunks`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks::<2>(); +/// ``` +/// /// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks /// [`remainder`]: ArrayChunks::remainder /// [slices]: ../../std/primitive.slice.html @@ -2080,6 +2207,15 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> /// /// This struct is created by the [`array_chunks_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks_mut::<2>(); +/// ``` +/// /// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut /// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html @@ -2190,6 +2326,13 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, /// /// This struct is created by the [`rchunks`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks(2); +/// ``` +/// /// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -2347,6 +2490,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { /// /// This struct is created by the [`rchunks_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_mut(2); +/// ``` +/// /// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] @@ -2503,6 +2653,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { /// /// This struct is created by the [`rchunks_exact`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact(2); +/// ``` +/// /// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact /// [`remainder`]: ChunksExact::remainder /// [slices]: ../../std/primitive.slice.html @@ -2656,6 +2813,13 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { /// /// This struct is created by the [`rchunks_exact_mut`] method on [slices]. /// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact_mut(2); +/// ``` +/// /// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut /// [`into_remainder`]: ChunksExactMut::into_remainder /// [slices]: ../../std/primitive.slice.html diff --git a/library/std/src/io/lazy.rs b/library/std/src/io/lazy.rs deleted file mode 100644 index 1968d498bbed4..0000000000000 --- a/library/std/src/io/lazy.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::cell::Cell; -use crate::ptr; -use crate::sync::Arc; -use crate::sys_common; -use crate::sys_common::mutex::Mutex; - -pub struct Lazy { - // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! - lock: Mutex, - ptr: Cell<*mut Arc>, -} - -#[inline] -const fn done() -> *mut Arc { - 1_usize as *mut _ -} - -unsafe impl Sync for Lazy {} - -impl Lazy { - pub const fn new() -> Lazy { - Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()) } - } -} - -impl Lazy { - /// Safety: `init` must not call `get` on the variable that is being - /// initialized. - pub unsafe fn get(&'static self, init: fn() -> Arc) -> Option> { - let _guard = self.lock.lock(); - let ptr = self.ptr.get(); - if ptr.is_null() { - Some(self.init(init)) - } else if ptr == done() { - None - } else { - Some((*ptr).clone()) - } - } - - // Must only be called with `lock` held - unsafe fn init(&'static self, init: fn() -> Arc) -> Arc { - // If we successfully register an at exit handler, then we cache the - // `Arc` allocation in our own internal box (it will get deallocated by - // the at exit handler). Otherwise we just return the freshly allocated - // `Arc`. - let registered = sys_common::at_exit(move || { - let ptr = { - let _guard = self.lock.lock(); - self.ptr.replace(done()) - }; - drop(Box::from_raw(ptr)) - }); - // This could reentrantly call `init` again, which is a problem - // because our `lock` allows reentrancy! - // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens. - let ret = init(); - if registered.is_ok() { - self.ptr.set(Box::into_raw(Box::new(ret.clone()))); - } - ret - } -} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index adea8a804e3ca..d9d0380781925 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -285,7 +285,6 @@ mod buffered; mod cursor; mod error; mod impls; -mod lazy; pub mod prelude; mod stdio; mod util; diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 71ed2d84cad0d..61ccc6f13c8da 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -7,10 +7,11 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; -use crate::io::lazy::Lazy; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; -use crate::sync::{Arc, Mutex, MutexGuard, Once}; +use crate::lazy::SyncOnceCell; +use crate::sync::{Mutex, MutexGuard}; use crate::sys::stdio; +use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; @@ -217,7 +218,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { - inner: Arc>>, + inner: &'static Mutex>, } /// A locked reference to the `Stdin` handle. @@ -292,15 +293,11 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>> = Lazy::new(); - return Stdin { - inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") }, - }; - - fn stdin_init() -> Arc>> { - // This must not reentrantly access `INSTANCE` - let stdin = stdin_raw(); - Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + Stdin { + inner: INSTANCE.get_or_init(|| { + Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) + }), } } @@ -476,7 +473,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the `Stdout` handle. @@ -534,19 +531,27 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>> = Lazy::new(); - return Stdout { - inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") }, - }; - - fn stdout_init() -> Arc>>> { - // This must not reentrantly access `INSTANCE` - let stdout = stdout_raw(); - unsafe { - let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))); - ret.init(); - ret - } + static INSTANCE: SyncOnceCell>>> = + SyncOnceCell::new(); + Stdout { + inner: INSTANCE.get_or_init(|| unsafe { + let _ = sys_common::at_exit(|| { + if let Some(instance) = INSTANCE.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = instance.try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } + } + }); + let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))); + r.init(); + r + }), } } @@ -741,16 +746,15 @@ pub fn stderr() -> Stderr { // // This has the added benefit of allowing `stderr` to be usable during // process shutdown as well! - static INSTANCE: ReentrantMutex> = - unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }; - - // When accessing stderr we need one-time initialization of the reentrant - // mutex. Afterwards we can just always use the now-filled-in `INSTANCE` value. - static INIT: Once = Once::new(); - INIT.call_once(|| unsafe { - INSTANCE.init(); - }); - Stderr { inner: &INSTANCE } + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + + Stderr { + inner: INSTANCE.get_or_init(|| unsafe { + let r = ReentrantMutex::new(RefCell::new(stderr_raw())); + r.init(); + r + }), + } } impl Stderr { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ac0075ad129c5..d03428dd08282 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -236,6 +236,7 @@ #![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] #![feature(const_fn_transmute)] #![feature(const_fn)] #![feature(const_ip)] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 9f3796e11ed1a..3d238b7f764ef 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -110,6 +110,8 @@ use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; use crate::sys::process as imp; +#[unstable(feature = "command_access", issue = "44434")] +pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// Representation of a running or exited child process. @@ -894,6 +896,98 @@ impl Command { .map(Child::from_inner) .and_then(|mut p| p.wait()) } + + /// Returns the path to the program that was given to [`Command::new`]. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::process::Command; + /// + /// let cmd = Command::new("echo"); + /// assert_eq!(cmd.get_program(), "echo"); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_program(&self) -> &OsStr { + self.inner.get_program() + } + + /// Returns an iterator of the arguments that will be passed to the program. + /// + /// This does not include the path to the program as the first argument; + /// it only includes the arguments specified with [`Command::arg`] and + /// [`Command::args`]. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("echo"); + /// cmd.arg("first").arg("second"); + /// let args: Vec<&OsStr> = cmd.get_args().collect(); + /// assert_eq!(args, &["first", "second"]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { inner: self.inner.get_args() } + } + + /// Returns an iterator of the environment variables that will be set when + /// the process is spawned. + /// + /// Each element is a tuple `(&OsStr, Option<&OsStr>)`, where the first + /// value is the key, and the second is the value, which is [`None`] if + /// the environment variable is to be explicitly removed. + /// + /// This only includes environment variables explicitly set with + /// [`Command::env`], [`Command::envs`], and [`Command::env_remove`]. It + /// does not include environment variables that will be inherited by the + /// child process. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// cmd.env("TERM", "dumb").env_remove("TZ"); + /// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect(); + /// assert_eq!(envs, &[ + /// (OsStr::new("TERM"), Some(OsStr::new("dumb"))), + /// (OsStr::new("TZ"), None) + /// ]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.inner.get_envs() + } + + /// Returns the working directory for the child process. + /// + /// This returns [`None`] if the working directory will not be changed. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::path::Path; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// assert_eq!(cmd.get_current_dir(), None); + /// cmd.current_dir("/bin"); + /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin"))); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_current_dir(&self) -> Option<&Path> { + self.inner.get_current_dir() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -918,6 +1012,37 @@ impl AsInnerMut for Command { } } +/// An iterator over the command arguments. +/// +/// This struct is created by [`Command::get_args`]. See its documentation for +/// more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandArgs<'a> { + inner: imp::CommandArgs<'a>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.inner.next() + } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.inner.len() + } + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + /// The output of a finished process. /// /// This is returned in a Result by either the [`output`] method of a diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index eddf00d3979f5..b48d2162eca92 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -75,6 +75,13 @@ pub use crate::sys_common::os_str_bytes as os_str; #[cfg(not(test))] pub fn init() { + // The standard streams might be closed on application startup. To prevent + // std::io::{stdin, stdout,stderr} objects from using other unrelated file + // resources opened later, we reopen standards streams when they are closed. + unsafe { + sanitize_standard_fds(); + } + // By default, some platforms will send a *signal* when an EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE // handler, causing it to kill the program, which isn't exactly what we @@ -86,6 +93,61 @@ pub fn init() { reset_sigpipe(); } + // In the case when all file descriptors are open, the poll has been + // observed to perform better than fcntl (on GNU/Linux). + #[cfg(not(any( + miri, + target_os = "emscripten", + target_os = "fuchsia", + // The poll on Darwin doesn't set POLLNVAL for closed fds. + target_os = "macos", + target_os = "ios", + target_os = "redox", + )))] + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + let pfds: &mut [_] = &mut [ + libc::pollfd { fd: 0, events: 0, revents: 0 }, + libc::pollfd { fd: 1, events: 0, revents: 0 }, + libc::pollfd { fd: 2, events: 0, revents: 0 }, + ]; + while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 { + if errno() == libc::EINTR { + continue; + } + libc::abort(); + } + for pfd in pfds { + if pfd.revents & libc::POLLNVAL == 0 { + continue; + } + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + // If the stream is closed but we failed to reopen it, abort the + // process. Otherwise we wouldn't preserve the safety of + // operations on the corresponding Rust object Stdin, Stdout, or + // Stderr. + libc::abort(); + } + } + } + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + for fd in 0..3 { + if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + libc::abort(); + } + } + } + } + #[cfg(any( + // The standard fds are always available in Miri. + miri, + target_os = "emscripten", + target_os = "fuchsia"))] + unsafe fn sanitize_standard_fds() {} + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 553e980f08e97..1b7b93f9d4a5f 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -1,6 +1,7 @@ -pub use self::process_common::{Command, ExitCode, Stdio, StdioPipes}; +pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::{ExitStatus, Process}; pub use crate::ffi::OsString as EnvKey; +pub use crate::sys_common::process::CommandEnvs; mod process_common; #[cfg(not(target_os = "fuchsia"))] diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index f8666485eeccb..9ddd4ad4000ef 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -7,11 +7,12 @@ use crate::collections::BTreeMap; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io; +use crate::path::Path; use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -184,11 +185,30 @@ impl Command { pub fn saw_nul(&self) -> bool { self.saw_nul } + + pub fn get_program(&self) -> &OsStr { + OsStr::from_bytes(self.program.as_bytes()) + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let mut iter = self.args.iter(); + iter.next(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes()))) + } + pub fn get_argv(&self) -> &Vec<*const c_char> { &self.argv.0 } - pub fn get_program(&self) -> &CStr { + pub fn get_program_cstr(&self) -> &CStr { &*self.program } @@ -402,3 +422,32 @@ impl ExitCode { self.0 as i32 } } + +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, CString>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() + } +} diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 08efe154e4c3b..50f5e78cf2a88 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -245,7 +245,7 @@ impl Command { *sys::os::environ() = envp.as_ptr(); } - libc::execvp(self.get_program().as_ptr(), self.get_argv().as_ptr()); + libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr()); Err(io::Error::last_os_error()) } @@ -383,7 +383,7 @@ impl Command { let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); let ret = libc::posix_spawnp( &mut p.pid, - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), file_actions.0.as_ptr(), attrs.0.as_ptr(), self.get_argv().as_ptr() as *const _, diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 7156c9ab92f2b..3ede2291d5a91 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -1,10 +1,12 @@ use crate::ffi::OsStr; use crate::fmt; use crate::io; +use crate::marker::PhantomData; +use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; @@ -49,6 +51,22 @@ impl Command { pub fn stderr(&mut self, _stderr: Stdio) {} + pub fn get_program(&self) -> &OsStr { + panic!("unsupported") + } + + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { _p: PhantomData } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + None + } + pub fn spawn( &mut self, _default: Stdio, @@ -147,3 +165,22 @@ impl Process { match self.0 {} } } + +pub struct CommandArgs<'a> { + _p: PhantomData<&'a ()>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + None + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> {} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().finish() + } +} diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index e18521bb30d91..243065b94b125 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -22,7 +22,7 @@ use crate::sys::handle::Handle; use crate::sys::mutex::Mutex; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::AsInner; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -134,6 +134,23 @@ impl Command { self.flags = flags; } + pub fn get_program(&self) -> &OsStr { + &self.program + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let iter = self.args.iter(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cwd| Path::new(cwd)) + } + pub fn spawn( &mut self, default: Stdio, @@ -529,3 +546,32 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { None => Ok((ptr::null(), Vec::new())), } } + +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, OsString>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|s| s.as_ref()) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() + } +} diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index f3a2962098b4d..fe89b11043c0f 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -92,4 +92,41 @@ impl CommandEnv { self.saw_path = true; } } + + pub fn iter(&self) -> CommandEnvs<'_> { + let iter = self.vars.iter(); + CommandEnvs { iter } + } +} + +/// An iterator over the command environment variables. +/// +/// This struct is created by +/// [`Command::get_envs`][crate::process::Command::get_envs]. See its +/// documentation for more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandEnvs<'a> { + iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + fn next(&mut self) -> Option { + self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md index 1510f4d59fa34..dfb39c54c1723 100644 --- a/src/bootstrap/CHANGELOG.md +++ b/src/bootstrap/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Non-breaking changes since the last major version] +- Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631) - Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626) - Optionally, download LLVM from CI on Linux and NixOS + [#76439](https://github.com/rust-lang/rust/pull/76349) diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index 6af13fc83d0ef..637083e08d510 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -7,21 +7,34 @@ use std::env; -use bootstrap::{Build, Config}; +use bootstrap::{Build, Config, Subcommand}; fn main() { let args = env::args().skip(1).collect::>(); let config = Config::parse(&args); let changelog_suggestion = check_version(&config); - if let Some(suggestion) = &changelog_suggestion { + + // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the + // changelog warning, not the `x.py setup` message. + let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. }); + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { println!("{}", suggestion); } Build::new(config).build(); - if let Some(suggestion) = changelog_suggestion { + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { println!("{}", suggestion); + } + + if suggest_setup || changelog_suggestion.is_some() { println!("note: this message was printed twice to make it more likely to be seen"); } } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d2537d65e67f5..4aaaeb8a93bda 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -549,7 +549,9 @@ impl<'a> Builder<'a> { Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), Subcommand::Install { ref paths } => (Kind::Install, &paths[..]), Subcommand::Run { ref paths } => (Kind::Run, &paths[..]), - Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), + Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => { + panic!() + } }; Self::new_internal(build, kind, paths.to_owned()) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 53fef7a838df6..b14746dabb93a 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -73,6 +73,8 @@ pub struct Config { pub keep_stage: Vec, pub keep_stage_std: Vec, pub src: PathBuf, + // defaults to `config.toml` + pub config: PathBuf, pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, @@ -513,6 +515,7 @@ impl Config { config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.deny_warnings = true; config.missing_tools = false; + config.config = PathBuf::from("config.toml"); // set by bootstrap.py config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); @@ -558,7 +561,7 @@ impl Config { let get_toml = |file: PathBuf| { use std::process; - let contents = t!(fs::read_to_string(&file), "configuration file did not exist"); + let contents = t!(fs::read_to_string(&file), "`include` config not found"); match toml::from_str(&contents) { Ok(table) => table, Err(err) => { @@ -644,6 +647,7 @@ impl Config { | Subcommand::Clippy { .. } | Subcommand::Fix { .. } | Subcommand::Run { .. } + | Subcommand::Setup { .. } | Subcommand::Format { .. } => flags.stage.unwrap_or(0), }; @@ -668,6 +672,7 @@ impl Config { | Subcommand::Clippy { .. } | Subcommand::Fix { .. } | Subcommand::Run { .. } + | Subcommand::Setup { .. } | Subcommand::Format { .. } => {} } } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index dad31fc77be17..a12fc50afad58 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -7,6 +7,7 @@ use std::env; use std::path::PathBuf; use std::process; +use build_helper::t; use getopts::Options; use crate::builder::Builder; @@ -89,6 +90,9 @@ pub enum Subcommand { Run { paths: Vec, }, + Setup { + path: String, + }, } impl Default for Subcommand { @@ -199,6 +203,7 @@ To learn more about a subcommand, run `./x.py -h`", || (s == "install") || (s == "run") || (s == "r") + || (s == "setup") }); let subcommand = match subcommand { Some(s) => s, @@ -453,10 +458,21 @@ Arguments: At least a tool needs to be called.", ); } + "setup" => { + subcommand_help.push_str( + "\n +Arguments: + This subcommand accepts a 'profile' to use for builds. For example: + + ./x.py setup library + + The profile is optional and you will be prompted interactively if it is not given.", + ); + } _ => {} }; // Get any optional paths which occur after the subcommand - let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); + let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); let verbose = matches.opt_present("verbose"); @@ -508,6 +524,20 @@ Arguments: } Subcommand::Run { paths } } + "setup" => { + let path = if paths.len() > 1 { + println!("\nat most one profile can be passed to setup\n"); + usage(1, &opts, verbose, &subcommand_help) + } else if let Some(path) = paths.pop() { + t!(path.into_os_string().into_string().map_err(|path| format!( + "{} is not a valid UTF8 string", + path.to_string_lossy() + ))) + } else { + t!(crate::setup::interactive_path()) + }; + Subcommand::Setup { path } + } _ => { usage(1, &opts, verbose, &subcommand_help); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 3f7aeae0ed495..4cc72f5f39c97 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -141,6 +141,7 @@ mod metadata; mod native; mod run; mod sanity; +mod setup; mod test; mod tool; mod toolstate; @@ -165,7 +166,7 @@ mod job { use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; -use crate::flags::Subcommand; +pub use crate::flags::Subcommand; const LLVM_TOOLS: &[&str] = &[ "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility @@ -470,6 +471,10 @@ impl Build { return clean::clean(self, all); } + if let Subcommand::Setup { path: include_name } = &self.config.cmd { + return setup::setup(&self.config.src, include_name); + } + { let builder = builder::Builder::new(&self); if let Some(path) = builder.paths.get(0) { diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 900534714277c..ba593cadbad81 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -10,7 +10,7 @@ impl Step for ExpandYamlAnchors { /// Runs the `expand-yaml_anchors` tool. /// - /// This tool in `src/tools` read the CI configuration files written in YAML and expands the + /// This tool in `src/tools` reads the CI configuration files written in YAML and expands the /// anchors in them, since GitHub Actions doesn't support them. fn run(self, builder: &Builder<'_>) { builder.info("Expanding YAML anchors in the GitHub Actions configuration"); diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs new file mode 100644 index 0000000000000..9d3a889aa008e --- /dev/null +++ b/src/bootstrap/setup.rs @@ -0,0 +1,88 @@ +use crate::t; +use std::path::{Path, PathBuf}; +use std::{ + env, fs, + io::{self, Write}, +}; + +pub fn setup(src_path: &Path, include_name: &str) { + let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); + + if cfg_file.as_ref().map_or(false, |f| f.exists()) { + let file = cfg_file.unwrap(); + println!( + "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", + file.display() + ); + println!( + "help: try adding `profile = \"{}\"` at the top of {}", + include_name, + file.display() + ); + println!( + "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}", + src_path.display(), + include_name + ); + std::process::exit(1); + } + + let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml")); + let settings = format!( + "# Includes one of the default files in src/bootstrap/defaults\n\ + profile = \"{}\"\n", + include_name + ); + t!(fs::write(path, settings)); + + let include_path = + format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name); + println!("`x.py` will now use the configuration at {}", include_path); + + let suggestions = match include_name { + "codegen" | "compiler" => &["check", "build", "test"][..], + "library" => &["check", "build", "test library/std", "doc"], + "user" => &["dist", "build"], + _ => return, + }; + + println!("To get started, try one of the following commands:"); + for cmd in suggestions { + println!("- `x.py {}`", cmd); + } + + if include_name != "user" { + println!( + "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" + ); + } +} + +// Used to get the path for `Subcommand::Setup` +pub fn interactive_path() -> io::Result { + let mut input = String::new(); + println!( + "Welcome to the Rust project! What do you want to do with x.py? +a) Contribute to the standard library +b) Contribute to the compiler +c) Contribute to the compiler, and also modify LLVM or codegen +d) Install Rust from source" + ); + let template = loop { + print!("Please choose one (a/b/c/d): "); + io::stdout().flush()?; + io::stdin().read_line(&mut input)?; + break match input.trim().to_lowercase().as_str() { + "a" | "lib" | "library" => "library", + "b" | "compiler" => "compiler", + "c" | "llvm" => "llvm", + "d" | "user" | "maintainer" => "maintainer", + _ => { + println!("error: unrecognized option '{}'", input.trim()); + println!("note: press Ctrl+C to exit"); + continue; + } + }; + }; + Ok(template.to_owned()) +} diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index df113f0f1613c..9bed06d323e08 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -27,6 +27,7 @@ Inline assembly is currently supported on the following architectures: - RISC-V - NVPTX - Hexagon +- MIPS32 ## Basic usage @@ -512,6 +513,8 @@ Here is the list of currently supported register classes: | ARM | `qreg` | `q[0-15]` | `w` | | ARM | `qreg_low8` | `q[0-7]` | `t` | | ARM | `qreg_low4` | `q[0-3]` | `x` | +| MIPS32 | `reg` | `$[2-25]` | `r` | +| MIPS32 | `freg` | `$f[0-31]` | `f` | | NVPTX | `reg16` | None\* | `h` | | NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg64` | None\* | `l` | @@ -547,6 +550,8 @@ Each register class has constraints on which value types they can be used with. | ARM | `sreg` | `vfp2` | `i32`, `f32` | | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` | | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` | +| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| MIPS32 | `freg` | None | `f32` | | NVPTX | `reg16` | None | `i8`, `i16` | | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | @@ -595,6 +600,7 @@ Some registers have multiple names. These are all treated by the compiler as ide | ARM | `r13` | `sp` | | ARM | `r14` | `lr` | | ARM | `r15` | `pc` | +| MIPS32 | `$[2-25]` | Please [see the Wikipedia page][mips-regs] | | RISC-V | `x0` | `zero` | | RISC-V | `x1` | `ra` | | RISC-V | `x2` | `sp` | @@ -615,12 +621,14 @@ Some registers have multiple names. These are all treated by the compiler as ide | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | +[mips-regs]: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File#Registers + Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | | ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. | | x86 | `k0` | This is a constant zero register which can't be modified. | @@ -629,6 +637,11 @@ Some registers cannot be used for input or output operands: | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | ARM | `pc` | This is the program counter, not a real register. | +| MIPS32 | `$0` or `$zero` | This is a constant zero register which can't be modified. | +| MIPS32 | `$1` or `$at` | Reserved for assembler. | +| MIPS32 | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | +| MIPS32 | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | +| MIPS32 | `$ra` | Return address cannot be used as inputs or outputs. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | @@ -676,6 +689,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `dreg` | None | `d0` | `P` | | ARM | `qreg` | None | `q0` | `q` | | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | +| MIPS32 | `reg` | None | `$2` | None | +| MIPS32 | `freg` | None | `$f0` | None | | NVPTX | `reg16` | None | `rs0` | None | | NVPTX | `reg32` | None | `r0` | None | | NVPTX | `reg64` | None | `rd0` | None | diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs new file mode 100644 index 0000000000000..d23bcedd1fa3a --- /dev/null +++ b/src/test/assembly/asm/mips-types.rs @@ -0,0 +1,191 @@ +// no-system-llvm +// assembly-output: emit-asm +// compile-flags: --target mips-unknown-linux-gnu +// needs-llvm-components: mips + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!("move {}, {}", out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!("move ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: lw $3, %got(extern_static) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: lw $3, %got(extern_func) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_func); +} + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mov.s $f0, $f{{(2[0-9])|(3[0-1])}} +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn reg_f32(x: f32) -> f32 { + dont_merge("reg_f32"); + let y; + asm!("mov.s {}, {}", out(freg) y, in(freg) x); + y +} + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: mov.s $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn f0_f32(x: f32) -> f32 { + dont_merge("f0_f32"); + let y; + asm!("mov.s $f0, $f0", lateout("$f0") y, in("$f0") x); + y +} + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[2-3]}}, ${{(1[6-9])|(2[0-3])}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[2-3]}}, ${{(1[6-9])|(2[0-3])}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg); + +// CHECK-LABEL: reg_f32_soft: +// CHECK: #APP +// CHECK: move ${{[2-3]}}, $1 +// CHECK: #NO_APP +check!(reg_f32_soft, f32, reg); + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[2-3]}}, $1 +// CHECK: #NO_APP +check!(reg_i8, i8, reg); + +// CHECK-LABEL: reg_u8: +// CHECK: #APP +// CHECK: move ${{[2-3]}}, $1 +// CHECK: #NO_APP +check!(reg_u8, u8, reg); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[2-3]}}, $1 +// CHECK: #NO_APP +check!(reg_i16, i16, reg); + +// CHECK-LABEL: t0_ptr: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_ptr, ptr, "$t0"); + +// CHECK-LABEL: t0_i32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i32, i32, "$t0"); + +// CHECK-LABEL: t0_f32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_f32, f32, "$t0"); + +// CHECK-LABEL: t0_i8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i8, i8, "$t0"); + +// CHECK-LABEL: t0_u8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_u8, u8, "$t0"); + +// CHECK-LABEL: t0_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i16, i16, "$t0"); + +// CHECK-LABEL: r8_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i16, i16, "$8"); diff --git a/src/test/ui/closed-std-fds.rs b/src/test/ui/closed-std-fds.rs new file mode 100644 index 0000000000000..906da94433455 --- /dev/null +++ b/src/test/ui/closed-std-fds.rs @@ -0,0 +1,69 @@ +// Verifies that std provides replacement for the standard file descriptors when they are missing. +// +// run-pass +// ignore-windows unix specific test +// ignore-cloudabi no processes +// ignore-emscripten no processes +// ignore-sgx no processes + +#![feature(rustc_private)] +extern crate libc; + +use std::io::{self, Read}; +use std::os::unix::process::CommandExt; +use std::process::Command; + +fn main() { + let mut args = std::env::args(); + let argv0 = args.next().expect("argv0"); + match args.next().as_deref() { + Some("child") => child(), + None => parent(&argv0), + _ => unreachable!(), + } +} + +fn parent(argv0: &str) { + let status = unsafe { Command::new(argv0) + .arg("child") + .pre_exec(close_std_fds_on_exec) + .status() + .expect("failed to execute child process") + }; + if !status.success() { + panic!("child failed with {}", status); + } +} + +fn close_std_fds_on_exec() -> io::Result<()> { + for fd in 0..3 { + if unsafe { libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC) == -1 } { + return Err(io::Error::last_os_error()) + } + } + Ok(()) +} + +fn child() { + // Standard file descriptors should be valid. + assert_fd_is_valid(0); + assert_fd_is_valid(1); + assert_fd_is_valid(2); + + // Writing to stdout & stderr should not panic. + println!("a"); + println!("b"); + eprintln!("c"); + eprintln!("d"); + + // Stdin should be at EOF. + let mut buffer = Vec::new(); + let n = io::stdin().read_to_end(&mut buffer).unwrap(); + assert_eq!(n, 0); +} + +fn assert_fd_is_valid(fd: libc::c_int) { + if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } { + panic!("file descriptor {} is not valid {}", fd, io::Error::last_os_error()); + } +} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index e0b9e5f33759e..094ae7378bce8 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -4,7 +4,7 @@ const extern fn unsize(x: &[u8; 3]) -> &[u8] { x } const unsafe extern "C" fn closure() -> fn() { || {} } //~^ ERROR function pointers in const fn are unstable const unsafe extern fn use_float() { 1.0 + 1.0; } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR floating point arithmetic const extern "C" fn ptr_cast(val: *const u8) { val as usize; } //~^ ERROR casting pointers to integers diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 5ca44b3fa7e65..fcc34f358f9f9 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -7,14 +7,14 @@ LL | const unsafe extern "C" fn closure() -> fn() { || {} } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error[E0658]: floating point arithmetic is not allowed in constant functions --> $DIR/const-extern-fn-min-const-fn.rs:6:38 | LL | const unsafe extern fn use_float() { 1.0 + 1.0; } | ^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/const-extern-fn-min-const-fn.rs:8:48 diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr new file mode 100644 index 0000000000000..ae24f8f65009a --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/const_fn_floating_point_arithmetic.rs:20:1 + | +LL | fn main() {} + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.rs b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs new file mode 100644 index 0000000000000..5e32482b21a52 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs @@ -0,0 +1,20 @@ +// gate-test-const_fn_floating_point_arithmetic + +// revisions: stock gated + +#![feature(rustc_attrs)] +#![cfg_attr(gated, feature(const_fn_floating_point_arithmetic))] + +const fn add(f: f32) -> f32 { f + 2.0 } +//[stock]~^ floating point arithmetic +const fn sub(f: f32) -> f32 { 2.0 - f } +//[stock]~^ floating point arithmetic +const fn mul(f: f32, g: f32) -> f32 { f * g } +//[stock]~^ floating point arithmetic +const fn div(f: f32, g: f32) -> f32 { f / g } +//[stock]~^ floating point arithmetic +const fn neg(f: f32) -> f32 { -f } +//[stock]~^ floating point arithmetic + +#[rustc_error] +fn main() {} //[gated]~ fatal error triggered by #[rustc_error] diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr new file mode 100644 index 0000000000000..ef7a60faf3f5c --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr @@ -0,0 +1,48 @@ +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:8:31 + | +LL | const fn add(f: f32) -> f32 { f + 2.0 } + | ^^^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:10:31 + | +LL | const fn sub(f: f32) -> f32 { 2.0 - f } + | ^^^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:12:39 + | +LL | const fn mul(f: f32, g: f32) -> f32 { f * g } + | ^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:14:39 + | +LL | const fn div(f: f32, g: f32) -> f32 { f / g } + | ^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:16:31 + | +LL | const fn neg(f: f32) -> f32 { -f } + | ^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const_let_eq_float.rs b/src/test/ui/consts/const_let_eq_float.rs index bc0ef26eb2fe5..e15f4b804f716 100644 --- a/src/test/ui/consts/const_let_eq_float.rs +++ b/src/test/ui/consts/const_let_eq_float.rs @@ -1,6 +1,6 @@ -// build-pass (FIXME(62277): could be check-pass?) +// run-pass -#![feature(const_fn)] +#![feature(const_fn_floating_point_arithmetic)] struct Foo(T); struct Bar { x: T } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 336d754b06a73..55a999d5cdc04 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -77,14 +77,6 @@ const fn foo11(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable const fn foo11_2(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable -const fn foo19(f: f32) -> f32 { f * 2.0 } -//~^ ERROR int, `bool` and `char` operations -const fn foo19_2(f: f32) -> f32 { 2.0 - f } -//~^ ERROR int, `bool` and `char` operations -const fn foo19_3(f: f32) -> f32 { -f } -//~^ ERROR int, `bool` and `char` operations -const fn foo19_4(f: f32, g: f32) -> f32 { f / g } -//~^ ERROR int, `bool` and `char` operations static BAR: u32 = 42; const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index c96500e38ec83..a37e5203eeef4 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -76,44 +76,8 @@ LL | const fn foo11_2(t: T) -> T { t } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:80:33 - | -LL | const fn foo19(f: f32) -> f32 { f * 2.0 } - | ^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:82:35 - | -LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } - | ^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:84:35 - | -LL | const fn foo19_3(f: f32) -> f32 { -f } - | ^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:86:43 - | -LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } - | ^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - error[E0013]: constant functions cannot refer to statics - --> $DIR/min_const_fn.rs:90:27 + --> $DIR/min_const_fn.rs:82:27 | LL | const fn foo25() -> u32 { BAR } | ^^^ @@ -121,7 +85,7 @@ LL | const fn foo25() -> u32 { BAR } = help: consider extracting the value of the `static` to a `const`, and referring to that error[E0013]: constant functions cannot refer to statics - --> $DIR/min_const_fn.rs:91:37 + --> $DIR/min_const_fn.rs:83:37 | LL | const fn foo26() -> &'static u32 { &BAR } | ^^^ @@ -129,7 +93,7 @@ LL | const fn foo26() -> &'static u32 { &BAR } = help: consider extracting the value of the `static` to a `const`, and referring to that error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:92:42 + --> $DIR/min_const_fn.rs:84:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ @@ -138,7 +102,7 @@ LL | const fn foo30(x: *const u32) -> usize { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:94:63 + --> $DIR/min_const_fn.rs:86:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ @@ -147,7 +111,7 @@ LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:96:42 + --> $DIR/min_const_fn.rs:88:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ @@ -156,7 +120,7 @@ LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/min_const_fn.rs:98:63 + --> $DIR/min_const_fn.rs:90:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ @@ -165,7 +129,7 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constant functions - --> $DIR/min_const_fn.rs:101:14 + --> $DIR/min_const_fn.rs:93:14 | LL | const fn inc(x: &mut i32) { *x += 1 } | ^ @@ -174,7 +138,7 @@ LL | const fn inc(x: &mut i32) { *x += 1 } = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:110:6 + --> $DIR/min_const_fn.rs:102:6 | LL | impl Foo { | ^ @@ -183,7 +147,7 @@ LL | impl Foo { = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:115:6 + --> $DIR/min_const_fn.rs:107:6 | LL | impl Foo { | ^ @@ -192,7 +156,7 @@ LL | impl Foo { = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:120:6 + --> $DIR/min_const_fn.rs:112:6 | LL | impl Foo { | ^ @@ -201,7 +165,7 @@ LL | impl Foo { = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:126:34 + --> $DIR/min_const_fn.rs:118:34 | LL | const fn no_apit2(_x: AlanTuring) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +174,7 @@ LL | const fn no_apit2(_x: AlanTuring) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:128:22 + --> $DIR/min_const_fn.rs:120:22 | LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +183,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:129:23 + --> $DIR/min_const_fn.rs:121:23 | LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ @@ -228,7 +192,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:130:32 + --> $DIR/min_const_fn.rs:122:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +201,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:135:41 + --> $DIR/min_const_fn.rs:127:41 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -246,7 +210,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:138:21 + --> $DIR/min_const_fn.rs:130:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ @@ -255,7 +219,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:140:27 + --> $DIR/min_const_fn.rs:132:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ @@ -263,7 +227,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error: aborting due to 30 previous errors +error: aborting due to 26 previous errors Some errors have detailed explanations: E0013, E0493, E0658, E0723. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index b83fdf7c656cd..292e2dd167c91 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -25,9 +25,9 @@ const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] -// conformity is required, even with `const_fn` feature gate +// Const-stable functions cannot rely on unstable const-eval features. const fn bar3() -> u32 { (5f32 + 6f32) as u32 } -//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index a1f1f6f52ab2a..fa2260b40d19f 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -14,7 +14,7 @@ LL | const fn bar2() -> u32 { foo2() } | = help: Const-stable functions can only call other const-stable functions -error: const-stable function cannot use `#[feature(const_fn)]` +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 | LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 902ed435e31bc..0f48341ddf3ec 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -27,7 +27,7 @@ const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } -//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 2741a86440487..1ca5964ce0fc4 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -14,7 +14,7 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | = help: Const-stable functions can only call other const-stable functions -error: const-stable function cannot use `#[feature(const_fn)]` +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 | LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.rs b/src/test/ui/fmt/format-args-capture-missing-variables.rs index 3c596ae3bb899..3a4b6144b04db 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.rs +++ b/src/test/ui/fmt/format-args-capture-missing-variables.rs @@ -5,7 +5,7 @@ fn main() { //~^ ERROR: cannot find value `foo` in this scope //~^^ ERROR: cannot find value `bar` in this scope - format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope + format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope format!("{valuea} {valueb}", valuea=5, valuec=7); //~^ ERROR cannot find value `valueb` in this scope @@ -16,7 +16,7 @@ fn main() { {foo} "##); - //~^^^^^ ERROR: cannot find value `foo` in this scope + //~^^^ ERROR: cannot find value `foo` in this scope - panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope + panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope } diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.stderr b/src/test/ui/fmt/format-args-capture-missing-variables.stderr index c3d740eef9d3c..ec2faa4185b3e 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.stderr +++ b/src/test/ui/fmt/format-args-capture-missing-variables.stderr @@ -7,45 +7,40 @@ LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | formatting specifier missing error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:17 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:26 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:8:13 + --> $DIR/format-args-capture-missing-variables.rs:8:14 | LL | format!("{foo}"); - | ^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/format-args-capture-missing-variables.rs:10:13 + --> $DIR/format-args-capture-missing-variables.rs:10:23 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:14:13 + --> $DIR/format-args-capture-missing-variables.rs:16:9 | -LL | format!(r##" - | _____________^ -LL | | -LL | | {foo} -LL | | -LL | | "##); - | |_______^ not found in this scope +LL | {foo} + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:21:12 + --> $DIR/format-args-capture-missing-variables.rs:21:13 | LL | panic!("{foo} {bar}", bar=1); - | ^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error: aborting due to 7 previous errors diff --git a/src/test/ui/stdout-during-shutdown.rs b/src/test/ui/stdout-during-shutdown.rs new file mode 100644 index 0000000000000..c785fc0869610 --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.rs @@ -0,0 +1,14 @@ +// run-pass +// check-run-results + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + extern "C" fn bye() { + print!(", world!"); + } + unsafe { libc::atexit(bye) }; + print!("hello"); +} diff --git a/src/test/ui/stdout-during-shutdown.run.stdout b/src/test/ui/stdout-during-shutdown.run.stdout new file mode 100644 index 0000000000000..30f51a3fba527 --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.run.stdout @@ -0,0 +1 @@ +hello, world! \ No newline at end of file diff --git a/src/tools/cargo b/src/tools/cargo index 8777a6b1e8834..05c611ae3c425 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 8777a6b1e8834899f51b7e09cc9b8d85b2417110 +Subproject commit 05c611ae3c4255b7a2bcf4fcfa65b20286a07839 diff --git a/src/tools/miri b/src/tools/miri index 02a33d411d8e3..2f84bfc57dd0e 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 02a33d411d8e385942776760a99535d69826349b +Subproject commit 2f84bfc57dd0ef22269bb84dae10f71e5e23e85d diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index f0a6ce2fa06c2..f5e5c0867b48a 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,6 @@ edition = "2018" clap = "2.25.0" [dependencies.mdbook] -version = "0.4.0" +version = "0.4.3" default-features = false features = ["search"]