diff options
| author | Ralf Jung <post@ralfj.de> | 2025-04-27 11:11:46 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-27 11:11:46 +0000 |
| commit | 55872a19f9aa0cc9b6e8978c30758e8739ae5a17 (patch) | |
| tree | 810a1c5fc6bda4807d26ad0d0059ebf71f1ccd37 | |
| parent | ea9037e1654d2fb7e29dca87679d3c18a713f82d (diff) | |
| parent | 6c2fa0bce7c2673e6ef1a6776fcc279fa3342b72 (diff) | |
| download | rust-55872a19f9aa0cc9b6e8978c30758e8739ae5a17.tar.gz rust-55872a19f9aa0cc9b6e8978c30758e8739ae5a17.zip | |
Merge pull request #4294 from rust-lang/rustup-2025-04-26
Automatic Rustup
222 files changed, 3219 insertions, 2144 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index efe4157aae2..93316b9cff7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,6 +91,17 @@ jobs: # Check the `calculate_matrix` job to see how is the matrix defined. include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }} steps: + - name: Install cargo in AWS CodeBuild + if: matrix.codebuild + run: | + # Check if cargo is installed + if ! command -v cargo &> /dev/null; then + echo "Cargo not found, installing Rust..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal + # Make cargo available in PATH + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + fi + - name: disable git crlf conversion run: git config --global core.autocrlf false @@ -165,6 +176,8 @@ jobs: run: src/ci/scripts/install-ninja.sh - name: enable ipv6 on Docker + # Don't run on codebuild because systemctl is not available + if: ${{ !matrix.codebuild }} run: src/ci/scripts/enable-docker-ipv6.sh # Disable automatic line ending conversion (again). On Windows, when we're diff --git a/Cargo.lock b/Cargo.lock index cfdd873e80f..ee6726eae51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4158,7 +4158,6 @@ dependencies = [ "rustc_data_structures", "rustc_index", "rustc_macros", - "rustc_serialize", "rustc_type_ir", "rustc_type_ir_macros", "tracing", diff --git a/INSTALL.md b/INSTALL.md index 30e08201d6d..98eb825cd10 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -75,8 +75,31 @@ See [the rustc-dev-guide for more info][sysllvm]. 2. Configure the build settings: + If you're unsure which build configurations to use and need a good default, you + can run the interactive `x.py setup` command. This will guide you through selecting + a config profile, setting up the LSP, configuring a Git hook, etc. + + With `configure` script, you can handle multiple configurations in a single + command which is useful to create complex/advanced config files. For example: + ```sh - ./configure + ./configure --build=aarch64-unknown-linux-gnu \ + --enable-full-tools \ + --enable-profiler \ + --enable-sanitizers \ + --enable-compiler-docs \ + --set target.aarch64-unknown-linux-gnu.linker=clang \ + --set target.aarch64-unknown-linux-gnu.ar=/rustroot/bin/llvm-ar \ + --set target.aarch64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \ + --set llvm.link-shared=true \ + --set llvm.thin-lto=true \ + --set llvm.libzstd=true \ + --set llvm.ninja=false \ + --set rust.debug-assertions=false \ + --set rust.jemalloc \ + --set rust.use-lld=true \ + --set rust.lto=thin \ + --set rust.codegen-units=1 ``` If you plan to use `x.py install` to create an installation, you can either diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1532ca77f71..8986430141b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1927,7 +1927,7 @@ impl AttrArgs { } /// Delimited arguments, as used in `#[attr()/[]/{}]` or `mac!()/[]/{}`. -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct DelimArgs { pub dspan: DelimSpan, pub delim: Delimiter, // Note: `Delimiter::Invisible` never occurs @@ -1942,18 +1942,6 @@ impl DelimArgs { } } -impl<CTX> HashStable<CTX> for DelimArgs -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let DelimArgs { dspan, delim, tokens } = self; - dspan.hash_stable(ctx, hasher); - delim.hash_stable(ctx, hasher); - tokens.hash_stable(ctx, hasher); - } -} - /// Represents a macro definition. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MacroDef { diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 294c6c9ba7a..1471262d2d6 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) @@ -14,7 +15,6 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 534e85e8bcb..1e14b4d6723 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,12 +32,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end @@ -916,7 +916,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs { - DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() } + args.clone() } /// Lower an associated item constraint. diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 093199cf342..7956057f88e 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -4,11 +4,11 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_is_partitioned)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index c61b44b273d..679fe935484 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -1,7 +1,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 63597b37cb5..55c3df003fe 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use std::ops::Deref; use std::sync::LazyLock; -use rustc_ast::{self as ast, DelimArgs}; +use rustc_ast as ast; use rustc_attr_data_structures::AttributeKind; use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::Features; @@ -315,11 +315,7 @@ impl<'sess> AttributeParser<'sess> { fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { match args { ast::AttrArgs::Empty => AttrArgs::Empty, - ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs { - dspan: args.dspan, - delim: args.delim, - tokens: args.tokens.clone(), - }), + ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()), // This is an inert key-value attribute - it will never be visible to macros // after it gets lowered to HIR. Therefore, we can extract literals to handle // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 249e71ef70d..b9692c01e2c 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -77,8 +77,8 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 134f30ed6f5..0de4bd67f0c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -49,7 +49,7 @@ impl<'tcx> UniverseInfo<'tcx> { UniverseInfo::RelateTys { expected, found } } - pub(crate) fn report_error( + pub(crate) fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, @@ -68,7 +68,7 @@ impl<'tcx> UniverseInfo<'tcx> { mbcx.buffer_error(err); } UniverseInfo::TypeOp(ref type_op_info) => { - type_op_info.report_error(mbcx, placeholder, error_element, cause); + type_op_info.report_erroneous_element(mbcx, placeholder, error_element, cause); } UniverseInfo::Other => { // FIXME: This error message isn't great, but it doesn't show @@ -145,8 +145,11 @@ pub(crate) trait TypeOpInfo<'tcx> { error_region: Option<ty::Region<'tcx>>, ) -> Option<Diag<'infcx>>; + /// Constraints require that `error_element` appear in the + /// values of `placeholder`, but this cannot be proven to + /// hold. Report an error. #[instrument(level = "debug", skip(self, mbcx))] - fn report_error( + fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, @@ -190,12 +193,7 @@ pub(crate) trait TypeOpInfo<'tcx> { let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region); debug!(?nice_error); - - if let Some(nice_error) = nice_error { - mbcx.buffer_error(nice_error); - } else { - mbcx.buffer_error(self.fallback_error(tcx, span)); - } + mbcx.buffer_error(nice_error.unwrap_or_else(|| self.fallback_error(tcx, span))); } } @@ -450,7 +448,8 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( ty::ReVar(vid) => universe_of_region(vid), _ => ty::UniverseIndex::ROOT, }; - let matches = + // Are the two regions the same? + let regions_the_same = |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) { (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound, _ => a_region == b_region, @@ -459,7 +458,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint { Constraint::RegSubReg(sub, sup) if ((exact && sup == placeholder_region) - || (!exact && matches(sup, placeholder_region))) + || (!exact && regions_the_same(sup, placeholder_region))) && sup != sub => { Some((sub, cause.clone())) @@ -468,23 +467,21 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( if (exact && sup == placeholder_region && !universe_of_region(vid).can_name(placeholder_universe)) - || (!exact && matches(sup, placeholder_region)) => + || (!exact && regions_the_same(sup, placeholder_region)) => { Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) } _ => None, }; - let mut info = region_constraints - .constraints - .iter() - .find_map(|(constraint, cause)| check(constraint, cause, true)); - if info.is_none() { - info = region_constraints + + let mut find_culprit = |exact_match: bool| { + region_constraints .constraints .iter() - .find_map(|(constraint, cause)| check(constraint, cause, false)); - } - let (sub_region, cause) = info?; + .find_map(|(constraint, cause)| check(constraint, cause, exact_match)) + }; + + let (sub_region, cause) = find_culprit(true).or_else(|| find_culprit(false))?; debug!(?sub_region, "cause = {:#?}", cause); let error = match (error_region, sub_region.kind()) { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 4423edb0605..3bec07afa0f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -405,7 +405,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let universe = placeholder.universe; let universe_info = self.regioncx.universe_info(universe); - universe_info.report_error(self, placeholder, error_element, cause); + universe_info.report_erroneous_element(self, placeholder, error_element, cause); } RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 83a9827e8f8..51d37353520 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,12 +2,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f8af9e59f63..c256051c122 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1628,30 +1628,23 @@ impl<'tcx> RegionInferenceContext<'tcx> { let longer_fr_scc = self.constraint_sccs.scc(longer_fr); debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,); - for error_element in self.scc_values.elements_contained_in(longer_fr_scc) { - match error_element { - RegionElement::Location(_) | RegionElement::RootUniversalRegion(_) => {} - // If we have some bound universal region `'a`, then the only - // elements it can contain is itself -- we don't know anything - // else about it! - RegionElement::PlaceholderRegion(placeholder1) => { - if placeholder == placeholder1 { - continue; - } - } - } - + // If we have some bound universal region `'a`, then the only + // elements it can contain is itself -- we don't know anything + // else about it! + if let Some(error_element) = self + .scc_values + .elements_contained_in(longer_fr_scc) + .find(|e| *e != RegionElement::PlaceholderRegion(placeholder)) + { + // Stop after the first error, it gets too noisy otherwise, and does not provide more information. errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { longer_fr, error_element, placeholder, }); - - // Stop after the first error, it gets too noisy otherwise, and does not provide more - // information. - break; + } else { + debug!("check_bound_universal_region: all bounds satisfied"); } - debug!("check_bound_universal_region: all bounds satisfied"); } #[instrument(level = "debug", skip(self, infcx, errors_buffer))] @@ -2071,7 +2064,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraint.category }; - match category { + let interest = match category { // Returns usually provide a type to blame and have specially written diagnostics, // so prioritize them. ConstraintCategory::Return(_) => 0, @@ -2123,9 +2116,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { // specific, and are not used for relations that would make sense to blame. ConstraintCategory::BoringNoLocation => 6, // Do not blame internal constraints. - ConstraintCategory::Internal => 7, - ConstraintCategory::IllegalUniverse => 8, - } + ConstraintCategory::IllegalUniverse => 7, + ConstraintCategory::Internal => 8, + }; + + debug!("constraint {constraint:?} category: {category:?}, interest: {interest:?}"); + + interest }; let best_choice = if blame_source { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index d9ac5b5cb13..f1427218cdb 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -21,7 +21,7 @@ rustc_index::newtype_index! { /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub(crate) enum RegionElement { /// A point in the control-flow graph. Location(Location), diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index bcd40f980e6..70e817db2a6 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,6 +5,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -12,7 +13,6 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 9d9e790289c..ab09a6f8b38 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -41,8 +41,8 @@ use std::sync::Arc; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; -use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_codegen_ssa::{CodegenResults, TargetConfig}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -178,7 +178,7 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) { + fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled @@ -197,7 +197,16 @@ impl CodegenBackend for CraneliftCodegenBackend { }; // FIXME do `unstable_target_features` properly let unstable_target_features = target_features.clone(); - (target_features, unstable_target_features) + + TargetConfig { + target_features, + unstable_target_features, + // Cranelift does not yet support f16 or f128 + has_reliable_f16: false, + has_reliable_f16_math: false, + has_reliable_f128: false, + has_reliable_f128_math: false, + } } fn print_version(&self) { diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index fd898c59707..452d3f22dc5 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-04-17" +channel = "nightly-2025-04-25" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index dbdf37ee6c9..396c6d57950 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -165,10 +165,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let mut input_registers = vec![]; for op in rust_operands { - if let InlineAsmOperandRef::In { reg, .. } = *op { - if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { - input_registers.push(reg_name); - } + if let InlineAsmOperandRef::In { reg, .. } = *op + && let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) + { + input_registers.push(reg_name); } } diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index a63da6b6e27..918195364ff 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -33,12 +33,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } + if value.get_type() == self.bool_type.make_pointer() + && let Some(pointee) = typ.get_pointee() + && pointee.dyncast_vector().is_some() + { + panic!() } // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some // SIMD builtins require a constant value. diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index acb39374628..0a67bd7bc71 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -242,10 +242,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let fn_attrs = self.tcx.codegen_fn_attrs(def_id); let global = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) { - if let Some(global) = self.get_declared_value(sym) { - if self.val_ty(global) != self.type_ptr_to(gcc_type) { - span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); - } + if let Some(global) = self.get_declared_value(sym) + && self.val_ty(global) != self.type_ptr_to(gcc_type) + { + span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); } let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 55e01687400..f3ced864395 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -126,14 +126,15 @@ fn make_mir_scope<'gcc, 'tcx>( return; }; - if let Some(ref vars) = *variables { - if !vars.contains(scope) && scope_data.inlined.is_none() { - // Do not create a DIScope if there are no variables defined in this - // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. - debug_context.scopes[scope] = parent_scope; - instantiated.insert(scope); - return; - } + if let Some(ref vars) = *variables + && !vars.contains(scope) + && scope_data.inlined.is_none() + { + // Do not create a DIScope if there are no variables defined in this + // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. + debug_context.scopes[scope] = parent_scope; + instantiated.insert(scope); + return; } let loc = cx.lookup_debug_loc(scope_data.span.lo()); diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 202764d5649..2b053abdd19 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -55,7 +55,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri ) } else if let Some(feature) = feature.strip_prefix('-') { // FIXME: Why do we not remove implied features on "-" here? - // We do the equivalent above in `target_features_cfg`. + // We do the equivalent above in `target_config`. // See <https://github.com/rust-lang/rust/issues/134792>. all_rust_features.push((false, feature)); } else if !feature.is_empty() && diagnostics { @@ -136,14 +136,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri }); features.extend(feats); - if diagnostics { - if let Some(f) = check_tied_features(sess, &featsmap) { - sess.dcx().emit_err(TargetFeatureDisableOrEnable { - features: f, - span: None, - missing_features: None, - }); - } + if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { + sess.dcx().emit_err(TargetFeatureDisableOrEnable { + features: f, + span: None, + missing_features: None, + }); } features diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 624fdb4043c..2c5a7871683 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -22,7 +22,7 @@ #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![deny(clippy::pattern_type_mismatch)] -#![allow(clippy::needless_lifetimes)] +#![allow(clippy::needless_lifetimes, clippy::uninlined_format_args)] // Some "regular" crates we want to share with rustc extern crate object; @@ -102,7 +102,7 @@ use rustc_codegen_ssa::back::write::{ }; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; @@ -260,8 +260,8 @@ impl CodegenBackend for GccCodegenBackend { .join(sess) } - fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) { - target_features_cfg(sess, &self.target_info) + fn target_config(&self, sess: &Session) -> TargetConfig { + target_config(sess, &self.target_info) } } @@ -485,10 +485,7 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel { } /// Returns the features that should be set in `cfg(target_feature)`. -fn target_features_cfg( - sess: &Session, - target_info: &LockedTargetInfo, -) -> (Vec<Symbol>, Vec<Symbol>) { +fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig { // TODO(antoyo): use global_gcc_features. let f = |allow_unstable| { sess.target @@ -523,5 +520,14 @@ fn target_features_cfg( let target_features = f(false); let unstable_target_features = f(true); - (target_features, unstable_target_features) + + TargetConfig { + target_features, + unstable_target_features, + // There are no known bugs with GCC support for f16 or f128 + has_reliable_f16: true, + has_reliable_f16_math: true, + has_reliable_f128: true, + has_reliable_f128_math: true, + } } diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index ae98b3d0b56..5745acce6fe 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -102,10 +102,10 @@ fn uncached_gcc_type<'gcc, 'tcx>( let mut name = with_no_trimmed_paths!(layout.ty.to_string()); if let (&ty::Adt(def, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) + && def.is_enum() + && !def.variants().is_empty() { - if def.is_enum() && !def.variants().is_empty() { - write!(&mut name, "::{}", def.variant(index).name).unwrap(); - } + write!(&mut name, "::{}", def.variant(index).name).unwrap(); } if let (&ty::Coroutine(_, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) @@ -264,10 +264,10 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { } fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { - if let BackendRepr::Scalar(ref scalar) = self.backend_repr { - if scalar.is_bool() { - return cx.type_i1(); - } + if let BackendRepr::Scalar(ref scalar) = self.backend_repr + && scalar.is_bool() + { + return cx.type_i1(); } self.gcc_type(cx) } diff --git a/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs index 64c932a2658..d5a0d71c4b2 100644 --- a/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs +++ b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs @@ -1,5 +1,7 @@ //! The common code for `tests/lang_tests_*.rs` +#![allow(clippy::uninlined_format_args)] + use std::env::{self, current_dir}; use std::path::{Path, PathBuf}; use std::process::Command; diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs index c1254c51ce9..e627886a9d5 100644 --- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -5,6 +5,7 @@ // stdout: 10 // 10 // 42 +// 1 #![feature(no_core)] #![no_std] @@ -21,6 +22,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u3 ) } +static mut ONE: usize = 1; + #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42); @@ -28,6 +31,10 @@ extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { libc::printf(b"%d\n\0" as *const u8 as *const i8, c); libc::printf(b"%ld\n\0" as *const u8 as *const i8, d); libc::printf(b"%ld\n\0" as *const u8 as *const i8, j); + + let ptr = ONE as *mut usize; + let value = ptr as usize; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, value); } 0 } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 425381b0ffa..e8010ec9fc4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -15,7 +16,6 @@ #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustdoc_internals)] #![feature(slice_as_array)] #![feature(try_blocks)] @@ -29,7 +29,7 @@ use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; use context::SimpleCx; use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; -use llvm_util::target_features_cfg; +use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; @@ -37,7 +37,7 @@ use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_metadata::EncodedMetadata; @@ -338,8 +338,8 @@ impl CodegenBackend for LlvmCodegenBackend { llvm_util::print_version(); } - fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) { - target_features_cfg(sess) + fn target_config(&self, sess: &Session) -> TargetConfig { + target_config(sess) } fn codegen_crate<'tcx>( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 36e35f81392..ae1bdac1655 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,6 +6,7 @@ use std::sync::Once; use std::{ptr, slice, str}; use libc::c_int; +use rustc_codegen_ssa::TargetConfig; use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::codegen_attrs::check_tied_features; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -302,7 +303,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea /// Must express features in the way Rust understands them. /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen. -pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) { +pub(crate) fn target_config(sess: &Session) -> TargetConfig { // Add base features for the target. // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below. // The reason is that if LLVM considers a feature implied but we do not, we don't want that to @@ -402,7 +403,89 @@ pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) let target_features = f(false); let unstable_target_features = f(true); - (target_features, unstable_target_features) + let mut cfg = TargetConfig { + target_features, + unstable_target_features, + has_reliable_f16: true, + has_reliable_f16_math: true, + has_reliable_f128: true, + has_reliable_f128_math: true, + }; + + update_target_reliable_float_cfg(sess, &mut cfg); + cfg +} + +/// Determine whether or not experimental float types are reliable based on known bugs. +fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { + let target_arch = sess.target.arch.as_ref(); + let target_os = sess.target.options.os.as_ref(); + let target_env = sess.target.options.env.as_ref(); + let target_abi = sess.target.options.abi.as_ref(); + let target_pointer_width = sess.target.pointer_width; + + cfg.has_reliable_f16 = match (target_arch, target_os) { + // Selection failure <https://github.com/llvm/llvm-project/issues/50374> + ("s390x", _) => false, + // Unsupported <https://github.com/llvm/llvm-project/issues/94434> + ("arm64ec", _) => false, + // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> + ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, + // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981> + ("csky", _) => false, + ("hexagon", _) => false, + ("powerpc" | "powerpc64", _) => false, + ("sparc" | "sparc64", _) => false, + ("wasm32" | "wasm64", _) => false, + // `f16` support only requires that symbols converting to and from `f32` are available. We + // provide these in `compiler-builtins`, so `f16` should be available on all platforms that + // do not have other ABI issues or LLVM crashes. + _ => true, + }; + + cfg.has_reliable_f128 = match (target_arch, target_os) { + // Unsupported <https://github.com/llvm/llvm-project/issues/94434> + ("arm64ec", _) => false, + // Selection bug <https://github.com/llvm/llvm-project/issues/96432> + ("mips64" | "mips64r6", _) => false, + // Selection bug <https://github.com/llvm/llvm-project/issues/95471> + ("nvptx64", _) => false, + // ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full + // list at <https://github.com/rust-lang/rust/issues/116909>) + ("powerpc" | "powerpc64", _) => false, + // ABI unsupported <https://github.com/llvm/llvm-project/issues/41838> + ("sparc", _) => false, + // Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may + // not fail if our compiler-builtins is linked. + ("x86", _) => false, + // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> + ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, + // There are no known problems on other platforms, so the only requirement is that symbols + // are available. `compiler-builtins` provides all symbols required for core `f128` + // support, so this should work for everything else. + _ => true, + }; + + cfg.has_reliable_f16_math = match (target_arch, target_os) { + // x86 has a crash for `powi`: <https://github.com/llvm/llvm-project/issues/105747> + ("x86" | "x86_64", _) => false, + // Assume that working `f16` means working `f16` math for most platforms, since + // operations just go through `f32`. + _ => true, + } && cfg.has_reliable_f16; + + cfg.has_reliable_f128_math = match (target_arch, target_os) { + // LLVM lowers `fp128` math to `long double` symbols even on platforms where + // `long double` is not IEEE binary128. See + // <https://github.com/llvm/llvm-project/issues/44744>. + // + // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits + // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86` + // (ld is 80-bit extended precision). + ("x86_64", _) => false, + (_, "linux") if target_pointer_width == 64 => true, + _ => false, + } && cfg.has_reliable_f128; } pub(crate) fn print_version() { @@ -686,7 +769,7 @@ pub(crate) fn global_llvm_features( ) } else if let Some(feature) = feature.strip_prefix('-') { // FIXME: Why do we not remove implied features on "-" here? - // We do the equivalent above in `target_features_cfg`. + // We do the equivalent above in `target_config`. // See <https://github.com/rust-lang/rust/issues/134792>. all_rust_features.push((false, feature)); } else if !feature.is_empty() { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 5b2ed69535b..b67c871cac9 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,13 +2,13 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(rustdoc_internals)] #![feature(string_from_utf8_lossy_owned)] @@ -235,6 +235,24 @@ pub struct CrateInfo { pub lint_levels: CodegenLintLevels, } +/// Target-specific options that get set in `cfg(...)`. +/// +/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen. +pub struct TargetConfig { + /// Options to be set in `cfg(target_features)`. + pub target_features: Vec<Symbol>, + /// Options to be set in `cfg(target_features)`, but including unstable features. + pub unstable_target_features: Vec<Symbol>, + /// Option for `cfg(target_has_reliable_f16)`, true if `f16` basic arithmetic works. + pub has_reliable_f16: bool, + /// Option for `cfg(target_has_reliable_f16_math)`, true if `f16` math calls work. + pub has_reliable_f16_math: bool, + /// Option for `cfg(target_has_reliable_f128)`, true if `f128` basic arithmetic works. + pub has_reliable_f128: bool, + /// Option for `cfg(target_has_reliable_f128_math)`, true if `f128` math calls work. + pub has_reliable_f128_math: bool, +} + #[derive(Encodable, Decodable)] pub struct CodegenResults { pub modules: Vec<CompiledModule>, diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 65fd843e7a5..e6b50cc7c0c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -18,7 +18,7 @@ use super::write::WriteBackendMethods; use crate::back::archive::ArArchiveBuilderBuilder; use crate::back::link::link_binary; use crate::back::write::TargetMachineFactoryFn; -use crate::{CodegenResults, ModuleCodegen}; +use crate::{CodegenResults, ModuleCodegen, TargetConfig}; pub trait BackendTypes { type Value: CodegenObject; @@ -50,8 +50,15 @@ pub trait CodegenBackend { /// - The second is like the first, but also includes unstable features. /// /// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen. - fn target_features_cfg(&self, _sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) { - (vec![], vec![]) + fn target_config(&self, _sess: &Session) -> TargetConfig { + TargetConfig { + target_features: vec![], + unstable_target_features: vec![], + has_reliable_f16: true, + has_reliable_f16_math: true, + has_reliable_f128: true, + has_reliable_f128_math: true, + } } fn print_passes(&self) {} diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index da52d60ae59..7a0c2543c30 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,12 +1,12 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(slice_ptr_get)] diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 5f07cfef133..dfd9bd32076 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -39,8 +39,15 @@ impls_dyn_send_neg!( [std::io::StderrLock<'_>] ); -#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] -// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms +#[cfg(any( + unix, + target_os = "hermit", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + target_os = "wasi", + target_os = "xous" +))] +// Consistent with `std`, `env_imp::Env` is `!Sync` in these platforms impl !DynSend for std::env::VarsOs {} macro_rules! already_send { @@ -106,8 +113,15 @@ impls_dyn_sync_neg!( [std::sync::mpsc::Sender<T> where T] ); -#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] -// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms +#[cfg(any( + unix, + target_os = "hermit", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + target_os = "wasi", + target_os = "xous" +))] +// Consistent with `std`, `env_imp::Env` is `!Sync` in these platforms impl !DynSync for std::env::VarsOs {} macro_rules! already_sync { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 40cc82727a5..d18fa892814 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -7,10 +7,10 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(decl_macro)] -#![feature(let_chains)] #![feature(panic_backtrace_config)] #![feature(panic_update_hook)] #![feature(result_flattening)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c0c5dba4677..6f37bad9bb4 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,6 +7,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -17,7 +18,6 @@ #![feature(default_field_values)] #![feature(error_reporter)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 4222c9fe906..79f838e2e33 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,11 +1,11 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(array_windows)] #![feature(associated_type_defaults)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] #![feature(proc_macro_diagnostic)] diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 43ba67e7dc6..a5e6b1c00d6 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -40,6 +40,26 @@ const GATED_CFGS: &[GatedCfg] = &[ // this is consistent with naming of the compiler flag it's for (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug), (sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh), + ( + sym::target_has_reliable_f16, + sym::cfg_target_has_reliable_f16_f128, + Features::cfg_target_has_reliable_f16_f128, + ), + ( + sym::target_has_reliable_f16_math, + sym::cfg_target_has_reliable_f16_f128, + Features::cfg_target_has_reliable_f16_f128, + ), + ( + sym::target_has_reliable_f128, + sym::cfg_target_has_reliable_f16_f128, + Features::cfg_target_has_reliable_f16_f128, + ), + ( + sym::target_has_reliable_f128_math, + sym::cfg_target_has_reliable_f16_f128, + Features::cfg_target_has_reliable_f16_f128, + ), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index cbc121e3632..12e254ab549 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -205,6 +205,8 @@ declare_features! ( (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), /// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind (internal, cfg_emscripten_wasm_eh, "1.86.0", None), + /// Allows checking whether or not the backend correctly supports unstable float types. + (internal, cfg_target_has_reliable_f16_f128, "CURRENT_RUSTC_VERSION", None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index a84857e3597..32064f96dd6 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,12 +4,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(closure_track_caller)] #![feature(debug_closure_helpers)] #![feature(exhaustive_patterns)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index e1ad8124aea..309b8f2c761 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,6 +59,7 @@ This API is completely unstable and subject to change. #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -67,7 +68,6 @@ This API is completely unstable and subject to change. #![feature(if_let_guard)] #![feature(iter_from_coroutine)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(slice_partition_dedup)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ff4385c3bcc..779fae80f19 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2,7 +2,7 @@ //! the definitions in this file have equivalents in `rustc_ast_pretty`. // tidy-alphabetical-start -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index b19d9efe2c6..caf36ba47bd 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -501,12 +501,25 @@ impl<'a, 'tcx> CastCheck<'tcx> { .must_apply_modulo_regions() { label = false; - err.span_suggestion( - self.span, - "consider using the `From` trait instead", - format!("{}::from({})", self.cast_ty, snippet), - Applicability::MaybeIncorrect, - ); + if let ty::Adt(def, args) = self.cast_ty.kind() { + err.span_suggestion_verbose( + self.span, + "consider using the `From` trait instead", + format!( + "{}::from({})", + fcx.tcx.value_path_str_with_args(def.did(), args), + snippet + ), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion( + self.span, + "consider using the `From` trait instead", + format!("{}::from({})", self.cast_ty, snippet), + Applicability::MaybeIncorrect, + ); + }; } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index af8ec373934..c3717b4efa4 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,11 +1,11 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index ece18f4ea64..8b2aab42042 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,12 +16,12 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(extend_one)] #![feature(iterator_try_collect)] -#![feature(let_chains)] #![feature(rustdoc_internals)] #![recursion_limit = "512"] // For rustdoc // tidy-alphabetical-end diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 67e0be93523..41280707183 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,8 +1,8 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(decl_macro)] #![feature(file_buffered)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index c3a939f1ab0..4d346b50c80 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -38,14 +38,25 @@ pub(crate) fn add_configuration( codegen_backend: &dyn CodegenBackend, ) { let tf = sym::target_feature; + let tf_cfg = codegen_backend.target_config(sess); - let (target_features, unstable_target_features) = codegen_backend.target_features_cfg(sess); + sess.unstable_target_features.extend(tf_cfg.unstable_target_features.iter().copied()); + sess.target_features.extend(tf_cfg.target_features.iter().copied()); - sess.unstable_target_features.extend(unstable_target_features.iter().copied()); + cfg.extend(tf_cfg.target_features.into_iter().map(|feat| (tf, Some(feat)))); - sess.target_features.extend(target_features.iter().copied()); - - cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat)))); + if tf_cfg.has_reliable_f16 { + cfg.insert((sym::target_has_reliable_f16, None)); + } + if tf_cfg.has_reliable_f16_math { + cfg.insert((sym::target_has_reliable_f16_math, None)); + } + if tf_cfg.has_reliable_f128 { + cfg.insert((sym::target_has_reliable_f128, None)); + } + if tf_cfg.has_reliable_f128_math { + cfg.insert((sym::target_has_reliable_f128_math, None)); + } if sess.crt_static(None) { cfg.insert((tf, Some(sym::crt_dash_static))); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c8c556fc2ac..b910d6a138e 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,6 +21,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -28,7 +29,6 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_order_by)] -#![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(try_blocks)] diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index edb25e79904..62ca7ce3ca9 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,7 +1,7 @@ // tidy-alphabetical-start #![allow(rustc::default_hash_types)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(never_type)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 3b44c44fcb9..3931be1654a 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(coroutines)] @@ -8,7 +9,6 @@ #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] -#![feature(let_chains)] #![feature(macro_metavar_expr)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 8fe2cc7101b..df025aeebf0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,6 +29,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] @@ -48,7 +49,6 @@ #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(iter_from_coroutine)] -#![feature(let_chains)] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 02e316dfc3d..551d816941b 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -121,11 +121,10 @@ impl<'tcx> Predicate<'tcx> { /// unsoundly accept some programs. See #91068. #[inline] pub fn allow_normalization(self) -> bool { - // Keep this in sync with the one in `rustc_type_ir::inherent`! match self.kind().skip_binder() { - PredicateKind::Clause(ClauseKind::WellFormed(_)) - | PredicateKind::AliasRelate(..) - | PredicateKind::NormalizesTo(..) => false, + PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) => { + false + } PredicateKind::Clause(ClauseKind::Trait(_)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) @@ -137,6 +136,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(_) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) | PredicateKind::ConstEquate(_, _) + | PredicateKind::NormalizesTo(..) | PredicateKind::Ambiguous => true, } } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 8e96d46dac2..a051cf570b7 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -3,10 +3,10 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index a0efc623b8e..38f82b12746 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,10 +1,10 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] #![feature(file_buffered)] -#![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs index 8be782dcbf0..4aff127908e 100644 --- a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs +++ b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs @@ -87,11 +87,8 @@ impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> { && let Some((func_def_id, _)) = func.const_fn_def() && self.tcx.is_intrinsic(func_def_id, sym::transmute) && let span = self.body.source_info(location).span - && let Some(lint) = self.is_unnecessary_transmute( - func, - self.tcx.sess.source_map().span_to_snippet(arg).expect("ok"), - span, - ) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(arg) + && let Some(lint) = self.is_unnecessary_transmute(func, snippet, span) && let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes) { self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 6977d23bd0e..5db62b7e902 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -7,7 +8,6 @@ #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] -#![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 8f6914f3d72..8469e0f17a6 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,9 +1,9 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] -#![feature(let_chains)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 63aa60f2f26..36d53901d9e 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -9,7 +9,6 @@ derive-where = "1.2.7" rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } -rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } tracing = "0.1" @@ -20,7 +19,6 @@ default = ["nightly"] nightly = [ "dep:rustc_data_structures", "dep:rustc_macros", - "dep:rustc_serialize", "rustc_index/nightly", "rustc_type_ir/nightly", ] diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 0fc313e33b3..f7bd4600943 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -16,6 +16,7 @@ //! relate them structurally. use rustc_type_ir::inherent::*; +use rustc_type_ir::solve::GoalSource; use rustc_type_ir::{self as ty, Interner}; use tracing::{instrument, trace}; @@ -49,7 +50,10 @@ where // Structurally normalize the lhs. let lhs = if let Some(alias) = lhs.to_alias_term() { let term = self.next_term_infer_of_kind(lhs); - self.add_normalizes_to_goal(goal.with(cx, ty::NormalizesTo { alias, term })); + self.add_goal( + GoalSource::TypeRelating, + goal.with(cx, ty::NormalizesTo { alias, term }), + ); term } else { lhs @@ -58,7 +62,10 @@ where // Structurally normalize the rhs. let rhs = if let Some(alias) = rhs.to_alias_term() { let term = self.next_term_infer_of_kind(rhs); - self.add_normalizes_to_goal(goal.with(cx, ty::NormalizesTo { alias, term })); + self.add_goal( + GoalSource::TypeRelating, + goal.with(cx, ty::NormalizesTo { alias, term }), + ); term } else { rhs diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index d56b0e5847e..04f80a056f9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -22,7 +22,7 @@ use tracing::{debug, instrument, trace}; use crate::canonicalizer::Canonicalizer; use crate::delegate::SolverDelegate; use crate::resolve::EagerResolver; -use crate::solve::eval_ctxt::{CurrentGoalKind, NestedGoals}; +use crate::solve::eval_ctxt::CurrentGoalKind; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput, @@ -112,13 +112,9 @@ where // by `try_evaluate_added_goals()`. let (certainty, normalization_nested_goals) = match self.current_goal_kind { CurrentGoalKind::NormalizesTo => { - let NestedGoals { normalizes_to_goals, goals } = - std::mem::take(&mut self.nested_goals); - if cfg!(debug_assertions) { - assert!(normalizes_to_goals.is_empty()); - if goals.is_empty() { - assert!(matches!(goals_certainty, Certainty::Yes)); - } + let goals = std::mem::take(&mut self.nested_goals); + if goals.is_empty() { + assert!(matches!(goals_certainty, Certainty::Yes)); } (certainty, NestedNormalizationGoals(goals)) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 9994c85d0d0..27ca8787db5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1,8 +1,8 @@ +use std::mem; use std::ops::ControlFlow; -use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_macros::HashStable_NoContext; use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; @@ -14,7 +14,6 @@ use rustc_type_ir::{ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; -use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; use crate::coherence; @@ -114,7 +113,7 @@ where pub(super) search_graph: &'a mut SearchGraph<D>, - nested_goals: NestedGoals<I>, + nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>)>, pub(super) origin_span: I::Span, @@ -129,38 +128,6 @@ where pub(super) inspect: ProofTreeBuilder<D>, } -#[derive_where(Clone, Debug, Default; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) -)] -struct NestedGoals<I: Interner> { - /// These normalizes-to goals are treated specially during the evaluation - /// loop. In each iteration we take the RHS of the projection, replace it with - /// a fresh inference variable, and only after evaluating that goal do we - /// equate the fresh inference variable with the actual RHS of the predicate. - /// - /// This is both to improve caching, and to avoid using the RHS of the - /// projection predicate to influence the normalizes-to candidate we select. - /// - /// Forgetting to replace the RHS with a fresh inference variable when we evaluate - /// this goal results in an ICE.. - pub normalizes_to_goals: Vec<Goal<I, ty::NormalizesTo<I>>>, - /// The rest of the goals which have not yet processed or remain ambiguous. - pub goals: Vec<(GoalSource, Goal<I, I::Predicate>)>, -} - -impl<I: Interner> NestedGoals<I> { - fn new() -> Self { - Self { normalizes_to_goals: Vec::new(), goals: Vec::new() } - } - - fn is_empty(&self) -> bool { - self.normalizes_to_goals.is_empty() && self.goals.is_empty() - } -} - #[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GenerateProofTree { @@ -332,7 +299,7 @@ where let mut ecx = EvalCtxt { delegate, search_graph: &mut search_graph, - nested_goals: NestedGoals::new(), + nested_goals: Default::default(), inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree), // Only relevant when canonicalizing the response, @@ -385,7 +352,7 @@ where predefined_opaques_in_body: input.predefined_opaques_in_body, max_input_universe: canonical_input.canonical.max_universe, search_graph, - nested_goals: NestedGoals::new(), + nested_goals: Default::default(), origin_span: I::Span::dummy(), tainted: Ok(()), inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values), @@ -629,78 +596,83 @@ where /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> { let cx = self.cx(); - let mut goals = core::mem::take(&mut self.nested_goals); - // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); - for goal in goals.normalizes_to_goals { - // Replace the goal with an unconstrained infer var, so the - // RHS does not affect projection candidate assembly. - let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term); - let unconstrained_goal = goal.with( - cx, - ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs }, - ); - - let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw( - GoalEvaluationKind::Nested, - GoalSource::TypeRelating, - unconstrained_goal, - )?; - // Add the nested goals from normalization to our own nested goals. - trace!(?nested_goals); - goals.goals.extend(nested_goals); - - // Finally, equate the goal's RHS with the unconstrained var. + for (source, goal) in mem::take(&mut self.nested_goals) { + // We treat normalizes-to goals specially here. In each iteration we take the + // RHS of the projection, replace it with a fresh inference variable, and only + // after evaluating that goal do we equate the fresh inference variable with the + // actual RHS of the predicate. // - // SUBTLE: - // We structurally relate aliases here. This is necessary - // as we otherwise emit a nested `AliasRelate` goal in case the - // returned term is a rigid alias, resulting in overflow. + // This is both to improve caching, and to avoid using the RHS of the + // projection predicate to influence the normalizes-to candidate we select. // - // It is correct as both `goal.predicate.term` and `unconstrained_rhs` - // start out as an unconstrained inference variable so any aliases get - // fully normalized when instantiating it. - // - // FIXME: Strictly speaking this may be incomplete if the normalized-to - // type contains an ambiguous alias referencing bound regions. We should - // consider changing this to only use "shallow structural equality". - self.eq_structurally_relating_aliases( - goal.param_env, - goal.predicate.term, - unconstrained_rhs, - )?; - - // We only look at the `projection_ty` part here rather than - // looking at the "has changed" return from evaluate_goal, - // because we expect the `unconstrained_rhs` part of the predicate - // to have changed -- that means we actually normalized successfully! - let with_resolved_vars = self.resolve_vars_if_possible(goal); - if goal.predicate.alias != with_resolved_vars.predicate.alias { - unchanged_certainty = None; - } - - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - self.nested_goals.normalizes_to_goals.push(with_resolved_vars); - unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + // Forgetting to replace the RHS with a fresh inference variable when we evaluate + // this goal results in an ICE. + if let Some(pred) = goal.predicate.as_normalizes_to() { + // We should never encounter higher-ranked normalizes-to goals. + let pred = pred.no_bound_vars().unwrap(); + // Replace the goal with an unconstrained infer var, so the + // RHS does not affect projection candidate assembly. + let unconstrained_rhs = self.next_term_infer_of_kind(pred.term); + let unconstrained_goal = + goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs }); + + let (NestedNormalizationGoals(nested_goals), _, certainty) = + self.evaluate_goal_raw(GoalEvaluationKind::Nested, source, unconstrained_goal)?; + // Add the nested goals from normalization to our own nested goals. + trace!(?nested_goals); + self.nested_goals.extend(nested_goals); + + // Finally, equate the goal's RHS with the unconstrained var. + // + // SUBTLE: + // We structurally relate aliases here. This is necessary + // as we otherwise emit a nested `AliasRelate` goal in case the + // returned term is a rigid alias, resulting in overflow. + // + // It is correct as both `goal.predicate.term` and `unconstrained_rhs` + // start out as an unconstrained inference variable so any aliases get + // fully normalized when instantiating it. + // + // FIXME: Strictly speaking this may be incomplete if the normalized-to + // type contains an ambiguous alias referencing bound regions. We should + // consider changing this to only use "shallow structural equality". + self.eq_structurally_relating_aliases( + goal.param_env, + pred.term, + unconstrained_rhs, + )?; + + // We only look at the `projection_ty` part here rather than + // looking at the "has changed" return from evaluate_goal, + // because we expect the `unconstrained_rhs` part of the predicate + // to have changed -- that means we actually normalized successfully! + let with_resolved_vars = self.resolve_vars_if_possible(goal); + if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias { + unchanged_certainty = None; } - } - } - for (source, goal) in goals.goals { - let (has_changed, certainty) = - self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; - if has_changed == HasChanged::Yes { - unchanged_certainty = None; - } + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + self.nested_goals.push((source, with_resolved_vars)); + unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + } + } + } else { + let (has_changed, certainty) = + self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; + if has_changed == HasChanged::Yes { + unchanged_certainty = None; + } - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - self.nested_goals.goals.push((source, goal)); - unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + self.nested_goals.push((source, goal)); + unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + } } } } @@ -717,23 +689,12 @@ where self.delegate.cx() } - #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) { - goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new( - self, - GoalSource::TypeRelating, - goal.param_env, - )); - self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); - self.nested_goals.normalizes_to_goals.push(goal); - } - #[instrument(level = "debug", skip(self))] pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) { goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env)); self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); - self.nested_goals.goals.push((source, goal)); + self.nested_goals.push((source, goal)); } #[instrument(level = "trace", skip(self, goals))] diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 6a8e0790f7c..f22b275bc44 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -412,20 +412,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> { } } - pub(crate) fn add_normalizes_to_goal( - &mut self, - delegate: &D, - max_input_universe: ty::UniverseIndex, - goal: Goal<I, ty::NormalizesTo<I>>, - ) { - self.add_goal( - delegate, - max_input_universe, - GoalSource::TypeRelating, - goal.with(delegate.cx(), goal.predicate), - ); - } - pub(crate) fn add_goal( &mut self, delegate: &D, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 896e348a12d..e73d68e2037 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,13 +4,13 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(debug_closure_helpers)] #![feature(if_let_guard)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(string_from_utf8_lossy_owned)] // tidy-alphabetical-end diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3b1b0300e62..a61d446a3a9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -683,10 +683,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } if !other_attr.has_any_name(ALLOW_LIST) { + let path = other_attr.path(); + let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); + let other_attr_name = path.join("::"); + self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: other_attr.span(), naked_span: attr.span(), - attr: other_attr.name().unwrap(), + attr: other_attr_name, }); return; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4052264b051..b1b4b9ee927 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1249,7 +1249,7 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub span: Span, #[label(passes_naked_attribute)] pub naked_span: Span, - pub attr: Symbol, + pub attr: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 93ff0f66d69..c7bb00df796 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,9 +6,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(map_try_insert)] #![feature(rustdoc_internals)] #![feature(try_blocks)] diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 176dcbf6da4..f63d8b2d79f 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -6,7 +6,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![allow(unused_crate_dependencies)] -#![cfg_attr(feature = "rustc", feature(let_chains))] +#![cfg_attr(all(feature = "rustc", bootstrap), feature(let_chains))] // tidy-alphabetical-end pub mod constructor; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 48e29c823a2..e57d12dce51 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,9 +1,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(associated_type_defaults)] -#![feature(let_chains)] #![feature(rustdoc_internals)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index ac24628447d..d2bcde14383 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -46,6 +46,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_data_structures::unhash::UnhashMap; use rustc_index::{Idx, IndexVec}; +use rustc_serialize::opaque::mem_encoder::MemEncoder; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use tracing::{debug, instrument}; @@ -105,22 +106,12 @@ impl SerializedDepGraph { ) -> impl Iterator<Item = SerializedDepNodeIndex> + Clone { let header = self.edge_list_indices[source]; let mut raw = &self.edge_list_data[header.start()..]; - // Figure out where the edge list for `source` ends by getting the start index of the next - // edge list, or the end of the array if this is the last edge. - let end = self - .edge_list_indices - .get(source + 1) - .map(|h| h.start()) - .unwrap_or_else(|| self.edge_list_data.len() - DEP_NODE_PAD); - - // The number of edges for this node is implicitly stored in the combination of the byte - // width and the length. + let bytes_per_index = header.bytes_per_index(); - let len = (end - header.start()) / bytes_per_index; // LLVM doesn't hoist EdgeHeader::mask so we do it ourselves. let mask = header.mask(); - (0..len).map(move |_| { + (0..header.num_edges).map(move |_| { // Doing this slicing in this order ensures that the first bounds check suffices for // all the others. let index = &raw[..DEP_NODE_SIZE]; @@ -163,6 +154,7 @@ impl SerializedDepGraph { #[derive(Debug, Clone, Copy)] struct EdgeHeader { repr: usize, + num_edges: u32, } impl EdgeHeader { @@ -205,9 +197,14 @@ impl SerializedDepGraph { let graph_bytes = d.len() - (2 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); - let mut nodes = IndexVec::with_capacity(node_count); - let mut fingerprints = IndexVec::with_capacity(node_count); - let mut edge_list_indices = IndexVec::with_capacity(node_count); + let mut nodes = IndexVec::from_elem_n( + DepNode { kind: D::DEP_KIND_NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) }, + node_count, + ); + let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_count); + let mut edge_list_indices = + IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_count); + // This estimation assumes that all of the encoded bytes are for the edge lists or for the // fixed-size node headers. But that's not necessarily true; if any edge list has a length // that spills out of the size we can bit-pack into SerializedNodeHeader then some of the @@ -226,11 +223,14 @@ impl SerializedDepGraph { let node_header = SerializedNodeHeader::<D> { bytes: d.read_array(), _marker: PhantomData }; - let _i: SerializedDepNodeIndex = nodes.push(node_header.node()); - debug_assert_eq!(_i.index(), _index); + let index = node_header.index(); + + let node = &mut nodes[index]; + // Make sure there's no duplicate indices in the dep graph. + assert!(node_header.node().kind != D::DEP_KIND_NULL && node.kind == D::DEP_KIND_NULL); + *node = node_header.node(); - let _i: SerializedDepNodeIndex = fingerprints.push(node_header.fingerprint()); - debug_assert_eq!(_i.index(), _index); + fingerprints[index] = node_header.fingerprint(); // If the length of this node's edge list is small, the length is stored in the header. // If it is not, we fall back to another decoder call. @@ -242,12 +242,11 @@ impl SerializedDepGraph { let edges_len_bytes = node_header.bytes_per_index() * (num_edges as usize); // The in-memory structure for the edges list stores the byte width of the edges on // this node with the offset into the global edge data array. - let edges_header = node_header.edges_header(&edge_list_data); + let edges_header = node_header.edges_header(&edge_list_data, num_edges); edge_list_data.extend(d.read_raw_bytes(edges_len_bytes)); - let _i: SerializedDepNodeIndex = edge_list_indices.push(edges_header); - debug_assert_eq!(_i.index(), _index); + edge_list_indices[index] = edges_header; } // When we access the edge list data, we do a fixed-size read from the edge list data then @@ -298,9 +297,10 @@ impl SerializedDepGraph { /// * In whatever bits remain, the length of the edge list for this node, if it fits struct SerializedNodeHeader<D> { // 2 bytes for the DepNode + // 4 bytes for the index // 16 for Fingerprint in DepNode // 16 for Fingerprint in NodeInfo - bytes: [u8; 34], + bytes: [u8; 38], _marker: PhantomData<D>, } @@ -310,6 +310,7 @@ struct Unpacked { len: Option<u32>, bytes_per_index: usize, kind: DepKind, + index: SerializedDepNodeIndex, hash: PackedFingerprint, fingerprint: Fingerprint, } @@ -331,6 +332,7 @@ impl<D: Deps> SerializedNodeHeader<D> { #[inline] fn new( node: DepNode, + index: DepNodeIndex, fingerprint: Fingerprint, edge_max_index: u32, edge_count: usize, @@ -352,10 +354,11 @@ impl<D: Deps> SerializedNodeHeader<D> { let hash: Fingerprint = node.hash.into(); // Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong. - let mut bytes = [0u8; 34]; + let mut bytes = [0u8; 38]; bytes[..2].copy_from_slice(&head.to_le_bytes()); - bytes[2..18].copy_from_slice(&hash.to_le_bytes()); - bytes[18..].copy_from_slice(&fingerprint.to_le_bytes()); + bytes[2..6].copy_from_slice(&index.as_u32().to_le_bytes()); + bytes[6..22].copy_from_slice(&hash.to_le_bytes()); + bytes[22..].copy_from_slice(&fingerprint.to_le_bytes()); #[cfg(debug_assertions)] { @@ -372,8 +375,9 @@ impl<D: Deps> SerializedNodeHeader<D> { #[inline] fn unpack(&self) -> Unpacked { let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap()); - let hash = self.bytes[2..18].try_into().unwrap(); - let fingerprint = self.bytes[18..].try_into().unwrap(); + let index = u32::from_le_bytes(self.bytes[2..6].try_into().unwrap()); + let hash = self.bytes[6..22].try_into().unwrap(); + let fingerprint = self.bytes[22..].try_into().unwrap(); let kind = head & mask(Self::KIND_BITS) as u16; let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16; @@ -383,6 +387,7 @@ impl<D: Deps> SerializedNodeHeader<D> { len: len.checked_sub(1), bytes_per_index: bytes_per_index as usize + 1, kind: DepKind::new(kind), + index: SerializedDepNodeIndex::from_u32(index), hash: Fingerprint::from_le_bytes(hash).into(), fingerprint: Fingerprint::from_le_bytes(fingerprint), } @@ -399,6 +404,11 @@ impl<D: Deps> SerializedNodeHeader<D> { } #[inline] + fn index(&self) -> SerializedDepNodeIndex { + self.unpack().index + } + + #[inline] fn fingerprint(&self) -> Fingerprint { self.unpack().fingerprint } @@ -410,9 +420,10 @@ impl<D: Deps> SerializedNodeHeader<D> { } #[inline] - fn edges_header(&self, edge_list_data: &[u8]) -> EdgeHeader { + fn edges_header(&self, edge_list_data: &[u8], num_edges: u32) -> EdgeHeader { EdgeHeader { repr: (edge_list_data.len() << DEP_NODE_WIDTH_BITS) | (self.bytes_per_index() - 1), + num_edges, } } } @@ -425,10 +436,15 @@ struct NodeInfo { } impl NodeInfo { - fn encode<D: Deps>(&self, e: &mut FileEncoder) { + fn encode<D: Deps>(&self, e: &mut MemEncoder, index: DepNodeIndex) { let NodeInfo { node, fingerprint, ref edges } = *self; - let header = - SerializedNodeHeader::<D>::new(node, fingerprint, edges.max_index(), edges.len()); + let header = SerializedNodeHeader::<D>::new( + node, + index, + fingerprint, + edges.max_index(), + edges.len(), + ); e.write_array(header.bytes); if header.len().is_none() { @@ -450,8 +466,9 @@ impl NodeInfo { /// This avoids the overhead of constructing `EdgesVec`, which would be needed to call `encode`. #[inline] fn encode_promoted<D: Deps>( - e: &mut FileEncoder, + e: &mut MemEncoder, node: DepNode, + index: DepNodeIndex, fingerprint: Fingerprint, prev_index: SerializedDepNodeIndex, colors: &DepNodeColorMap, @@ -464,7 +481,7 @@ impl NodeInfo { let edge_max = edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0); - let header = SerializedNodeHeader::<D>::new(node, fingerprint, edge_max, edge_count); + let header = SerializedNodeHeader::<D>::new(node, index, fingerprint, edge_max, edge_count); e.write_array(header.bytes); if header.len().is_none() { @@ -498,6 +515,8 @@ struct EncoderState<D: Deps> { total_edge_count: usize, stats: Option<FxHashMap<DepKind, Stat>>, + mem_encoder: MemEncoder, + /// Stores the number of times we've encoded each dep kind. kind_stats: Vec<u32>, marker: PhantomData<D>, @@ -511,22 +530,28 @@ impl<D: Deps> EncoderState<D> { total_edge_count: 0, total_node_count: 0, stats: record_stats.then(FxHashMap::default), + mem_encoder: MemEncoder::new(), kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(), marker: PhantomData, } } #[inline] + fn alloc_index(&mut self) -> DepNodeIndex { + let index = DepNodeIndex::new(self.total_node_count); + self.total_node_count += 1; + index + } + + #[inline] fn record( &mut self, node: DepNode, + index: DepNodeIndex, edge_count: usize, edges: impl FnOnce(&mut Self) -> Vec<DepNodeIndex>, record_graph: &Option<Lock<DepGraphQuery>>, ) -> DepNodeIndex { - let index = DepNodeIndex::new(self.total_node_count); - - self.total_node_count += 1; self.kind_stats[node.kind.as_usize()] += 1; self.total_edge_count += edge_count; @@ -558,14 +583,25 @@ impl<D: Deps> EncoderState<D> { index } + #[inline] + fn flush_mem_encoder(&mut self) { + let data = &mut self.mem_encoder.data; + if data.len() > 64 * 1024 { + self.encoder.emit_raw_bytes(&data[..]); + data.clear(); + } + } + /// Encodes a node to the current graph. fn encode_node( &mut self, node: &NodeInfo, record_graph: &Option<Lock<DepGraphQuery>>, ) -> DepNodeIndex { - node.encode::<D>(&mut self.encoder); - self.record(node.node, node.edges.len(), |_| node.edges[..].to_vec(), record_graph) + let index = self.alloc_index(); + node.encode::<D>(&mut self.mem_encoder, index); + self.flush_mem_encoder(); + self.record(node.node, index, node.edges.len(), |_| node.edges[..].to_vec(), record_graph) } /// Encodes a node that was promoted from the previous graph. It reads the information directly from @@ -581,20 +617,22 @@ impl<D: Deps> EncoderState<D> { record_graph: &Option<Lock<DepGraphQuery>>, colors: &DepNodeColorMap, ) -> DepNodeIndex { + let index = self.alloc_index(); let node = self.previous.index_to_node(prev_index); - let fingerprint = self.previous.fingerprint_by_index(prev_index); let edge_count = NodeInfo::encode_promoted::<D>( - &mut self.encoder, + &mut self.mem_encoder, node, + index, fingerprint, prev_index, colors, &self.previous, ); - + self.flush_mem_encoder(); self.record( node, + index, edge_count, |this| { this.previous @@ -603,12 +641,14 @@ impl<D: Deps> EncoderState<D> { .collect() }, record_graph, - ) + ); + index } fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { let Self { mut encoder, + mem_encoder, total_node_count, total_edge_count, stats: _, @@ -617,6 +657,8 @@ impl<D: Deps> EncoderState<D> { previous, } = self; + encoder.emit_raw_bytes(&mem_encoder.data); + let node_count = total_node_count.try_into().unwrap(); let edge_count = total_edge_count.try_into().unwrap(); diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 2aedd365adc..b159b876c7e 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,9 +1,9 @@ // tidy-alphabetical-start #![allow(rustc::potential_query_instability, internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(let_chains)] #![feature(min_specialization)] // tidy-alphabetical-end diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b121755acd9..4a252a7b528 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,13 +10,13 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs index e4792563e71..729c921450e 100644 --- a/compiler/rustc_sanitizers/src/lib.rs +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -4,7 +4,7 @@ //! compiler. // tidy-alphabetical-start -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] // tidy-alphabetical-end pub mod cfi; diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 0a55504a556..00bad8e70cf 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -10,6 +10,8 @@ use crate::int_overflow::DebugStrictAdd; use crate::leb128; use crate::serialize::{Decodable, Decoder, Encodable, Encoder}; +pub mod mem_encoder; + // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- diff --git a/compiler/rustc_serialize/src/opaque/mem_encoder.rs b/compiler/rustc_serialize/src/opaque/mem_encoder.rs new file mode 100644 index 00000000000..56beebb49af --- /dev/null +++ b/compiler/rustc_serialize/src/opaque/mem_encoder.rs @@ -0,0 +1,128 @@ +use super::IntEncodedWithFixedSize; +use crate::{Encodable, Encoder, leb128}; + +pub struct MemEncoder { + pub data: Vec<u8>, +} + +impl MemEncoder { + pub fn new() -> MemEncoder { + MemEncoder { data: vec![] } + } + + #[inline] + pub fn position(&self) -> usize { + self.data.len() + } + + pub fn finish(self) -> Vec<u8> { + self.data + } + + /// Write up to `N` bytes to this encoder. + /// + /// This function can be used to avoid the overhead of calling memcpy for writes that + /// have runtime-variable length, but are small and have a small fixed upper bound. + /// + /// This can be used to do in-place encoding as is done for leb128 (without this function + /// we would need to write to a temporary buffer then memcpy into the encoder), and it can + /// also be used to implement the varint scheme we use for rmeta and dep graph encoding, + /// where we only want to encode the first few bytes of an integer. Note that common + /// architectures support fixed-size writes up to 8 bytes with one instruction, so while this + /// does in some sense do wasted work, we come out ahead. + #[inline] + pub fn write_with<const N: usize>(&mut self, visitor: impl FnOnce(&mut [u8; N]) -> usize) { + self.data.reserve(N); + + let old_len = self.data.len(); + + // SAFETY: The above `reserve` ensures that there is enough + // room to write the encoded value to the vector's internal buffer. + // The memory is also initialized as 0. + let buf = unsafe { + let buf = self.data.as_mut_ptr().add(old_len) as *mut [u8; N]; + *buf = [0; N]; + &mut *buf + }; + let written = visitor(buf); + if written > N { + Self::panic_invalid_write::<N>(written); + } + unsafe { self.data.set_len(old_len + written) }; + } + + #[cold] + #[inline(never)] + fn panic_invalid_write<const N: usize>(written: usize) { + panic!("MemEncoder::write_with::<{N}> cannot be used to write {written} bytes"); + } + + /// Helper for calls where [`MemEncoder::write_with`] always writes the whole array. + #[inline] + pub fn write_array<const N: usize>(&mut self, buf: [u8; N]) { + self.write_with(|dest| { + *dest = buf; + N + }) + } +} + +macro_rules! write_leb128 { + ($this_fn:ident, $int_ty:ty, $write_leb_fn:ident) => { + #[inline] + fn $this_fn(&mut self, v: $int_ty) { + self.write_with(|buf| leb128::$write_leb_fn(buf, v)) + } + }; +} + +impl Encoder for MemEncoder { + write_leb128!(emit_usize, usize, write_usize_leb128); + write_leb128!(emit_u128, u128, write_u128_leb128); + write_leb128!(emit_u64, u64, write_u64_leb128); + write_leb128!(emit_u32, u32, write_u32_leb128); + + #[inline] + fn emit_u16(&mut self, v: u16) { + self.write_array(v.to_le_bytes()); + } + + #[inline] + fn emit_u8(&mut self, v: u8) { + self.write_array([v]); + } + + write_leb128!(emit_isize, isize, write_isize_leb128); + write_leb128!(emit_i128, i128, write_i128_leb128); + write_leb128!(emit_i64, i64, write_i64_leb128); + write_leb128!(emit_i32, i32, write_i32_leb128); + + #[inline] + fn emit_i16(&mut self, v: i16) { + self.write_array(v.to_le_bytes()); + } + + #[inline] + fn emit_raw_bytes(&mut self, s: &[u8]) { + self.data.extend_from_slice(s); + } +} + +// Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc., +// since the default implementations call `encode` on their slices internally. +impl Encodable<MemEncoder> for [u8] { + fn encode(&self, e: &mut MemEncoder) { + Encoder::emit_usize(e, self.len()); + e.emit_raw_bytes(self); + } +} + +impl Encodable<MemEncoder> for IntEncodedWithFixedSize { + #[inline] + fn encode(&self, e: &mut MemEncoder) { + let start_pos = e.position(); + e.write_array(self.0.to_le_bytes()); + let end_pos = e.position(); + debug_assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); + } +} diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 231ca434962..cbfe9e0da6a 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -142,6 +142,10 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { | (sym::target_has_atomic, Some(_)) | (sym::target_has_atomic_equal_alignment, Some(_)) | (sym::target_has_atomic_load_store, Some(_)) + | (sym::target_has_reliable_f16, None | Some(_)) + | (sym::target_has_reliable_f16_math, None | Some(_)) + | (sym::target_has_reliable_f128, None | Some(_)) + | (sym::target_has_reliable_f128_math, None | Some(_)) | (sym::target_thread_local, None) => disallow(cfg, "--target"), (sym::fmt_debug, None | Some(_)) => disallow(cfg, "-Z fmt-debug"), (sym::emscripten_wasm_eh, None | Some(_)) => disallow(cfg, "-Z emscripten_wasm_eh"), diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 0e19b982a13..ec8e9898dc7 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,8 +1,8 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(default_field_values)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustc_attrs)] // To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums // with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers"). diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f788fd48037..fccdaed21a2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,6 +17,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -24,7 +25,6 @@ #![feature(core_io_borrowed_buf)] #![feature(hash_set_entry)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(map_try_insert)] #![feature(negative_impls)] #![feature(read_buf)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9ddeef6c462..31b85677997 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -623,6 +623,7 @@ symbols! { cfg_target_feature, cfg_target_has_atomic, cfg_target_has_atomic_equal_alignment, + cfg_target_has_reliable_f16_f128, cfg_target_thread_local, cfg_target_vendor, cfg_trace: "<cfg>", // must not be a valid identifier @@ -2074,6 +2075,10 @@ symbols! { target_has_atomic, target_has_atomic_equal_alignment, target_has_atomic_load_store, + target_has_reliable_f128, + target_has_reliable_f128_math, + target_has_reliable_f16, + target_has_reliable_f16_math, target_os, target_pointer_width, target_thread_local, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index cc33974cc62..ca8918e06aa 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -89,9 +89,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index df99280f571..922c18448d5 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,12 +9,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(debug_closure_helpers)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 54544a90226..595dd12d6f6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1523,19 +1523,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_term.def_id)?; - let trait_assoc_ident = trait_assoc_item.ident(self.tcx); - let mut associated_items = vec![]; self.tcx.for_each_relevant_impl( self.tcx.trait_of_item(proj.projection_term.def_id)?, proj.projection_term.self_ty(), |impl_def_id| { associated_items.extend( - self.tcx - .associated_items(impl_def_id) - .in_definition_order() - .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident), + self.tcx.associated_items(impl_def_id).in_definition_order().find( + |assoc| { + assoc.trait_item_def_id == Some(proj.projection_term.def_id) + }, + ), ); }, ); diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 93c11805304..7613a0cef52 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -14,6 +14,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -23,7 +24,6 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iterator_try_reduce)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(try_blocks)] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 57051e0df55..ea0f6b8dfba 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -13,7 +14,6 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iterator_try_collect)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 417803e75ea..9b066b6869f 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -442,6 +442,14 @@ pub trait Predicate<I: Interner<Predicate = Self>>: { fn as_clause(self) -> Option<I::Clause>; + fn as_normalizes_to(self) -> Option<ty::Binder<I, ty::NormalizesTo<I>>> { + let kind = self.kind(); + match kind.skip_binder() { + ty::PredicateKind::NormalizesTo(pred) => Some(kind.rebind(pred)), + _ => None, + } + } + // FIXME: Eventually uplift the impl out of rustc and make this defaulted. fn allow_normalization(self) -> bool; } diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 330b4098764..16c0c118040 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1138,6 +1138,10 @@ pub(crate) mod builtin { issue = "29599", reason = "`concat_idents` is not stable enough for use and is subject to change" )] + #[deprecated( + since = "1.88.0", + note = "use `${concat(...)}` with the `macro_metavar_expr_concat` feature instead" + )] #[rustc_builtin_macro] #[macro_export] macro_rules! concat_idents { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 7ec0ac71271..aed5a043c11 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -162,8 +162,14 @@ //! The [`is_some`] and [`is_none`] methods return [`true`] if the [`Option`] //! is [`Some`] or [`None`], respectively. //! +//! The [`is_some_and`] and [`is_none_or`] methods apply the provided function +//! to the contents of the [`Option`] to produce a boolean value. +//! If this is [`None`] then a default result is returned instead without executing the function. +//! //! [`is_none`]: Option::is_none //! [`is_some`]: Option::is_some +//! [`is_some_and`]: Option::is_some_and +//! [`is_none_or`]: Option::is_none_or //! //! ## Adapters for working with references //! @@ -177,6 +183,10 @@ //! <code>[Option]<[Pin]<[&]T>></code> //! * [`as_pin_mut`] converts from <code>[Pin]<[&mut] [Option]\<T>></code> to //! <code>[Option]<[Pin]<[&mut] T>></code> +//! * [`as_slice`] returns a one-element slice of the contained value, if any. +//! If this is [`None`], an empty slice is returned. +//! * [`as_mut_slice`] returns a mutable one-element slice of the contained value, if any. +//! If this is [`None`], an empty slice is returned. //! //! [&]: reference "shared reference" //! [&mut]: reference "mutable reference" @@ -187,6 +197,8 @@ //! [`as_pin_mut`]: Option::as_pin_mut //! [`as_pin_ref`]: Option::as_pin_ref //! [`as_ref`]: Option::as_ref +//! [`as_slice`]: Option::as_slice +//! [`as_mut_slice`]: Option::as_mut_slice //! //! ## Extracting the contained value //! @@ -200,12 +212,15 @@ //! (which must implement the [`Default`] trait) //! * [`unwrap_or_else`] returns the result of evaluating the provided //! function +//! * [`unwrap_unchecked`] produces *[undefined behavior]* //! //! [`expect`]: Option::expect //! [`unwrap`]: Option::unwrap //! [`unwrap_or`]: Option::unwrap_or //! [`unwrap_or_default`]: Option::unwrap_or_default //! [`unwrap_or_else`]: Option::unwrap_or_else +//! [`unwrap_unchecked`]: Option::unwrap_unchecked +//! [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html //! //! ## Transforming contained values //! @@ -230,8 +245,9 @@ //! * [`filter`] calls the provided predicate function on the contained //! value `t` if the [`Option`] is [`Some(t)`], and returns [`Some(t)`] //! if the function returns `true`; otherwise, returns [`None`] -//! * [`flatten`] removes one level of nesting from an -//! [`Option<Option<T>>`] +//! * [`flatten`] removes one level of nesting from an [`Option<Option<T>>`] +//! * [`inspect`] method takes ownership of the [`Option`] and applies +//! the provided function to the contained value by reference if [`Some`] //! * [`map`] transforms [`Option<T>`] to [`Option<U>`] by applying the //! provided function to the contained value of [`Some`] and leaving //! [`None`] values unchanged @@ -239,6 +255,7 @@ //! [`Some(t)`]: Some //! [`filter`]: Option::filter //! [`flatten`]: Option::flatten +//! [`inspect`]: Option::inspect //! [`map`]: Option::map //! //! These methods transform [`Option<T>`] to a value of a possibly @@ -621,6 +638,10 @@ impl<T> Option<T> { /// /// let x: Option<u32> = None; /// assert_eq!(x.is_some_and(|x| x > 1), false); + /// + /// let x: Option<String> = Some("ownership".to_string()); + /// assert_eq!(x.as_ref().is_some_and(|x| x.len() > 1), true); + /// println!("still alive {:?}", x); /// ``` #[must_use] #[inline] @@ -665,6 +686,10 @@ impl<T> Option<T> { /// /// let x: Option<u32> = None; /// assert_eq!(x.is_none_or(|x| x > 1), true); + /// + /// let x: Option<String> = Some("ownership".to_string()); + /// assert_eq!(x.as_ref().is_none_or(|x| x.len() > 1), true); + /// println!("still alive {:?}", x); /// ``` #[must_use] #[inline] diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 8f1b5275871..9737d0baec7 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -59,6 +59,7 @@ pub use crate::hash::macros::Hash; #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] +#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[doc(no_inline)] pub use crate::{ assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 48ab9267f21..736ffb7d0ca 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -259,8 +259,14 @@ //! The [`is_ok`] and [`is_err`] methods return [`true`] if the [`Result`] //! is [`Ok`] or [`Err`], respectively. //! +//! The [`is_ok_and`] and [`is_err_and`] methods apply the provided function +//! to the contents of the [`Result`] to produce a boolean value. If the [`Result`] does not have the expected variant +//! then [`false`] is returned instead without executing the function. +//! //! [`is_err`]: Result::is_err //! [`is_ok`]: Result::is_ok +//! [`is_ok_and`]: Result::is_ok_and +//! [`is_err_and`]: Result::is_err_and //! //! ## Adapters for working with references //! @@ -287,6 +293,7 @@ //! (which must implement the [`Default`] trait) //! * [`unwrap_or_else`] returns the result of evaluating the provided //! function +//! * [`unwrap_unchecked`] produces *[undefined behavior]* //! //! The panicking methods [`expect`] and [`unwrap`] require `E` to //! implement the [`Debug`] trait. @@ -297,6 +304,8 @@ //! [`unwrap_or`]: Result::unwrap_or //! [`unwrap_or_default`]: Result::unwrap_or_default //! [`unwrap_or_else`]: Result::unwrap_or_else +//! [`unwrap_unchecked`]: Result::unwrap_unchecked +//! [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html //! //! These methods extract the contained value in a [`Result<T, E>`] when it //! is the [`Err`] variant. They require `T` to implement the [`Debug`] @@ -304,10 +313,13 @@ //! //! * [`expect_err`] panics with a provided custom message //! * [`unwrap_err`] panics with a generic message +//! * [`unwrap_err_unchecked`] produces *[undefined behavior]* //! //! [`Debug`]: crate::fmt::Debug //! [`expect_err`]: Result::expect_err //! [`unwrap_err`]: Result::unwrap_err +//! [`unwrap_err_unchecked`]: Result::unwrap_err_unchecked +//! [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html //! //! ## Transforming contained values //! @@ -330,21 +342,29 @@ //! [`Some(v)`]: Option::Some //! [`transpose`]: Result::transpose //! -//! This method transforms the contained value of the [`Ok`] variant: +//! These methods transform the contained value of the [`Ok`] variant: //! //! * [`map`] transforms [`Result<T, E>`] into [`Result<U, E>`] by applying //! the provided function to the contained value of [`Ok`] and leaving //! [`Err`] values unchanged +//! * [`inspect`] takes ownership of the [`Result`], applies the +//! provided function to the contained value by reference, +//! and then returns the [`Result`] //! //! [`map`]: Result::map +//! [`inspect`]: Result::inspect //! -//! This method transforms the contained value of the [`Err`] variant: +//! These methods transform the contained value of the [`Err`] variant: //! //! * [`map_err`] transforms [`Result<T, E>`] into [`Result<T, F>`] by //! applying the provided function to the contained value of [`Err`] and //! leaving [`Ok`] values unchanged +//! * [`inspect_err`] takes ownership of the [`Result`], applies the +//! provided function to the contained value of [`Err`] by reference, +//! and then returns the [`Result`] //! //! [`map_err`]: Result::map_err +//! [`inspect_err`]: Result::inspect_err //! //! These methods transform a [`Result<T, E>`] into a value of a possibly //! different type `U`: @@ -578,6 +598,10 @@ impl<T, E> Result<T, E> { /// /// let x: Result<u32, &str> = Err("hey"); /// assert_eq!(x.is_ok_and(|x| x > 1), false); + /// + /// let x: Result<String, &str> = Ok("ownership".to_string()); + /// assert_eq!(x.as_ref().is_ok_and(|x| x.len() > 1), true); + /// println!("still alive {:?}", x); /// ``` #[must_use] #[inline] @@ -623,6 +647,10 @@ impl<T, E> Result<T, E> { /// /// let x: Result<u32, Error> = Ok(123); /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false); + /// + /// let x: Result<u32, String> = Err("ownership".to_string()); + /// assert_eq!(x.as_ref().is_err_and(|x| x.len() > 1), true); + /// println!("still alive {:?}", x); /// ``` #[must_use] #[inline] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 3536e84d58b..7b8f2dd46d6 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -163,4 +163,10 @@ check-cfg = [ # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg 'cfg(feature, values(any()))', + # Internal features aren't marked known config by default, we use these to + # gate tests. + 'cfg(target_has_reliable_f16)', + 'cfg(target_has_reliable_f16_math)', + 'cfg(target_has_reliable_f128)', + 'cfg(target_has_reliable_f128_math)', ] diff --git a/library/std/build.rs b/library/std/build.rs index 40a56d4930d..ef695601a44 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -7,12 +7,6 @@ fn main() { let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set"); let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set"); - let target_abi = env::var("CARGO_CFG_TARGET_ABI").expect("CARGO_CFG_TARGET_ABI was not set"); - let target_pointer_width: u32 = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") - .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") - .parse() - .unwrap(); - let is_miri = env::var_os("CARGO_CFG_MIRI").is_some(); println!("cargo:rustc-check-cfg=cfg(netbsd10)"); if target_os == "netbsd" && env::var("RUSTC_STD_NETBSD10").is_ok() { @@ -80,108 +74,4 @@ fn main() { println!("cargo:rustc-cfg=backtrace_in_libstd"); println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap()); - - // Emit these on platforms that have no known ABI bugs, LLVM selection bugs, lowering bugs, - // missing symbols, or other problems, to determine when tests get run. - // If more broken platforms are found, please update the tracking issue at - // <https://github.com/rust-lang/rust/issues/116909> - // - // Some of these match arms are redundant; the goal is to separate reasons that the type is - // unreliable, even when multiple reasons might fail the same platform. - println!("cargo:rustc-check-cfg=cfg(reliable_f16)"); - println!("cargo:rustc-check-cfg=cfg(reliable_f128)"); - - // This is a step beyond only having the types and basic functions available. Math functions - // aren't consistently available or correct. - println!("cargo:rustc-check-cfg=cfg(reliable_f16_math)"); - println!("cargo:rustc-check-cfg=cfg(reliable_f128_math)"); - - let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) { - // We can always enable these in Miri as that is not affected by codegen bugs. - _ if is_miri => true, - // Selection failure <https://github.com/llvm/llvm-project/issues/50374> - ("s390x", _) => false, - // Unsupported <https://github.com/llvm/llvm-project/issues/94434> - ("arm64ec", _) => false, - // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> - ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, - // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981> - ("csky", _) => false, - ("hexagon", _) => false, - ("powerpc" | "powerpc64", _) => false, - ("sparc" | "sparc64", _) => false, - ("wasm32" | "wasm64", _) => false, - // `f16` support only requires that symbols converting to and from `f32` are available. We - // provide these in `compiler-builtins`, so `f16` should be available on all platforms that - // do not have other ABI issues or LLVM crashes. - _ => true, - }; - - let has_reliable_f128 = match (target_arch.as_str(), target_os.as_str()) { - // We can always enable these in Miri as that is not affected by codegen bugs. - _ if is_miri => true, - // Unsupported <https://github.com/llvm/llvm-project/issues/94434> - ("arm64ec", _) => false, - // Selection bug <https://github.com/llvm/llvm-project/issues/96432> - ("mips64" | "mips64r6", _) => false, - // Selection bug <https://github.com/llvm/llvm-project/issues/95471> - ("nvptx64", _) => false, - // ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full - // list at <https://github.com/rust-lang/rust/issues/116909>) - ("powerpc" | "powerpc64", _) => false, - // ABI unsupported <https://github.com/llvm/llvm-project/issues/41838> - ("sparc", _) => false, - // Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may - // not fail if our compiler-builtins is linked. - ("x86", _) => false, - // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> - ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, - // There are no known problems on other platforms, so the only requirement is that symbols - // are available. `compiler-builtins` provides all symbols required for core `f128` - // support, so this should work for everything else. - _ => true, - }; - - // Configure platforms that have reliable basics but may have unreliable math. - - // LLVM is currently adding missing routines, <https://github.com/llvm/llvm-project/issues/93566> - let has_reliable_f16_math = has_reliable_f16 - && match (target_arch.as_str(), target_os.as_str()) { - // FIXME: Disabled on Miri as the intrinsics are not implemented yet. - _ if is_miri => false, - // x86 has a crash for `powi`: <https://github.com/llvm/llvm-project/issues/105747> - ("x86" | "x86_64", _) => false, - // Assume that working `f16` means working `f16` math for most platforms, since - // operations just go through `f32`. - _ => true, - }; - - let has_reliable_f128_math = has_reliable_f128 - && match (target_arch.as_str(), target_os.as_str()) { - // FIXME: Disabled on Miri as the intrinsics are not implemented yet. - _ if is_miri => false, - // LLVM lowers `fp128` math to `long double` symbols even on platforms where - // `long double` is not IEEE binary128. See - // <https://github.com/llvm/llvm-project/issues/44744>. - // - // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits - // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86` - // (ld is 80-bit extended precision). - ("x86_64", _) => false, - (_, "linux") if target_pointer_width == 64 => true, - _ => false, - }; - - if has_reliable_f16 { - println!("cargo:rustc-cfg=reliable_f16"); - } - if has_reliable_f128 { - println!("cargo:rustc-cfg=reliable_f128"); - } - if has_reliable_f16_math { - println!("cargo:rustc-cfg=reliable_f16_math"); - } - if has_reliable_f128_math { - println!("cargo:rustc-cfg=reliable_f128_math"); - } } diff --git a/library/std/src/env.rs b/library/std/src/env.rs index c84a72c4fad..1593969e114 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -13,7 +13,7 @@ use crate::error::Error; use crate::ffi::{OsStr, OsString}; use crate::path::{Path, PathBuf}; -use crate::sys::os as os_imp; +use crate::sys::{env as env_imp, os as os_imp}; use crate::{fmt, io, sys}; /// Returns the current working directory as a [`PathBuf`]. @@ -96,7 +96,7 @@ pub struct Vars { /// [`env::vars_os()`]: vars_os #[stable(feature = "env", since = "1.0.0")] pub struct VarsOs { - inner: os_imp::Env, + inner: env_imp::Env, } /// Returns an iterator of (variable, value) pairs of strings, for all the @@ -150,7 +150,7 @@ pub fn vars() -> Vars { #[must_use] #[stable(feature = "env", since = "1.0.0")] pub fn vars_os() -> VarsOs { - VarsOs { inner: os_imp::env() } + VarsOs { inner: env_imp::env() } } #[stable(feature = "env", since = "1.0.0")] @@ -259,7 +259,7 @@ pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> { } fn _var_os(key: &OsStr) -> Option<OsString> { - os_imp::getenv(key) + env_imp::getenv(key) } /// The error type for operations interacting with environment variables. @@ -363,7 +363,7 @@ impl Error for VarError { #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) { let (key, value) = (key.as_ref(), value.as_ref()); - unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| { + unsafe { env_imp::setenv(key, value) }.unwrap_or_else(|e| { panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}") }) } @@ -434,7 +434,7 @@ pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) { #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var<K: AsRef<OsStr>>(key: K) { let key = key.as_ref(); - unsafe { os_imp::unsetenv(key) } + unsafe { env_imp::unsetenv(key) } .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}")) } diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index 217528fdf1c..2b416b13fa5 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -22,7 +22,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.7_f128; /// let g = 3.0_f128; @@ -49,7 +53,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.01_f128; /// let g = 4.0_f128; @@ -76,7 +84,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.3_f128; /// let g = -3.3_f128; @@ -108,7 +120,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.3_f128; /// let g = -3.3_f128; @@ -138,7 +154,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.7_f128; /// let g = 3.0_f128; @@ -166,7 +186,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 3.6_f128; /// let y = -3.6_f128; @@ -203,7 +227,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let m = 10.0_f128; /// let x = 4.0_f128; @@ -247,7 +275,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let a: f128 = 7.0; /// let b = 4.0; @@ -289,7 +321,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let a: f128 = 7.0; /// let b = 4.0; @@ -326,7 +362,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0_f128; /// let abs_difference = (x.powi(2) - (x * x)).abs(); @@ -354,7 +394,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0_f128; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); @@ -386,7 +430,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let positive = 4.0_f128; /// let negative = -4.0_f128; @@ -417,7 +465,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let one = 1.0f128; /// // e^1 @@ -448,7 +500,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 2.0f128; /// @@ -479,7 +535,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let one = 1.0f128; /// // e^1 @@ -495,7 +555,11 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.ln(), f128::NEG_INFINITY); /// assert!((-42_f128).ln().is_nan()); @@ -526,7 +590,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let five = 5.0f128; /// @@ -540,7 +608,11 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.log(10.0), f128::NEG_INFINITY); /// assert!((-42_f128).log(10.0).is_nan()); @@ -567,7 +639,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let two = 2.0f128; /// @@ -581,7 +657,11 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.log2(), f128::NEG_INFINITY); /// assert!((-42_f128).log2().is_nan()); @@ -608,7 +688,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let ten = 10.0f128; /// @@ -622,7 +706,11 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.log10(), f128::NEG_INFINITY); /// assert!((-42_f128).log10().is_nan()); @@ -651,7 +739,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 8.0f128; /// @@ -687,7 +779,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0f128; /// let y = 3.0f128; @@ -717,7 +813,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = std::f128::consts::FRAC_PI_2; /// @@ -745,7 +845,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0 * std::f128::consts::PI; /// @@ -776,7 +880,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = std::f128::consts::FRAC_PI_4; /// let abs_difference = (x.tan() - 1.0).abs(); @@ -808,7 +916,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = std::f128::consts::FRAC_PI_2; /// @@ -843,7 +955,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = std::f128::consts::FRAC_PI_4; /// @@ -877,7 +993,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 1.0f128; /// @@ -915,7 +1035,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// // Positive angles measured counter-clockwise /// // from positive x axis @@ -957,7 +1081,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = std::f128::consts::FRAC_PI_4; /// let f = x.sin_cos(); @@ -992,7 +1120,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1e-8_f128; /// @@ -1028,7 +1160,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1e-8_f128; /// @@ -1043,7 +1179,11 @@ impl f128 { /// Out-of-range values: /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!((-1.0_f128).ln_1p(), f128::NEG_INFINITY); /// assert!((-2.0_f128).ln_1p().is_nan()); @@ -1072,7 +1212,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; /// let x = 1.0f128; @@ -1107,7 +1251,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; /// let x = 1.0f128; @@ -1142,7 +1290,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; /// let x = 1.0f128; @@ -1174,7 +1326,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1.0f128; /// let f = x.sinh().asinh(); @@ -1206,7 +1362,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1.0f128; /// let f = x.cosh().acosh(); @@ -1240,7 +1400,11 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; /// let f = e.tanh().atanh(); @@ -1274,7 +1438,11 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_gamma)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 5.0f128; /// @@ -1309,7 +1477,11 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_gamma)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0f128; /// @@ -1344,7 +1516,11 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_erf)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// /// The error function relates what percent of a normal distribution lies /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). /// fn within_standard_deviations(x: f128) -> f128 { @@ -1383,7 +1559,11 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_erf)] - /// # #[cfg(reliable_f128_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f128_math)] { /// let x: f128 = 0.123; /// /// let one = x.erf() + x.erfc(); diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index 4dadcbb5185..3f88ab2d400 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -22,7 +22,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.7_f16; /// let g = 3.0_f16; @@ -49,7 +53,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.01_f16; /// let g = 4.0_f16; @@ -76,7 +84,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.3_f16; /// let g = -3.3_f16; @@ -108,7 +120,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.3_f16; /// let g = -3.3_f16; @@ -138,7 +154,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.7_f16; /// let g = 3.0_f16; @@ -166,7 +186,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 3.6_f16; /// let y = -3.6_f16; @@ -203,7 +227,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let m = 10.0_f16; /// let x = 4.0_f16; @@ -247,7 +275,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let a: f16 = 7.0; /// let b = 4.0; @@ -289,7 +321,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let a: f16 = 7.0; /// let b = 4.0; @@ -326,7 +362,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0_f16; /// let abs_difference = (x.powi(2) - (x * x)).abs(); @@ -354,7 +394,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0_f16; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); @@ -386,7 +430,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let positive = 4.0_f16; /// let negative = -4.0_f16; @@ -417,7 +465,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let one = 1.0f16; /// // e^1 @@ -448,7 +500,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 2.0f16; /// @@ -479,7 +535,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let one = 1.0f16; /// // e^1 @@ -495,7 +555,11 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.ln(), f16::NEG_INFINITY); /// assert!((-42_f16).ln().is_nan()); @@ -526,7 +590,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let five = 5.0f16; /// @@ -540,7 +608,11 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.log(10.0), f16::NEG_INFINITY); /// assert!((-42_f16).log(10.0).is_nan()); @@ -567,7 +639,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let two = 2.0f16; /// @@ -581,7 +657,11 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.log2(), f16::NEG_INFINITY); /// assert!((-42_f16).log2().is_nan()); @@ -608,7 +688,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let ten = 10.0f16; /// @@ -622,7 +706,11 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.log10(), f16::NEG_INFINITY); /// assert!((-42_f16).log10().is_nan()); @@ -650,7 +738,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 8.0f16; /// @@ -685,7 +777,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0f16; /// let y = 3.0f16; @@ -715,7 +811,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = std::f16::consts::FRAC_PI_2; /// @@ -743,7 +843,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0 * std::f16::consts::PI; /// @@ -774,7 +878,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = std::f16::consts::FRAC_PI_4; /// let abs_difference = (x.tan() - 1.0).abs(); @@ -806,7 +914,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = std::f16::consts::FRAC_PI_2; /// @@ -841,7 +953,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = std::f16::consts::FRAC_PI_4; /// @@ -875,7 +991,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 1.0f16; /// @@ -913,7 +1033,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// // Positive angles measured counter-clockwise /// // from positive x axis @@ -955,7 +1079,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = std::f16::consts::FRAC_PI_4; /// let f = x.sin_cos(); @@ -990,7 +1118,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1e-4_f16; /// @@ -1026,7 +1158,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1e-4_f16; /// @@ -1041,7 +1177,11 @@ impl f16 { /// Out-of-range values: /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!((-1.0_f16).ln_1p(), f16::NEG_INFINITY); /// assert!((-2.0_f16).ln_1p().is_nan()); @@ -1070,7 +1210,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; /// let x = 1.0f16; @@ -1105,7 +1249,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; /// let x = 1.0f16; @@ -1140,7 +1288,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; /// let x = 1.0f16; @@ -1172,7 +1324,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1.0f16; /// let f = x.sinh().asinh(); @@ -1204,7 +1360,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1.0f16; /// let f = x.cosh().acosh(); @@ -1238,7 +1398,11 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; /// let f = e.tanh().atanh(); @@ -1272,7 +1436,11 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_gamma)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 5.0f16; /// @@ -1307,7 +1475,11 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_gamma)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0f16; /// @@ -1342,7 +1514,11 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_erf)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// /// The error function relates what percent of a normal distribution lies /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). /// fn within_standard_deviations(x: f16) -> f16 { @@ -1381,7 +1557,11 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_erf)] - /// # #[cfg(reliable_f16_math)] { + /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] + /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #[cfg(not(miri))] + /// # #[cfg(not(bootstrap))] + /// # #[cfg(target_has_reliable_f16_math)] { /// let x: f16 = 0.123; /// /// let one = x.erf() + x.erfc(); diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c07c391892d..91701576130 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -119,7 +119,7 @@ mod break_keyword {} #[doc(keyword = "const")] // -/// Compile-time constants, compile-time evaluable functions, and raw pointers. +/// Compile-time constants, compile-time blocks, compile-time evaluable functions, and raw pointers. /// /// ## Compile-time constants /// @@ -166,6 +166,12 @@ mod break_keyword {} /// /// For more detail on `const`, see the [Rust Book] or the [Reference]. /// +/// ## Compile-time blocks +/// +/// The `const` keyword can also be used to define a block of code that is evaluated at compile time. +/// This is useful for ensuring certain computations are completed before optimizations happen, as well as +/// before runtime. For more details, see the [Reference][const-blocks]. +/// /// ## Compile-time evaluable functions /// /// The other main use of the `const` keyword is in `const fn`. This marks a function as being @@ -184,6 +190,7 @@ mod break_keyword {} /// [pointer primitive]: pointer /// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#constants /// [Reference]: ../reference/items/constant-items.html +/// [const-blocks]: ../reference/expressions/block-expr.html#const-blocks /// [const-eval]: ../reference/const_eval.html mod const_keyword {} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3a52b779037..f77bf92a806 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -709,6 +709,7 @@ pub use core::primitive; // Re-export built-in macros defined through core. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] +#[cfg_attr(bootstrap, allow(deprecated_in_future))] pub use core::{ assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args, env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax, diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index c15d8c40085..68c9ac1e414 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -46,6 +46,7 @@ pub use crate::result::Result::{self, Err, Ok}; // Re-exported built-in macros #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] +#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[doc(no_inline)] pub use core::prelude::v1::{ assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index 6a37b32d229..0011f55dc14 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -2,6 +2,16 @@ #![forbid(unsafe_op_in_unsafe_fn)] +#[cfg(any( + all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))), + target_family = "windows", + target_os = "hermit", + target_os = "uefi", + target_os = "wasi", + target_os = "xous", +))] +mod common; + cfg_if::cfg_if! { if #[cfg(any( all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))), diff --git a/library/std/src/sys/args/uefi.rs b/library/std/src/sys/args/uefi.rs index 84406c7f69d..02dada382ef 100644 --- a/library/std/src/sys/args/uefi.rs +++ b/library/std/src/sys/args/uefi.rs @@ -1,14 +1,11 @@ use r_efi::protocols::loaded_image; +pub use super::common::Args; use crate::env::current_exe; use crate::ffi::OsString; use crate::iter::Iterator; use crate::sys::pal::helpers; -#[path = "common.rs"] -mod common; -pub use common::Args; - pub fn args() -> Args { let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]); diff --git a/library/std/src/sys/args/unix.rs b/library/std/src/sys/args/unix.rs index c087fd62965..a7b79ad396e 100644 --- a/library/std/src/sys/args/unix.rs +++ b/library/std/src/sys/args/unix.rs @@ -5,16 +5,13 @@ #![allow(dead_code)] // runtime init functions not used during testing +pub use super::common::Args; use crate::ffi::CStr; #[cfg(target_os = "hermit")] use crate::os::hermit::ffi::OsStringExt; #[cfg(not(target_os = "hermit"))] use crate::os::unix::ffi::OsStringExt; -#[path = "common.rs"] -mod common; -pub use common::Args; - /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { unsafe { imp::init(argc, argv) } diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasi.rs index 4795789e4c7..72063a87dc9 100644 --- a/library/std/src/sys/args/wasi.rs +++ b/library/std/src/sys/args/wasi.rs @@ -1,12 +1,9 @@ #![forbid(unsafe_op_in_unsafe_fn)] +pub use super::common::Args; use crate::ffi::{CStr, OsStr, OsString}; use crate::os::wasi::ffi::OsStrExt; -#[path = "common.rs"] -mod common; -pub use common::Args; - /// Returns the command line arguments pub fn args() -> Args { Args::new(maybe_args().unwrap_or(Vec::new())) diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index 47f0e5f2d05..81c44fabdcc 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -6,6 +6,7 @@ #[cfg(test)] mod tests; +pub use super::common::Args; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::os::windows::prelude::*; @@ -18,10 +19,6 @@ use crate::sys_common::AsInner; use crate::sys_common::wstr::WStrUnits; use crate::{io, iter, ptr}; -#[path = "common.rs"] -mod common; -pub use common::Args; - pub fn args() -> Args { // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 // string so it's safe for `WStrUnits` to use. diff --git a/library/std/src/sys/args/xous.rs b/library/std/src/sys/args/xous.rs index 09a47283d65..2010bad14d1 100644 --- a/library/std/src/sys/args/xous.rs +++ b/library/std/src/sys/args/xous.rs @@ -1,10 +1,7 @@ +pub use super::common::Args; use crate::sys::pal::os::get_application_parameters; use crate::sys::pal::os::params::ArgumentList; -#[path = "common.rs"] -mod common; -pub use common::Args; - pub fn args() -> Args { let Some(params) = get_application_parameters() else { return Args::new(vec![]); diff --git a/library/std/src/sys/env/common.rs b/library/std/src/sys/env/common.rs new file mode 100644 index 00000000000..f161ff073f3 --- /dev/null +++ b/library/std/src/sys/env/common.rs @@ -0,0 +1,48 @@ +use crate::ffi::OsString; +use crate::{fmt, vec}; + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub(super) fn new(env: Vec<(OsString, OsString)>) -> Self { + Env { iter: env.into_iter() } + } + + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + EnvStrDebug { slice: self.iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} diff --git a/library/std/src/sys/env/hermit.rs b/library/std/src/sys/env/hermit.rs new file mode 100644 index 00000000000..445ecdeb6a3 --- /dev/null +++ b/library/std/src/sys/env/hermit.rs @@ -0,0 +1,72 @@ +use core::slice::memchr; + +pub use super::common::Env; +use crate::collections::HashMap; +use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::io; +use crate::os::hermit::ffi::OsStringExt; +use crate::sync::Mutex; + +static ENV: Mutex<Option<HashMap<OsString, OsString>>> = Mutex::new(None); + +pub fn init(env: *const *const c_char) { + let mut guard = ENV.lock().unwrap(); + let map = guard.insert(HashMap::new()); + + if env.is_null() { + return; + } + + unsafe { + let mut environ = env; + while !(*environ).is_null() { + if let Some((key, value)) = parse(CStr::from_ptr(*environ).to_bytes()) { + map.insert(key, value); + } + environ = environ.add(1); + } + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + let guard = ENV.lock().unwrap(); + let env = guard.as_ref().unwrap(); + + let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect(); + + Env::new(result) +} + +pub fn getenv(k: &OsStr) -> Option<OsString> { + ENV.lock().unwrap().as_ref().unwrap().get(k).cloned() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let (k, v) = (k.to_owned(), v.to_owned()); + ENV.lock().unwrap().as_mut().unwrap().insert(k, v); + Ok(()) +} + +pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { + ENV.lock().unwrap().as_mut().unwrap().remove(k); + Ok(()) +} diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs new file mode 100644 index 00000000000..d81ff875c83 --- /dev/null +++ b/library/std/src/sys/env/mod.rs @@ -0,0 +1,48 @@ +//! Platform-dependent environment variables abstraction. + +#![forbid(unsafe_op_in_unsafe_fn)] + +#[cfg(any( + target_family = "unix", + target_os = "hermit", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + target_os = "uefi", + target_os = "wasi", + target_os = "xous", +))] +mod common; + +cfg_if::cfg_if! { + if #[cfg(target_family = "unix")] { + mod unix; + pub use unix::*; + } else if #[cfg(target_family = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs new file mode 100644 index 00000000000..85be9cd6ad4 --- /dev/null +++ b/library/std/src/sys/env/sgx.rs @@ -0,0 +1,55 @@ +#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers + +pub use super::common::Env; +use crate::collections::HashMap; +use crate::ffi::{OsStr, OsString}; +use crate::io; +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::{Mutex, Once}; + +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests +#[cfg_attr(test, linkage = "available_externally")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")] +static ENV: AtomicUsize = AtomicUsize::new(0); +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests +#[cfg_attr(test, linkage = "available_externally")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")] +static ENV_INIT: Once = Once::new(); +type EnvStore = Mutex<HashMap<OsString, OsString>>; + +fn get_env_store() -> Option<&'static EnvStore> { + unsafe { (ENV.load(Ordering::Relaxed) as *const EnvStore).as_ref() } +} + +fn create_env_store() -> &'static EnvStore { + ENV_INIT.call_once(|| { + ENV.store(Box::into_raw(Box::new(EnvStore::default())) as _, Ordering::Relaxed) + }); + unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) } +} + +pub fn env() -> Env { + let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> { + map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + }; + + let env = get_env_store().map(|env| clone_to_vec(&env.lock().unwrap())).unwrap_or_default(); + Env::new(env) +} + +pub fn getenv(k: &OsStr) -> Option<OsString> { + get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned()) +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let (k, v) = (k.to_owned(), v.to_owned()); + create_env_store().lock().unwrap().insert(k, v); + Ok(()) +} + +pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { + if let Some(env) = get_env_store() { + env.lock().unwrap().remove(k); + } + Ok(()) +} diff --git a/library/std/src/sys/env/solid.rs b/library/std/src/sys/env/solid.rs new file mode 100644 index 00000000000..ea77fc3c119 --- /dev/null +++ b/library/std/src/sys/env/solid.rs @@ -0,0 +1,96 @@ +use core::slice::memchr; + +pub use super::common::Env; +use crate::ffi::{CStr, OsStr, OsString}; +use crate::io; +use crate::os::raw::{c_char, c_int}; +use crate::os::solid::ffi::{OsStrExt, OsStringExt}; +use crate::sync::{PoisonError, RwLock}; +use crate::sys::common::small_c_string::run_with_cstr; + +static ENV_LOCK: RwLock<()> = RwLock::new(()); + +pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + unsafe extern "C" { + static mut environ: *const *const c_char; + } + + unsafe { + let _guard = env_read_lock(); + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env::new(result); + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option<OsString> { + // environment variables with a nul byte can't be set, so their value is + // always None as well + run_with_cstr(k.as_bytes(), &|k| { + let _guard = env_read_lock(); + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } + }) + .ok() + .flatten() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + run_with_cstr(k.as_bytes(), &|k| { + run_with_cstr(v.as_bytes(), &|v| { + let _guard = ENV_LOCK.write(); + cvt_env(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop) + }) + }) +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + run_with_cstr(n.as_bytes(), &|nbuf| { + let _guard = ENV_LOCK.write(); + cvt_env(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop) + }) +} + +/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this +/// function just returns a generic error. +fn cvt_env(t: c_int) -> io::Result<c_int> { + if t == -1 { Err(io::const_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } +} diff --git a/library/std/src/sys/env/uefi.rs b/library/std/src/sys/env/uefi.rs new file mode 100644 index 00000000000..1561df41cac --- /dev/null +++ b/library/std/src/sys/env/uefi.rs @@ -0,0 +1,102 @@ +pub use super::common::Env; +use crate::ffi::{OsStr, OsString}; +use crate::io; + +pub fn env() -> Env { + let env = uefi_env::get_all().expect("not supported on this platform"); + Env::new(env) +} + +pub fn getenv(key: &OsStr) -> Option<OsString> { + uefi_env::get(key) +} + +pub unsafe fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> { + uefi_env::set(key, val) +} + +pub unsafe fn unsetenv(key: &OsStr) -> io::Result<()> { + uefi_env::unset(key) +} + +mod uefi_env { + use crate::ffi::{OsStr, OsString}; + use crate::io; + use crate::os::uefi::ffi::OsStringExt; + use crate::ptr::NonNull; + use crate::sys::{helpers, unsupported_err}; + + pub(crate) fn get(key: &OsStr) -> Option<OsString> { + let shell = helpers::open_shell()?; + let mut key_ptr = helpers::os_string_to_raw(key)?; + unsafe { get_raw(shell, key_ptr.as_mut_ptr()) } + } + + pub(crate) fn set(key: &OsStr, val: &OsStr) -> io::Result<()> { + let mut key_ptr = helpers::os_string_to_raw(key) + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; + let mut val_ptr = helpers::os_string_to_raw(val) + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; + unsafe { set_raw(key_ptr.as_mut_ptr(), val_ptr.as_mut_ptr()) } + } + + pub(crate) fn unset(key: &OsStr) -> io::Result<()> { + let mut key_ptr = helpers::os_string_to_raw(key) + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; + unsafe { set_raw(key_ptr.as_mut_ptr(), crate::ptr::null_mut()) } + } + + pub(crate) fn get_all() -> io::Result<Vec<(OsString, OsString)>> { + let shell = helpers::open_shell().ok_or(unsupported_err())?; + + let mut vars = Vec::new(); + let val = unsafe { ((*shell.as_ptr()).get_env)(crate::ptr::null_mut()) }; + + if val.is_null() { + return Ok(vars); + } + + let mut start = 0; + + // UEFI Shell returns all keys separated by NULL. + // End of string is denoted by two NULLs + for i in 0.. { + if unsafe { *val.add(i) } == 0 { + // Two NULL signal end of string + if i == start { + break; + } + + let key = OsString::from_wide(unsafe { + crate::slice::from_raw_parts(val.add(start), i - start) + }); + // SAFETY: val.add(start) is always NULL terminated + let val = unsafe { get_raw(shell, val.add(start)) } + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; + + vars.push((key, val)); + start = i + 1; + } + } + + Ok(vars) + } + + unsafe fn get_raw( + shell: NonNull<r_efi::efi::protocols::shell::Protocol>, + key_ptr: *mut r_efi::efi::Char16, + ) -> Option<OsString> { + let val = unsafe { ((*shell.as_ptr()).get_env)(key_ptr) }; + helpers::os_string_from_raw(val) + } + + unsafe fn set_raw( + key_ptr: *mut r_efi::efi::Char16, + val_ptr: *mut r_efi::efi::Char16, + ) -> io::Result<()> { + let shell = helpers::open_shell().ok_or(unsupported_err())?; + let r = + unsafe { ((*shell.as_ptr()).set_env)(key_ptr, val_ptr, r_efi::efi::Boolean::FALSE) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } +} diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs new file mode 100644 index 00000000000..78c7af65f9e --- /dev/null +++ b/library/std/src/sys/env/unix.rs @@ -0,0 +1,126 @@ +use core::slice::memchr; + +use libc::c_char; + +pub use super::common::Env; +use crate::ffi::{CStr, OsStr, OsString}; +use crate::io; +use crate::os::unix::prelude::*; +use crate::sync::{PoisonError, RwLock}; +use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::cvt; + +// Use `_NSGetEnviron` on Apple platforms. +// +// `_NSGetEnviron` is the documented alternative (see `man environ`), and has +// been available since the first versions of both macOS and iOS. +// +// Nowadays, specifically since macOS 10.8, `environ` has been exposed through +// `libdyld.dylib`, which is linked via. `libSystem.dylib`: +// <https://github.com/apple-oss-distributions/dyld/blob/dyld-1160.6/libdyld/libdyldGlue.cpp#L913> +// +// So in the end, it likely doesn't really matter which option we use, but the +// performance cost of using `_NSGetEnviron` is extremely miniscule, and it +// might be ever so slightly more supported, so let's just use that. +// +// NOTE: The header where this is defined (`crt_externs.h`) was added to the +// iOS 13.0 SDK, which has been the source of a great deal of confusion in the +// past about the availability of this API. +// +// NOTE(madsmtm): Neither this nor using `environ` has been verified to not +// cause App Store rejections; if this is found to be the case, an alternative +// implementation of this is possible using `[NSProcessInfo environment]` +// - which internally uses `_NSGetEnviron` and a system-wide lock on the +// environment variables to protect against `setenv`, so using that might be +// desirable anyhow? Though it also means that we have to link to Foundation. +#[cfg(target_vendor = "apple")] +pub unsafe fn environ() -> *mut *const *const c_char { + unsafe { libc::_NSGetEnviron() as *mut *const *const c_char } +} + +// Use the `environ` static which is part of POSIX. +#[cfg(not(target_vendor = "apple"))] +pub unsafe fn environ() -> *mut *const *const c_char { + unsafe extern "C" { + static mut environ: *const *const c_char; + } + &raw mut environ +} + +static ENV_LOCK: RwLock<()> = RwLock::new(()); + +pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + unsafe { + let _guard = env_read_lock(); + let mut environ = *environ(); + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env::new(result); + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option<OsString> { + // environment variables with a nul byte can't be set, so their value is + // always None as well + run_with_cstr(k.as_bytes(), &|k| { + let _guard = env_read_lock(); + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } + }) + .ok() + .flatten() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + run_with_cstr(k.as_bytes(), &|k| { + run_with_cstr(v.as_bytes(), &|v| { + let _guard = ENV_LOCK.write(); + cvt(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop) + }) + }) +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + run_with_cstr(n.as_bytes(), &|nbuf| { + let _guard = ENV_LOCK.write(); + cvt(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop) + }) +} diff --git a/library/std/src/sys/env/unsupported.rs b/library/std/src/sys/env/unsupported.rs new file mode 100644 index 00000000000..98905e64827 --- /dev/null +++ b/library/std/src/sys/env/unsupported.rs @@ -0,0 +1,40 @@ +use crate::ffi::{OsStr, OsString}; +use crate::{fmt, io}; + +pub struct Env(!); + +impl Env { + // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + self.0 + } +} + +impl fmt::Debug for Env { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.0 + } +} + +pub fn env() -> Env { + panic!("not supported on this platform") +} + +pub fn getenv(_: &OsStr) -> Option<OsString> { + None +} + +pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) +} + +pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) +} diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs new file mode 100644 index 00000000000..3719f9db51e --- /dev/null +++ b/library/std/src/sys/env/wasi.rs @@ -0,0 +1,102 @@ +use core::slice::memchr; + +pub use super::common::Env; +use crate::ffi::{CStr, OsStr, OsString}; +use crate::io; +use crate::os::wasi::prelude::*; +use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::pal::os::{cvt, libc}; + +cfg_if::cfg_if! { + if #[cfg(target_feature = "atomics")] { + // Access to the environment must be protected by a lock in multi-threaded scenarios. + use crate::sync::{PoisonError, RwLock}; + static ENV_LOCK: RwLock<()> = RwLock::new(()); + pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) + } + pub fn env_write_lock() -> impl Drop { + ENV_LOCK.write().unwrap_or_else(PoisonError::into_inner) + } + } else { + // No need for a lock if we are single-threaded. + pub fn env_read_lock() -> impl Drop { + Box::new(()) + } + pub fn env_write_lock() -> impl Drop { + Box::new(()) + } + } +} + +pub fn env() -> Env { + unsafe { + let _guard = env_read_lock(); + + // Use `__wasilibc_get_environ` instead of `environ` here so that we + // don't require wasi-libc to eagerly initialize the environment + // variables. + let mut environ = libc::__wasilibc_get_environ(); + + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env::new(result); + } + + // See src/libstd/sys/pal/unix/os.rs, same as that + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option<OsString> { + // environment variables with a nul byte can't be set, so their value is + // always None as well + run_with_cstr(k.as_bytes(), &|k| { + let _guard = env_read_lock(); + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } + }) + .ok() + .flatten() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + run_with_cstr(k.as_bytes(), &|k| { + run_with_cstr(v.as_bytes(), &|v| unsafe { + let _guard = env_write_lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) + }) + }) +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + run_with_cstr(n.as_bytes(), &|nbuf| unsafe { + let _guard = env_write_lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) + }) +} diff --git a/library/std/src/sys/env/windows.rs b/library/std/src/sys/env/windows.rs new file mode 100644 index 00000000000..3c4d4a84cfd --- /dev/null +++ b/library/std/src/sys/env/windows.rs @@ -0,0 +1,133 @@ +use crate::ffi::{OsStr, OsString}; +use crate::os::windows::prelude::*; +use crate::sys::pal::{c, cvt, fill_utf16_buf, to_u16s}; +use crate::{fmt, io, ptr, slice}; + +pub struct Env { + base: *mut c::WCHAR, + iter: EnvIterator, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + iter: &'a EnvIterator, +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + let iter: EnvIterator = (*iter).clone(); + let mut list = f.debug_list(); + for (a, b) in iter { + list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); + } + list.finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { base: _, iter } = self; + EnvStrDebug { iter } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { base: _, iter } = self; + f.debug_list().entries(iter.clone()).finish() + } +} + +impl Iterator for Env { + type Item = (OsString, OsString); + + fn next(&mut self) -> Option<(OsString, OsString)> { + let Self { base: _, iter } = self; + iter.next() + } +} + +#[derive(Clone)] +struct EnvIterator(*mut c::WCHAR); + +impl Iterator for EnvIterator { + type Item = (OsString, OsString); + + fn next(&mut self) -> Option<(OsString, OsString)> { + let Self(cur) = self; + loop { + unsafe { + if **cur == 0 { + return None; + } + let p = *cur as *const u16; + let mut len = 0; + while *p.add(len) != 0 { + len += 1; + } + let s = slice::from_raw_parts(p, len); + *cur = cur.add(len + 1); + + // Windows allows environment variables to start with an equals + // symbol (in any other position, this is the separator between + // variable name and value). Since`s` has at least length 1 at + // this point (because the empty string terminates the array of + // environment variables), we can safely slice. + let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { + Some(p) => p, + None => continue, + }; + return Some(( + OsStringExt::from_wide(&s[..pos]), + OsStringExt::from_wide(&s[pos + 1..]), + )); + } + } + } +} + +impl Drop for Env { + fn drop(&mut self) { + unsafe { + c::FreeEnvironmentStringsW(self.base); + } + } +} + +pub fn env() -> Env { + unsafe { + let ch = c::GetEnvironmentStringsW(); + if ch.is_null() { + panic!("failure getting env string from OS: {}", io::Error::last_os_error()); + } + Env { base: ch, iter: EnvIterator(ch) } + } +} + +pub fn getenv(k: &OsStr) -> Option<OsString> { + let k = to_u16s(k).ok()?; + fill_utf16_buf( + |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, + OsStringExt::from_wide, + ) + .ok() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + // SAFETY: We ensure that k and v are null-terminated wide strings. + unsafe { + let k = to_u16s(k)?; + let v = to_u16s(v)?; + + cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) + } +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + // SAFETY: We ensure that v is a null-terminated wide strings. + unsafe { + let v = to_u16s(n)?; + cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) + } +} diff --git a/library/std/src/sys/env/xous.rs b/library/std/src/sys/env/xous.rs new file mode 100644 index 00000000000..232a3dafb0b --- /dev/null +++ b/library/std/src/sys/env/xous.rs @@ -0,0 +1,54 @@ +pub use super::common::Env; +use crate::collections::HashMap; +use crate::ffi::{OsStr, OsString}; +use crate::io; +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::{Mutex, Once}; +use crate::sys::pal::os::{get_application_parameters, params}; + +static ENV: AtomicUsize = AtomicUsize::new(0); +static ENV_INIT: Once = Once::new(); +type EnvStore = Mutex<HashMap<OsString, OsString>>; + +fn get_env_store() -> &'static EnvStore { + ENV_INIT.call_once(|| { + let env_store = EnvStore::default(); + if let Some(params) = get_application_parameters() { + for param in params { + if let Ok(envs) = params::EnvironmentBlock::try_from(¶m) { + let mut env_store = env_store.lock().unwrap(); + for env in envs { + env_store.insert(env.key.into(), env.value.into()); + } + break; + } + } + } + ENV.store(Box::into_raw(Box::new(env_store)) as _, Ordering::Relaxed) + }); + unsafe { &*core::ptr::with_exposed_provenance::<EnvStore>(ENV.load(Ordering::Relaxed)) } +} + +pub fn env() -> Env { + let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> { + map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + }; + + let env = clone_to_vec(&*get_env_store().lock().unwrap()); + Env::new(env) +} + +pub fn getenv(k: &OsStr) -> Option<OsString> { + get_env_store().lock().unwrap().get(k).cloned() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let (k, v) = (k.to_owned(), v.to_owned()); + get_env_store().lock().unwrap().insert(k, v); + Ok(()) +} + +pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { + get_env_store().lock().unwrap().remove(k); + Ok(()) +} diff --git a/library/std/src/sys/env/zkvm.rs b/library/std/src/sys/env/zkvm.rs new file mode 100644 index 00000000000..2eb7005ba12 --- /dev/null +++ b/library/std/src/sys/env/zkvm.rs @@ -0,0 +1,32 @@ +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_env; +pub use unsupported_env::{Env, env, setenv, unsetenv}; + +use crate::ffi::{OsStr, OsString}; +use crate::sys::os_str; +use crate::sys::pal::{WORD_SIZE, abi}; +use crate::sys_common::FromInner; + +pub fn getenv(varname: &OsStr) -> Option<OsString> { + let varname = varname.as_encoded_bytes(); + let nbytes = + unsafe { abi::sys_getenv(crate::ptr::null_mut(), 0, varname.as_ptr(), varname.len()) }; + if nbytes == usize::MAX { + return None; + } + + let nwords = (nbytes + WORD_SIZE - 1) / WORD_SIZE; + let words = unsafe { abi::sys_alloc_words(nwords) }; + + let nbytes2 = unsafe { abi::sys_getenv(words, nwords, varname.as_ptr(), varname.len()) }; + debug_assert_eq!(nbytes, nbytes2); + + // Convert to OsString. + // + // FIXME: We can probably get rid of the extra copy here if we + // reimplement "os_str" instead of just using the generic unix + // "os_str". + let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) }; + Some(OsString::from_inner(os_str::Buf { inner: u8s.to_vec() })) +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index e7b631999e0..f9a02b522e5 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -12,6 +12,7 @@ pub mod anonymous_pipe; pub mod args; pub mod backtrace; pub mod cmath; +pub mod env; pub mod env_consts; pub mod exit_guard; pub mod fd; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 70636760a83..ea636938d70 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -16,7 +16,10 @@ #![deny(unsafe_op_in_unsafe_fn)] #![allow(missing_docs, nonstandard_style)] +use crate::io::ErrorKind; +use crate::os::hermit::hermit_abi; use crate::os::raw::c_char; +use crate::sys::env; pub mod futex; pub mod os; @@ -25,9 +28,6 @@ pub mod pipe; pub mod thread; pub mod time; -use crate::io::ErrorKind; -use crate::os::hermit::hermit_abi; - pub fn unsupported<T>() -> crate::io::Result<T> { Err(unsupported_err()) } @@ -76,7 +76,7 @@ pub unsafe extern "C" fn runtime_entry( } // initialize environment - os::init_environment(env); + env::init(env); let result = unsafe { main(argc as isize, argv) }; diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index 791cdb1e57e..a998c3165e5 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -1,15 +1,10 @@ -use core::slice::memchr; - use super::hermit_abi; -use crate::collections::HashMap; use crate::error::Error as StdError; -use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; -use crate::os::hermit::ffi::OsStringExt; use crate::path::{self, PathBuf}; -use crate::sync::Mutex; use crate::sys::unsupported; -use crate::{fmt, io, str, vec}; +use crate::{fmt, io, str}; pub fn errno() -> i32 { unsafe { hermit_abi::get_errno() } @@ -68,115 +63,6 @@ pub fn current_exe() -> io::Result<PathBuf> { unsupported() } -static ENV: Mutex<Option<HashMap<OsString, OsString>>> = Mutex::new(None); - -pub fn init_environment(env: *const *const c_char) { - let mut guard = ENV.lock().unwrap(); - let map = guard.insert(HashMap::new()); - - if env.is_null() { - return; - } - - unsafe { - let mut environ = env; - while !(*environ).is_null() { - if let Some((key, value)) = parse(CStr::from_ptr(*environ).to_bytes()) { - map.insert(key, value); - } - environ = environ.add(1); - } - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - let guard = ENV.lock().unwrap(); - let env = guard.as_ref().unwrap(); - - let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect::<Vec<_>>(); - - Env { iter: result.into_iter() } -} - -pub fn getenv(k: &OsStr) -> Option<OsString> { - ENV.lock().unwrap().as_ref().unwrap().get(k).cloned() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let (k, v) = (k.to_owned(), v.to_owned()); - ENV.lock().unwrap().as_mut().unwrap().insert(k, v); - Ok(()) -} - -pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { - ENV.lock().unwrap().as_mut().unwrap().remove(k); - Ok(()) -} - pub fn temp_dir() -> PathBuf { PathBuf::from("/tmp") } diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs index 010634cf310..70f838679c9 100644 --- a/library/std/src/sys/pal/sgx/os.rs +++ b/library/std/src/sys/pal/sgx/os.rs @@ -1,14 +1,11 @@ use fortanix_sgx_abi::{Error, RESULT_SUCCESS}; -use crate::collections::HashMap; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sync::{Mutex, Once}; use crate::sys::{decode_error_kind, sgx_ineffective, unsupported}; -use crate::{fmt, io, str, vec}; +use crate::{fmt, io, str}; pub fn errno() -> i32 { RESULT_SUCCESS @@ -73,101 +70,6 @@ pub fn current_exe() -> io::Result<PathBuf> { unsupported() } -// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests -#[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")] -static ENV: AtomicUsize = AtomicUsize::new(0); -// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests -#[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")] -static ENV_INIT: Once = Once::new(); -type EnvStore = Mutex<HashMap<OsString, OsString>>; - -fn get_env_store() -> Option<&'static EnvStore> { - unsafe { (ENV.load(Ordering::Relaxed) as *const EnvStore).as_ref() } -} - -fn create_env_store() -> &'static EnvStore { - ENV_INIT.call_once(|| { - ENV.store(Box::into_raw(Box::new(EnvStore::default())) as _, Ordering::Relaxed) - }); - unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) } -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -pub fn env() -> Env { - let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> { - map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() - }; - - let iter = get_env_store() - .map(|env| clone_to_vec(&env.lock().unwrap())) - .unwrap_or_default() - .into_iter(); - Env { iter } -} - -pub fn getenv(k: &OsStr) -> Option<OsString> { - get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned()) -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let (k, v) = (k.to_owned(), v.to_owned()); - create_env_store().lock().unwrap().insert(k, v); - Ok(()) -} - -pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { - if let Some(env) = get_env_store() { - env.lock().unwrap().remove(k); - } - Ok(()) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem in SGX") } diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs index e3b2e0aa50f..8f5976b0592 100644 --- a/library/std/src/sys/pal/solid/os.rs +++ b/library/std/src/sys/pal/solid/os.rs @@ -1,14 +1,8 @@ -use core::slice::memchr; - use super::{error, itron, unsupported}; use crate::error::Error as StdError; -use crate::ffi::{CStr, OsStr, OsString}; -use crate::os::raw::{c_char, c_int}; -use crate::os::solid::ffi::{OsStrExt, OsStringExt}; +use crate::ffi::{OsStr, OsString}; use crate::path::{self, PathBuf}; -use crate::sync::{PoisonError, RwLock}; -use crate::sys::common::small_c_string::run_with_cstr; -use crate::{fmt, io, vec}; +use crate::{fmt, io}; // `solid` directly maps `errno`s to μITRON error codes. impl itron::error::ItronError { @@ -75,138 +69,6 @@ pub fn current_exe() -> io::Result<PathBuf> { unsupported() } -static ENV_LOCK: RwLock<()> = RwLock::new(()); - -pub fn env_read_lock() -> impl Drop { - ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe extern "C" { - static mut environ: *const *const c_char; - } - - unsafe { - let _guard = env_read_lock(); - let mut result = Vec::new(); - if !environ.is_null() { - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - } - return Env { iter: result.into_iter() }; - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> Option<OsString> { - // environment variables with a nul byte can't be set, so their value is - // always None as well - run_with_cstr(k.as_bytes(), &|k| { - let _guard = env_read_lock(); - let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; - - if v.is_null() { - Ok(None) - } else { - // SAFETY: `v` cannot be mutated while executing this line since we've a read lock - let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); - - Ok(Some(OsStringExt::from_vec(bytes))) - } - }) - .ok() - .flatten() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - run_with_cstr(k.as_bytes(), &|k| { - run_with_cstr(v.as_bytes(), &|v| { - let _guard = ENV_LOCK.write(); - cvt_env(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop) - }) - }) -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - run_with_cstr(n.as_bytes(), &|nbuf| { - let _guard = ENV_LOCK.write(); - cvt_env(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop) - }) -} - -/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this -/// function just returns a generic error. -fn cvt_env(t: c_int) -> io::Result<c_int> { - if t == -1 { Err(io::const_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } -} - pub fn temp_dir() -> PathBuf { panic!("no standard temporary directory on this platform") } diff --git a/library/std/src/sys/pal/teeos/os.rs b/library/std/src/sys/pal/teeos/os.rs index bf6945811ab..03f3c72b022 100644 --- a/library/std/src/sys/pal/teeos/os.rs +++ b/library/std/src/sys/pal/teeos/os.rs @@ -73,47 +73,6 @@ pub fn current_exe() -> io::Result<PathBuf> { unsupported() } -pub struct Env(!); - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} - } -} - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self(inner) = self; - match *inner {} - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -pub fn getenv(_: &OsStr) -> Option<OsString> { - None -} - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index d26d61890c1..bfd4dc81cb4 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -131,60 +131,6 @@ pub fn current_exe() -> io::Result<PathBuf> { helpers::device_path_to_text(protocol).map(PathBuf::from) } -pub struct EnvStrDebug<'a> { - iter: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut list = f.debug_list(); - for (a, b) in self.iter { - list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); - } - list.finish() - } -} - -pub struct Env(crate::vec::IntoIter<(OsString, OsString)>); - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - EnvStrDebug { iter: self.0.as_slice() } - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - self.0.next() - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -pub fn env() -> Env { - let env = uefi_env::get_all().expect("not supported on this platform"); - Env(env.into_iter()) -} - -pub fn getenv(key: &OsStr) -> Option<OsString> { - uefi_env::get(key) -} - -pub unsafe fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> { - uefi_env::set(key, val) -} - -pub unsafe fn unsetenv(key: &OsStr) -> io::Result<()> { - uefi_env::unset(key) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } @@ -213,85 +159,3 @@ pub fn exit(code: i32) -> ! { pub fn getpid() -> u32 { panic!("no pids on this platform") } - -mod uefi_env { - use crate::ffi::{OsStr, OsString}; - use crate::io; - use crate::os::uefi::ffi::OsStringExt; - use crate::ptr::NonNull; - use crate::sys::{helpers, unsupported_err}; - - pub(crate) fn get(key: &OsStr) -> Option<OsString> { - let shell = helpers::open_shell()?; - let mut key_ptr = helpers::os_string_to_raw(key)?; - unsafe { get_raw(shell, key_ptr.as_mut_ptr()) } - } - - pub(crate) fn set(key: &OsStr, val: &OsStr) -> io::Result<()> { - let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; - let mut val_ptr = helpers::os_string_to_raw(val) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; - unsafe { set_raw(key_ptr.as_mut_ptr(), val_ptr.as_mut_ptr()) } - } - - pub(crate) fn unset(key: &OsStr) -> io::Result<()> { - let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; - unsafe { set_raw(key_ptr.as_mut_ptr(), crate::ptr::null_mut()) } - } - - pub(crate) fn get_all() -> io::Result<Vec<(OsString, OsString)>> { - let shell = helpers::open_shell().ok_or(unsupported_err())?; - - let mut vars = Vec::new(); - let val = unsafe { ((*shell.as_ptr()).get_env)(crate::ptr::null_mut()) }; - - if val.is_null() { - return Ok(vars); - } - - let mut start = 0; - - // UEFI Shell returns all keys separated by NULL. - // End of string is denoted by two NULLs - for i in 0.. { - if unsafe { *val.add(i) } == 0 { - // Two NULL signal end of string - if i == start { - break; - } - - let key = OsString::from_wide(unsafe { - crate::slice::from_raw_parts(val.add(start), i - start) - }); - // SAFETY: val.add(start) is always NULL terminated - let val = unsafe { get_raw(shell, val.add(start)) } - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; - - vars.push((key, val)); - start = i + 1; - } - } - - Ok(vars) - } - - unsafe fn get_raw( - shell: NonNull<r_efi::efi::protocols::shell::Protocol>, - key_ptr: *mut r_efi::efi::Char16, - ) -> Option<OsString> { - let val = unsafe { ((*shell.as_ptr()).get_env)(key_ptr) }; - helpers::os_string_from_raw(val) - } - - unsafe fn set_raw( - key_ptr: *mut r_efi::efi::Char16, - val_ptr: *mut r_efi::efi::Char16, - ) -> io::Result<()> { - let shell = helpers::open_shell().ok_or(unsupported_err())?; - let r = - unsafe { ((*shell.as_ptr()).set_env)(key_ptr, val_ptr, r_efi::efi::Boolean::FALSE) }; - if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } - } -} diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index f47421c6705..4883303b88e 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -5,20 +5,15 @@ #[cfg(test)] mod tests; -use core::slice::memchr; - use libc::{c_char, c_int, c_void}; use crate::error::Error as StdError; -use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::{self, PathBuf}; -use crate::sync::{PoisonError, RwLock}; -use crate::sys::common::small_c_string::{run_path_with_cstr, run_with_cstr}; -#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))] -use crate::sys::weak::weak; -use crate::sys::{cvt, fd}; -use crate::{fmt, io, iter, mem, ptr, slice, str, vec}; +use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::cvt; +use crate::{fmt, io, iter, mem, ptr, slice, str}; const TMPBUF_SZ: usize = 128; @@ -552,166 +547,6 @@ pub fn current_exe() -> io::Result<PathBuf> { if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) } } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -// Use `_NSGetEnviron` on Apple platforms. -// -// `_NSGetEnviron` is the documented alternative (see `man environ`), and has -// been available since the first versions of both macOS and iOS. -// -// Nowadays, specifically since macOS 10.8, `environ` has been exposed through -// `libdyld.dylib`, which is linked via. `libSystem.dylib`: -// <https://github.com/apple-oss-distributions/dyld/blob/dyld-1160.6/libdyld/libdyldGlue.cpp#L913> -// -// So in the end, it likely doesn't really matter which option we use, but the -// performance cost of using `_NSGetEnviron` is extremely miniscule, and it -// might be ever so slightly more supported, so let's just use that. -// -// NOTE: The header where this is defined (`crt_externs.h`) was added to the -// iOS 13.0 SDK, which has been the source of a great deal of confusion in the -// past about the availability of this API. -// -// NOTE(madsmtm): Neither this nor using `environ` has been verified to not -// cause App Store rejections; if this is found to be the case, an alternative -// implementation of this is possible using `[NSProcessInfo environment]` -// - which internally uses `_NSGetEnviron` and a system-wide lock on the -// environment variables to protect against `setenv`, so using that might be -// desirable anyhow? Though it also means that we have to link to Foundation. -#[cfg(target_vendor = "apple")] -pub unsafe fn environ() -> *mut *const *const c_char { - libc::_NSGetEnviron() as *mut *const *const c_char -} - -// Use the `environ` static which is part of POSIX. -#[cfg(not(target_vendor = "apple"))] -pub unsafe fn environ() -> *mut *const *const c_char { - unsafe extern "C" { - static mut environ: *const *const c_char; - } - &raw mut environ -} - -static ENV_LOCK: RwLock<()> = RwLock::new(()); - -pub fn env_read_lock() -> impl Drop { - ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe { - let _guard = env_read_lock(); - let mut environ = *environ(); - let mut result = Vec::new(); - if !environ.is_null() { - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - } - return Env { iter: result.into_iter() }; - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> Option<OsString> { - // environment variables with a nul byte can't be set, so their value is - // always None as well - run_with_cstr(k.as_bytes(), &|k| { - let _guard = env_read_lock(); - let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; - - if v.is_null() { - Ok(None) - } else { - // SAFETY: `v` cannot be mutated while executing this line since we've a read lock - let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); - - Ok(Some(OsStringExt::from_vec(bytes))) - } - }) - .ok() - .flatten() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - run_with_cstr(k.as_bytes(), &|k| { - run_with_cstr(v.as_bytes(), &|v| { - let _guard = ENV_LOCK.write(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) - }) - }) -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - run_with_cstr(n.as_bytes(), &|nbuf| { - let _guard = ENV_LOCK.write(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) - }) -} - #[cfg(not(target_os = "espidf"))] pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } diff --git a/library/std/src/sys/pal/unix/sync/condvar.rs b/library/std/src/sys/pal/unix/sync/condvar.rs index 73631053e9f..efa6f8d7765 100644 --- a/library/std/src/sys/pal/unix/sync/condvar.rs +++ b/library/std/src/sys/pal/unix/sync/condvar.rs @@ -64,7 +64,10 @@ impl Condvar { // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c // // To work around this issue, the timeout is clamped to 1000 years. - #[cfg(target_vendor = "apple")] + // + // Cygwin implementation is based on NT API and a super large timeout + // makes the syscall block forever. + #[cfg(any(target_vendor = "apple", target_os = "cygwin"))] let dur = Duration::min(dur, Duration::from_secs(1000 * 365 * 86400)); let timeout = Timespec::now(Self::CLOCK).checked_add_duration(&dur); diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs index 48de4312885..a8ef97ecf67 100644 --- a/library/std/src/sys/pal/unsupported/os.rs +++ b/library/std/src/sys/pal/unsupported/os.rs @@ -62,47 +62,6 @@ pub fn current_exe() -> io::Result<PathBuf> { unsupported() } -pub struct Env(!); - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} - } -} - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self(inner) = self; - match *inner {} - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -pub fn getenv(_: &OsStr) -> Option<OsString> { - None -} - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index ba2b65a1f40..672cf70d1a5 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -1,19 +1,16 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use core::slice::memchr; - use crate::error::Error as StdError; use crate::ffi::{CStr, OsStr, OsString}; use crate::marker::PhantomData; -use crate::ops::Drop; use crate::os::wasi::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::common::small_c_string::{run_path_with_cstr, run_with_cstr}; +use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::unsupported; -use crate::{fmt, io, str, vec}; +use crate::{fmt, io, str}; // Add a few symbols not in upstream `libc` just yet. -mod libc { +pub mod libc { pub use libc::*; unsafe extern "C" { @@ -23,28 +20,6 @@ mod libc { } } -cfg_if::cfg_if! { - if #[cfg(target_feature = "atomics")] { - // Access to the environment must be protected by a lock in multi-threaded scenarios. - use crate::sync::{PoisonError, RwLock}; - static ENV_LOCK: RwLock<()> = RwLock::new(()); - pub fn env_read_lock() -> impl Drop { - ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) - } - pub fn env_write_lock() -> impl Drop { - ENV_LOCK.write().unwrap_or_else(PoisonError::into_inner) - } - } else { - // No need for a lock if we are single-threaded. - pub fn env_read_lock() -> impl Drop { - Box::new(()) - } - pub fn env_write_lock() -> impl Drop { - Box::new(()) - } - } -} - pub fn errno() -> i32 { unsafe extern "C" { #[thread_local] @@ -141,123 +116,6 @@ pub fn current_exe() -> io::Result<PathBuf> { unsupported() } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -pub fn env() -> Env { - unsafe { - let _guard = env_read_lock(); - - // Use `__wasilibc_get_environ` instead of `environ` here so that we - // don't require wasi-libc to eagerly initialize the environment - // variables. - let mut environ = libc::__wasilibc_get_environ(); - - let mut result = Vec::new(); - if !environ.is_null() { - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - } - return Env { iter: result.into_iter() }; - } - - // See src/libstd/sys/pal/unix/os.rs, same as that - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> Option<OsString> { - // environment variables with a nul byte can't be set, so their value is - // always None as well - run_with_cstr(k.as_bytes(), &|k| { - let _guard = env_read_lock(); - let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; - - if v.is_null() { - Ok(None) - } else { - // SAFETY: `v` cannot be mutated while executing this line since we've a read lock - let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); - - Ok(Some(OsStringExt::from_vec(bytes))) - } - }) - .ok() - .flatten() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - run_with_cstr(k.as_bytes(), &|k| { - run_with_cstr(v.as_bytes(), &|v| unsafe { - let _guard = env_write_lock(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) - }) - }) -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - run_with_cstr(n.as_bytes(), &|nbuf| unsafe { - let _guard = env_write_lock(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) - }) -} - #[allow(dead_code)] pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } @@ -294,6 +152,6 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } -fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { +pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } } diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 044dc2e8cd8..f331282d2d7 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -5,16 +5,16 @@ #[cfg(test)] mod tests; +use super::api; #[cfg(not(target_vendor = "uwp"))] use super::api::WinError; -use super::{api, to_u16s}; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::os::windows::ffi::EncodeWide; use crate::os::windows::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::{c, cvt}; -use crate::{fmt, io, ptr, slice}; +use crate::sys::pal::{c, cvt}; +use crate::{fmt, io, ptr}; pub fn errno() -> i32 { api::get_last_error().code as i32 @@ -76,108 +76,6 @@ pub fn error_string(mut errnum: i32) -> String { } } -pub struct Env { - base: *mut c::WCHAR, - iter: EnvIterator, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. -pub struct EnvStrDebug<'a> { - iter: &'a EnvIterator, -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - let iter: EnvIterator = (*iter).clone(); - let mut list = f.debug_list(); - for (a, b) in iter { - list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); - } - list.finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { base: _, iter } = self; - EnvStrDebug { iter } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { base: _, iter } = self; - f.debug_list().entries(iter.clone()).finish() - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self { base: _, iter } = self; - iter.next() - } -} - -#[derive(Clone)] -struct EnvIterator(*mut c::WCHAR); - -impl Iterator for EnvIterator { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self(cur) = self; - loop { - unsafe { - if **cur == 0 { - return None; - } - let p = *cur as *const u16; - let mut len = 0; - while *p.add(len) != 0 { - len += 1; - } - let s = slice::from_raw_parts(p, len); - *cur = cur.add(len + 1); - - // Windows allows environment variables to start with an equals - // symbol (in any other position, this is the separator between - // variable name and value). Since`s` has at least length 1 at - // this point (because the empty string terminates the array of - // environment variables), we can safely slice. - let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { - Some(p) => p, - None => continue, - }; - return Some(( - OsStringExt::from_wide(&s[..pos]), - OsStringExt::from_wide(&s[pos + 1..]), - )); - } - } - } -} - -impl Drop for Env { - fn drop(&mut self) { - unsafe { - c::FreeEnvironmentStringsW(self.base); - } - } -} - -pub fn env() -> Env { - unsafe { - let ch = c::GetEnvironmentStringsW(); - if ch.is_null() { - panic!("failure getting env string from OS: {}", io::Error::last_os_error()); - } - Env { base: ch, iter: EnvIterator(ch) } - } -} - pub struct SplitPaths<'a> { data: EncodeWide<'a>, must_yield: bool, @@ -290,33 +188,6 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop) } -pub fn getenv(k: &OsStr) -> Option<OsString> { - let k = to_u16s(k).ok()?; - super::fill_utf16_buf( - |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, - OsStringExt::from_wide, - ) - .ok() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - // SAFETY: We ensure that k and v are null-terminated wide strings. - unsafe { - let k = to_u16s(k)?; - let v = to_u16s(v)?; - - cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) - } -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - // SAFETY: We ensure that v is a null-terminated wide strings. - unsafe { - let v = to_u16s(n)?; - cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) - } -} - pub fn temp_dir() -> PathBuf { super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap() } diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index 2c87e7d91f2..1b41575358f 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -1,13 +1,11 @@ use super::unsupported; -use crate::collections::HashMap; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::xous::ffi::Error as XousError; use crate::path::{self, PathBuf}; -use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; -use crate::sync::{Mutex, Once}; -use crate::{fmt, io, vec}; +use crate::sync::atomic::{AtomicPtr, Ordering}; +use crate::{fmt, io}; pub(crate) mod params; @@ -136,100 +134,6 @@ pub(crate) fn get_application_parameters() -> Option<params::ApplicationParamete unsafe { params::ApplicationParameters::new_from_ptr(params_address) } } -// ---------- Environment handling ---------- // -static ENV: AtomicUsize = AtomicUsize::new(0); -static ENV_INIT: Once = Once::new(); -type EnvStore = Mutex<HashMap<OsString, OsString>>; - -fn get_env_store() -> &'static EnvStore { - ENV_INIT.call_once(|| { - let env_store = EnvStore::default(); - if let Some(params) = get_application_parameters() { - for param in params { - if let Ok(envs) = params::EnvironmentBlock::try_from(¶m) { - let mut env_store = env_store.lock().unwrap(); - for env in envs { - env_store.insert(env.key.into(), env.value.into()); - } - break; - } - } - } - ENV.store(Box::into_raw(Box::new(env_store)) as _, Ordering::Relaxed) - }); - unsafe { &*core::ptr::with_exposed_provenance::<EnvStore>(ENV.load(Ordering::Relaxed)) } -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -pub fn env() -> Env { - let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> { - map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() - }; - - let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter(); - Env { iter } -} - -pub fn getenv(k: &OsStr) -> Option<OsString> { - get_env_store().lock().unwrap().get(k).cloned() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let (k, v) = (k.to_owned(), v.to_owned()); - get_env_store().lock().unwrap().insert(k, v); - Ok(()) -} - -pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { - get_env_store().lock().unwrap().remove(k); - Ok(()) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index 868b19e33b6..a8ef97ecf67 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -1,10 +1,8 @@ -use super::{WORD_SIZE, abi, unsupported}; +use super::unsupported; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; -use crate::sys::os_str; -use crate::sys_common::FromInner; use crate::{fmt, io}; pub fn errno() -> i32 { @@ -64,64 +62,6 @@ pub fn current_exe() -> io::Result<PathBuf> { unsupported() } -pub struct Env(!); - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.0 - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} - } -} - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} - } -} - -pub fn getenv(varname: &OsStr) -> Option<OsString> { - let varname = varname.as_encoded_bytes(); - let nbytes = - unsafe { abi::sys_getenv(crate::ptr::null_mut(), 0, varname.as_ptr(), varname.len()) }; - if nbytes == usize::MAX { - return None; - } - - let nwords = (nbytes + WORD_SIZE - 1) / WORD_SIZE; - let words = unsafe { abi::sys_alloc_words(nwords) }; - - let nbytes2 = unsafe { abi::sys_getenv(words, nwords, varname.as_ptr(), varname.len()) }; - debug_assert_eq!(nbytes, nbytes2); - - // Convert to OsString. - // - // FIXME: We can probably get rid of the extra copy here if we - // reimplement "os_str" instead of just using the generic unix - // "os_str". - let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) }; - Some(OsString::from_inner(os_str::Buf { inner: u8s.to_vec() })) -} - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 92bb809d90c..478f6583b1f 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -88,7 +88,7 @@ impl Command { // in its own process. Thus the parent drops the lock guard immediately. // The child calls `mem::forget` to leak the lock, which is crucial because // releasing a lock is not async-signal-safe. - let env_lock = sys::os::env_read_lock(); + let env_lock = sys::env::env_read_lock(); let pid = unsafe { self.do_fork()? }; if pid == 0 { @@ -237,7 +237,7 @@ impl Command { // Similar to when forking, we want to ensure that access to // the environment is synchronized, so make sure to grab the // environment lock before we try to exec. - let _lock = sys::os::env_read_lock(); + let _lock = sys::env::env_read_lock(); let Err(e) = self.do_exec(theirs, envp.as_ref()); e @@ -386,13 +386,13 @@ impl Command { impl Drop for Reset { fn drop(&mut self) { unsafe { - *sys::os::environ() = self.0; + *sys::env::environ() = self.0; } } } - _reset = Some(Reset(*sys::os::environ())); - *sys::os::environ() = envp.as_ptr(); + _reset = Some(Reset(*sys::env::environ())); + *sys::env::environ() = envp.as_ptr(); } libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr()); @@ -739,8 +739,8 @@ impl Command { cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; // Make sure we synchronize access to the global `environ` resource - let _env_lock = sys::os::env_read_lock(); - let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); + let _env_lock = sys::env::env_read_lock(); + let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::env::environ() as *const _); #[cfg(not(target_os = "nto"))] let spawn_fn = libc::posix_spawnp; diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs index 5f1727789a1..b92446f0cf6 100644 --- a/library/std/src/sys/process/unix/vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -67,7 +67,7 @@ impl Command { let c_envp = envp .as_ref() .map(|c| c.as_ptr()) - .unwrap_or_else(|| *sys::os::environ() as *const _); + .unwrap_or_else(|| *sys::env::environ() as *const _); let stack_size = crate::cmp::max( crate::env::var_os("RUST_MIN_STACK") .and_then(|s| s.to_str().and_then(|s| s.parse().ok())) @@ -76,7 +76,7 @@ impl Command { ); // ensure that access to the environment is synchronized - let _lock = sys::os::env_read_lock(); + let _lock = sys::env::env_read_lock(); let ret = libc::rtpSpawn( self.get_program_cstr().as_ptr(), diff --git a/library/std/tests/floats/f128.rs b/library/std/tests/floats/f128.rs index 677738bac8f..8b13d6e6558 100644 --- a/library/std/tests/floats/f128.rs +++ b/library/std/tests/floats/f128.rs @@ -1,9 +1,12 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(reliable_f128)] +#![cfg(not(bootstrap))] +#![cfg(target_has_reliable_f128)] use std::f128::consts; use std::num::FpCategory as Fp; -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] use std::ops::Rem; use std::ops::{Add, Div, Mul, Sub}; @@ -19,7 +22,9 @@ const TOL: f128 = 1e-12; /// Tolerances for math that is allowed to be imprecise, usually due to multiple chained /// operations. -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] const TOL_IMPR: f128 = 1e-10; /// Smallest number @@ -66,8 +71,13 @@ fn test_num_f128() { assert_eq!(ten.div(two), ten / two); } +// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support +// the intrinsics. + #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_num_f128_rem() { let ten = 10f128; let two = 2f128; @@ -75,28 +85,36 @@ fn test_num_f128_rem() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_min_nan() { assert_eq!(f128::NAN.min(2.0), 2.0); assert_eq!(2.0f128.min(f128::NAN), 2.0); } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_max_nan() { assert_eq!(f128::NAN.max(2.0), 2.0); assert_eq!(2.0f128.max(f128::NAN), 2.0); } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_minimum() { assert!(f128::NAN.minimum(2.0).is_nan()); assert!(2.0f128.minimum(f128::NAN).is_nan()); } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_maximum() { assert!(f128::NAN.maximum(2.0).is_nan()); assert!(2.0f128.maximum(f128::NAN).is_nan()); @@ -253,7 +271,9 @@ fn test_classify() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_floor() { assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE); assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE); @@ -268,7 +288,9 @@ fn test_floor() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_ceil() { assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE); assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE); @@ -283,7 +305,9 @@ fn test_ceil() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_round() { assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE); assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE); @@ -299,7 +323,9 @@ fn test_round() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_round_ties_even() { assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE); @@ -315,7 +341,9 @@ fn test_round_ties_even() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_trunc() { assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE); assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE); @@ -330,7 +358,9 @@ fn test_trunc() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_fract() { assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE); assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE); @@ -345,7 +375,9 @@ fn test_fract() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_abs() { assert_eq!(f128::INFINITY.abs(), f128::INFINITY); assert_eq!(1f128.abs(), 1f128); @@ -445,7 +477,9 @@ fn test_next_down() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_mul_add() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -462,7 +496,9 @@ fn test_mul_add() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_recip() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -484,7 +520,9 @@ fn test_recip() { // Many math functions allow for less accurate results, so the next tolerance up is used #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_powi() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -499,7 +537,9 @@ fn test_powi() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_powf() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -516,7 +556,9 @@ fn test_powf() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_sqrt_domain() { assert!(f128::NAN.sqrt().is_nan()); assert!(f128::NEG_INFINITY.sqrt().is_nan()); @@ -528,7 +570,9 @@ fn test_sqrt_domain() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_exp() { assert_eq!(1.0, 0.0f128.exp()); assert_approx_eq!(consts::E, 1.0f128.exp(), TOL); @@ -543,7 +587,9 @@ fn test_exp() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_exp2() { assert_eq!(32.0, 5.0f128.exp2()); assert_eq!(1.0, 0.0f128.exp2()); @@ -557,7 +603,9 @@ fn test_exp2() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_ln() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -573,7 +621,9 @@ fn test_ln() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_log() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -592,7 +642,9 @@ fn test_log() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_log2() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -609,7 +661,9 @@ fn test_log2() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_log10() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -659,7 +713,9 @@ fn test_to_radians() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_asinh() { // Lower accuracy results are allowed, use increased tolerances assert_eq!(0.0f128.asinh(), 0.0f128); @@ -690,7 +746,9 @@ fn test_asinh() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_acosh() { assert_eq!(1.0f128.acosh(), 0.0f128); assert!(0.999f128.acosh().is_nan()); @@ -709,7 +767,9 @@ fn test_acosh() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_atanh() { assert_eq!(0.0f128.atanh(), 0.0f128); assert_eq!((-0.0f128).atanh(), -0.0f128); @@ -729,7 +789,9 @@ fn test_atanh() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_gamma() { // precision can differ among platforms assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR); @@ -750,7 +812,9 @@ fn test_gamma() { } #[test] -#[cfg(reliable_f128_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f128_math)] fn test_ln_gamma() { assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); assert_eq!(1.0f128.ln_gamma().1, 1); @@ -781,7 +845,9 @@ fn test_real_consts() { assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE); assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE); - #[cfg(reliable_f128_math)] + #[cfg(not(miri))] + #[cfg(not(bootstrap))] + #[cfg(target_has_reliable_f128_math)] { let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI; let sqrt2: f128 = consts::SQRT_2; diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs index 0fc4df8115a..8b3b344dd46 100644 --- a/library/std/tests/floats/f16.rs +++ b/library/std/tests/floats/f16.rs @@ -1,5 +1,6 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(reliable_f16)] +#![cfg(not(bootstrap))] +#![cfg(target_has_reliable_f16)] use std::f16::consts; use std::num::FpCategory as Fp; @@ -57,29 +58,40 @@ fn test_num_f16() { crate::test_num(10f16, 2f16); } +// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support +// the intrinsics. + #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_min_nan() { assert_eq!(f16::NAN.min(2.0), 2.0); assert_eq!(2.0f16.min(f16::NAN), 2.0); } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_max_nan() { assert_eq!(f16::NAN.max(2.0), 2.0); assert_eq!(2.0f16.max(f16::NAN), 2.0); } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_minimum() { assert!(f16::NAN.minimum(2.0).is_nan()); assert!(2.0f16.minimum(f16::NAN).is_nan()); } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_maximum() { assert!(f16::NAN.maximum(2.0).is_nan()); assert!(2.0f16.maximum(f16::NAN).is_nan()); @@ -236,7 +248,9 @@ fn test_classify() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_floor() { assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0); assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0); @@ -251,7 +265,9 @@ fn test_floor() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_ceil() { assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0); assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0); @@ -266,7 +282,9 @@ fn test_ceil() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_round() { assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0); assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0); @@ -282,7 +300,9 @@ fn test_round() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_round_ties_even() { assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0); assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0); @@ -298,7 +318,9 @@ fn test_round_ties_even() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_trunc() { assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0); assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0); @@ -313,7 +335,9 @@ fn test_trunc() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_fract() { assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0); assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0); @@ -328,7 +352,9 @@ fn test_fract() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_abs() { assert_eq!(f16::INFINITY.abs(), f16::INFINITY); assert_eq!(1f16.abs(), 1f16); @@ -428,7 +454,9 @@ fn test_next_down() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_mul_add() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -445,7 +473,9 @@ fn test_mul_add() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_recip() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -461,7 +491,9 @@ fn test_recip() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_powi() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -476,7 +508,9 @@ fn test_powi() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_powf() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -493,7 +527,9 @@ fn test_powf() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_sqrt_domain() { assert!(f16::NAN.sqrt().is_nan()); assert!(f16::NEG_INFINITY.sqrt().is_nan()); @@ -505,7 +541,9 @@ fn test_sqrt_domain() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_exp() { assert_eq!(1.0, 0.0f16.exp()); assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0); @@ -520,7 +558,9 @@ fn test_exp() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_exp2() { assert_eq!(32.0, 5.0f16.exp2()); assert_eq!(1.0, 0.0f16.exp2()); @@ -534,7 +574,9 @@ fn test_exp2() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_ln() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -550,7 +592,9 @@ fn test_ln() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_log() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -569,7 +613,9 @@ fn test_log() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_log2() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -586,7 +632,9 @@ fn test_log2() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_log10() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -634,7 +682,9 @@ fn test_to_radians() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_asinh() { assert_eq!(0.0f16.asinh(), 0.0f16); assert_eq!((-0.0f16).asinh(), -0.0f16); @@ -659,7 +709,9 @@ fn test_asinh() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_acosh() { assert_eq!(1.0f16.acosh(), 0.0f16); assert!(0.999f16.acosh().is_nan()); @@ -678,7 +730,9 @@ fn test_acosh() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_atanh() { assert_eq!(0.0f16.atanh(), 0.0f16); assert_eq!((-0.0f16).atanh(), -0.0f16); @@ -698,7 +752,9 @@ fn test_atanh() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_gamma() { // precision can differ among platforms assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0); @@ -719,7 +775,9 @@ fn test_gamma() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_ln_gamma() { assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0); assert_eq!(1.0f16.ln_gamma().1, 1); @@ -752,7 +810,9 @@ fn test_real_consts() { assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0); assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0); - #[cfg(reliable_f16_math)] + #[cfg(not(miri))] + #[cfg(not(bootstrap))] + #[cfg(target_has_reliable_f16_math)] { let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI; let sqrt2: f16 = consts::SQRT_2; @@ -813,7 +873,9 @@ fn test_clamp_max_is_nan() { } #[test] -#[cfg(reliable_f16_math)] +#[cfg(not(miri))] +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16_math)] fn test_total_cmp() { use core::cmp::Ordering; diff --git a/library/std/tests/floats/lib.rs b/library/std/tests/floats/lib.rs index de5a3cdbd0f..7884fc9239e 100644 --- a/library/std/tests/floats/lib.rs +++ b/library/std/tests/floats/lib.rs @@ -1,4 +1,6 @@ #![feature(f16, f128, float_algebraic, float_gamma, float_minimum_maximum)] +#![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] +#![cfg_attr(not(bootstrap), expect(internal_features))] // for reliable_f16_f128 use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index ed90ede7936..3c412683b94 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -421,13 +421,13 @@ impl Step for Rustc { builder.install(&rustdoc, &image.join("bin"), FileType::Executable); } + let ra_proc_macro_srv_compiler = + builder.compiler_for(compiler.stage, builder.config.build, compiler.host); + builder.ensure(compile::Rustc::new(ra_proc_macro_srv_compiler, compiler.host)); + if let Some(ra_proc_macro_srv) = builder.ensure_if_default( tool::RustAnalyzerProcMacroSrv { - compiler: builder.compiler_for( - compiler.stage, - builder.config.build, - compiler.host, - ), + compiler: ra_proc_macro_srv_compiler, target: compiler.host, }, builder.kind, @@ -1178,6 +1178,8 @@ impl Step for Cargo { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let cargo = builder.ensure(tool::Cargo { compiler, target }); let src = builder.src.join("src/tools/cargo"); let etc = src.join("src/etc"); @@ -1232,6 +1234,8 @@ impl Step for RustAnalyzer { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let rust_analyzer = builder.ensure(tool::RustAnalyzer { compiler, target }); let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); @@ -1274,6 +1278,8 @@ impl Step for Clippy { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + // Prepare the image directory // We expect clippy to build, because we've exited this step above if tool // state for clippy isn't testing. @@ -1324,9 +1330,12 @@ impl Step for Miri { if !builder.build.unstable_features() { return None; } + let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let miri = builder.ensure(tool::Miri { compiler, target }); let cargomiri = builder.ensure(tool::CargoMiri { compiler, target }); @@ -1463,6 +1472,8 @@ impl Step for Rustfmt { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let rustfmt = builder.ensure(tool::Rustfmt { compiler, target }); let cargofmt = builder.ensure(tool::Cargofmt { compiler, target }); let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); @@ -2328,6 +2339,8 @@ impl Step for LlvmBitcodeLinker { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let llbc_linker = builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] }); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 8e2c6fc52cd..51852099dc3 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -449,6 +449,7 @@ mod dist { use pretty_assertions::assert_eq; use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, first, run_build}; + use crate::Flags; use crate::core::builder::*; fn configure(host: &[&str], target: &[&str]) -> Config { @@ -687,6 +688,37 @@ mod dist { ); } + /// This also serves as an important regression test for <https://github.com/rust-lang/rust/issues/138123> + /// and <https://github.com/rust-lang/rust/issues/138004>. + #[test] + fn dist_all_cross() { + let cmd_args = + &["dist", "--stage", "2", "--dry-run", "--config=/does/not/exist"].map(str::to_owned); + let config_str = r#" + [rust] + channel = "nightly" + + [build] + extended = true + + build = "i686-unknown-haiku" + host = ["i686-unknown-netbsd"] + target = ["i686-unknown-netbsd"] + "#; + let config = Config::parse_inner(Flags::parse(cmd_args), |&_| toml::from_str(config_str)); + let mut cache = run_build(&[], config); + + // Stage 2 `compile::Rustc` should **NEVER** be cached here. + assert_eq!( + first(cache.all::<compile::Rustc>()), + &[ + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_3, stage = 1), + ] + ); + } + #[test] fn build_all() { let build = Build::new(configure( diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 13880ad466a..5600d7b4db5 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -3,12 +3,15 @@ mod tests; use std::collections::BTreeMap; +use anyhow::Context as _; use serde_yaml::Value; use crate::GitHubContext; +use crate::utils::load_env_var; /// Representation of a job loaded from the `src/ci/github-actions/jobs.yml` file. #[derive(serde::Deserialize, Debug, Clone)] +#[serde(deny_unknown_fields)] pub struct Job { /// Name of the job, e.g. mingw-check pub name: String, @@ -26,6 +29,8 @@ pub struct Job { pub free_disk: Option<bool>, /// Documentation link to a resource that could help people debug this CI job. pub doc_url: Option<String>, + /// Whether the job is executed on AWS CodeBuild. + pub codebuild: Option<bool>, } impl Job { @@ -80,7 +85,7 @@ impl JobDatabase { } pub fn load_job_db(db: &str) -> anyhow::Result<JobDatabase> { - let mut db: Value = serde_yaml::from_str(&db)?; + let mut db: Value = serde_yaml::from_str(db)?; // We need to expand merge keys (<<), because serde_yaml can't deal with them // `apply_merge` only applies the merge once, so do it a few times to unwrap nested merges. @@ -107,6 +112,29 @@ struct GithubActionsJob { free_disk: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] doc_url: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + codebuild: Option<bool>, +} + +/// Replace GitHub context variables with environment variables in job configs. +/// Used for codebuild jobs like +/// `codebuild-ubuntu-22-8c-$github.run_id-$github.run_attempt` +fn substitute_github_vars(jobs: Vec<Job>) -> anyhow::Result<Vec<Job>> { + let run_id = load_env_var("GITHUB_RUN_ID")?; + let run_attempt = load_env_var("GITHUB_RUN_ATTEMPT")?; + + let jobs = jobs + .into_iter() + .map(|mut job| { + job.os = job + .os + .replace("$github.run_id", &run_id) + .replace("$github.run_attempt", &run_attempt); + job + }) + .collect(); + + Ok(jobs) } /// Skip CI jobs that are not supposed to be executed on the given `channel`. @@ -177,6 +205,8 @@ fn calculate_jobs( } RunType::AutoJob => (db.auto_jobs.clone(), "auto", &db.envs.auto_env), }; + let jobs = substitute_github_vars(jobs.clone()) + .context("Failed to substitute GitHub context variables in jobs")?; let jobs = skip_jobs(jobs, channel); let jobs = jobs .into_iter() @@ -207,6 +237,7 @@ fn calculate_jobs( continue_on_error: job.continue_on_error, free_disk: job.free_disk, doc_url: job.doc_url, + codebuild: job.codebuild, } }) .collect(); diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile index 420c42bc9d8..3795859f308 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ghcr.io/rust-lang/ubuntu:22.04 COPY scripts/cross-apt-packages.sh /scripts/ RUN sh /scripts/cross-apt-packages.sh diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 00d791eeb6b..36f7df2b069 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -288,7 +288,7 @@ args="$args --privileged" # `LOCAL_USER_ID` (recognized in `src/ci/run.sh`) to ensure that files are all # read/written as the same user as the bare-metal user. if [ -f /.dockerenv ]; then - docker create -v /checkout --name checkout alpine:3.4 /bin/true + docker create -v /checkout --name checkout ghcr.io/rust-lang/alpine:3.4 /bin/true docker cp . checkout:/checkout args="$args --volumes-from checkout" else diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 950a75721c4..88b29d2df56 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -56,6 +56,15 @@ runners: - &job-aarch64-linux-8c os: ubuntu-24.04-arm64-8core-32gb <<: *base-job + + # Codebuild runners are provisioned in + # https://github.com/rust-lang/simpleinfra/blob/b7ddd5e6bec8a93ec30510cdddec02c5666fefe9/terragrunt/accounts/ci-prod/ci-runners/terragrunt.hcl#L2 + - &job-linux-36c-codebuild + free_disk: true + codebuild: true + os: codebuild-ubuntu-22-36c-$github.run_id-$github.run_attempt + <<: *base-job + envs: env-x86_64-apple-tests: &env-x86_64-apple-tests SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact @@ -151,7 +160,7 @@ auto: <<: *job-linux-4c - name: dist-arm-linux - <<: *job-linux-8c + <<: *job-linux-36c-codebuild - name: dist-armhf-linux <<: *job-linux-4c diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh index 055a6ac2211..ad7ee136e9c 100755 --- a/src/ci/scripts/free-disk-space.sh +++ b/src/ci/scripts/free-disk-space.sh @@ -14,6 +14,17 @@ isX86() { fi } +# Check if we're on a GitHub hosted runner. +# In aws codebuild, the variable RUNNER_ENVIRONMENT is "self-hosted". +isGitHubRunner() { + # `:-` means "use the value of RUNNER_ENVIRONMENT if it exists, otherwise use an empty string". + if [[ "${RUNNER_ENVIRONMENT:-}" == "github-hosted" ]]; then + return 0 + else + return 1 + fi +} + # print a line of the specified character printSeparationLine() { for ((i = 0; i < 80; i++)); do @@ -32,7 +43,7 @@ getAvailableSpace() { # make Kb human readable (assume the input is Kb) # REF: https://unix.stackexchange.com/a/44087/60849 formatByteCount() { - numfmt --to=iec-i --suffix=B --padding=7 "$1"'000' + numfmt --to=iec-i --suffix=B --padding=7 "${1}000" } # macro to output saved space @@ -45,6 +56,11 @@ printSavedSpace() { after=$(getAvailableSpace) local saved=$((after - before)) + if [ "$saved" -lt 0 ]; then + echo "::warning::Saved space is negative: $saved. Using '0' as saved space." + saved=0 + fi + echo "" printSeparationLine "*" if [ -n "${title}" ]; then @@ -118,10 +134,14 @@ removeUnusedFilesAndDirs() { # Azure "/opt/az" "/usr/share/az_"* + ) + if [ -n "${AGENT_TOOLSDIRECTORY:-}" ]; then # Environment variable set by GitHub Actions - "$AGENT_TOOLSDIRECTORY" - ) + to_remove+=( + "${AGENT_TOOLSDIRECTORY}" + ) + fi for element in "${to_remove[@]}"; do if [ ! -e "$element" ]; then @@ -155,20 +175,25 @@ cleanPackages() { '^dotnet-.*' '^llvm-.*' '^mongodb-.*' - 'azure-cli' 'firefox' 'libgl1-mesa-dri' 'mono-devel' 'php.*' ) - if isX86; then + if isGitHubRunner; then packages+=( - 'google-chrome-stable' - 'google-cloud-cli' - 'google-cloud-sdk' - 'powershell' + azure-cli ) + + if isX86; then + packages+=( + 'google-chrome-stable' + 'google-cloud-cli' + 'google-cloud-sdk' + 'powershell' + ) + fi fi sudo apt-get -qq remove -y --fix-missing "${packages[@]}" diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 872592d669d..b55ddf6e0e1 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -222,6 +222,28 @@ For more, see [the chapter on documentation tests](write-documentation/documenta See also `--test`. +## `--test-runtool`, `--test-runtool-arg`: program to run tests with; args to pass to it + +A doctest wrapper program can be specified with the `--test-runtool` flag. +Rustdoc will execute that wrapper instead of the doctest executable when +running tests. The first arguments to the wrapper will be any arguments +specified with the `--test-runtool-arg` flag, followed by the path to the +doctest executable to run. + +Using these options looks like this: + +```bash +$ rustdoc src/lib.rs --test-runtool path/to/runner --test-runtool-arg --do-thing --test-runtool-arg --do-other-thing +``` + +For example, if you want to run your doctests under valgrind you might run: + +```bash +$ rustdoc src/lib.rs --test-runtool valgrind +``` + +Another use case would be to run a test inside an emulator, or through a Virtual Machine. + ## `--target`: generate documentation for the specified target triple Using this flag looks like this: diff --git a/src/doc/rustdoc/src/read-documentation/search.md b/src/doc/rustdoc/src/read-documentation/search.md index bace2f5f953..5635f68b1b3 100644 --- a/src/doc/rustdoc/src/read-documentation/search.md +++ b/src/doc/rustdoc/src/read-documentation/search.md @@ -89,7 +89,7 @@ the standard library and functions that are included in the results list: ### Non-functions in type-based search Certain items that are not functions are treated as though they -were a semantically equivelent function. +were a semantically equivalent function. For example, struct fields are treated as though they were getter methods. This means that a search for `CpuidResult -> u32` will show diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index d4ff69a9933..69e5a5adbec 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -631,60 +631,6 @@ The generated output (formatted) will look like this: `--output-format html` has no effect, as the default output is HTML. This is accepted on stable, even though the other options for this flag aren't. -## `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests - - * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245) - -Using this flag looks like this: - -```bash -$ rustdoc src/lib.rs -Z unstable-options --enable-per-target-ignores -``` - -This flag allows you to tag doctests with compiletest style `ignore-foo` filters that prevent -rustdoc from running that test if the target triple string contains foo. For example: - -```rust -///```ignore-foo,ignore-bar -///assert!(2 == 2); -///``` -struct Foo; -``` - -This will not be run when the build target is `super-awesome-foo` or `less-bar-awesome`. -If the flag is not enabled, then rustdoc will consume the filter, but do nothing with it, and -the above example will be run for all targets. -If you want to preserve backwards compatibility for older versions of rustdoc, you can use - -```rust -///```ignore,ignore-foo -///assert!(2 == 2); -///``` -struct Foo; -``` - -In older versions, this will be ignored on all targets, but on newer versions `ignore-gnu` will -override `ignore`. - -## `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it - - * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245) - -Using these options looks like this: - -```bash -$ rustdoc src/lib.rs -Z unstable-options --runtool runner --runtool-arg --do-thing --runtool-arg --do-other-thing -``` - -These options can be used to run the doctest under a program, and also pass arguments to -that program. For example, if you want to run your doctests under valgrind you might run - -```bash -$ rustdoc src/lib.rs -Z unstable-options --runtool valgrind -``` - -Another use case would be to run a test inside an emulator, or through a Virtual Machine. - ## `--with-examples`: include examples of uses of items as documentation * Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791) diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md index b921f677857..077b02d603d 100644 --- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md +++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md @@ -427,6 +427,43 @@ should not be merged with the others. So the previous code should use it: In this case, it means that the line information will not change if you add/remove other doctests. +### Ignoring targets + +Attributes starting with `ignore-` can be used to ignore doctests for specific +targets. For example, `ignore-x86_64` will avoid building doctests when the +target name contains `x86_64`. + +```rust +/// ```ignore-x86_64 +/// assert!(2 == 2); +/// ``` +struct Foo; +``` + +This doctest will not be built for targets such as `x86_64-unknown-linux-gnu`. + +Multiple ignore attributes can be specified to ignore multiple targets: + +```rust +/// ```ignore-x86_64,ignore-windows +/// assert!(2 == 2); +/// ``` +struct Foo; +``` + +If you want to preserve backwards compatibility for older versions of rustdoc, +you can specify both `ignore` and `ignore-`, such as: + +```rust +/// ```ignore,ignore-x86_64 +/// assert!(2 == 2); +/// ``` +struct Foo; +``` + +In older versions, this will be ignored on all targets, but starting with +version CURRENT_RUSTC_VERSION, `ignore-x86_64` will override `ignore`. + ### Custom CSS classes for code blocks ```rust diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md index 4366172fb99..8a38d155e3d 100644 --- a/src/doc/unstable-book/src/library-features/concat-idents.md +++ b/src/doc/unstable-book/src/library-features/concat-idents.md @@ -2,7 +2,10 @@ The tracking issue for this feature is: [#29599] +This feature is deprecated, to be replaced by [`macro_metavar_expr_concat`]. + [#29599]: https://github.com/rust-lang/rust/issues/29599 +[`macro_metavar_expr_concat`]: https://github.com/rust-lang/rust/issues/124225 ------------------------ diff --git a/src/gcc b/src/gcc -Subproject 13cc8243226a9028bb08ab6c5e1c5fe6d533bcd +Subproject 0ea98a1365b81f7488073512c850e8ee951a4af diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 23a2bcd9011..4ef73ff48ed 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -124,13 +124,9 @@ pub(crate) struct Options { /// temporary directory if not set. pub(crate) persist_doctests: Option<PathBuf>, /// Runtool to run doctests with - pub(crate) runtool: Option<String>, + pub(crate) test_runtool: Option<String>, /// Arguments to pass to the runtool - pub(crate) runtool_args: Vec<String>, - /// Whether to allow ignoring doctests on a per-target basis - /// For example, using ignore-foo to ignore running the doctest on any target that - /// contains "foo" as a substring - pub(crate) enable_per_target_ignores: bool, + pub(crate) test_runtool_args: Vec<String>, /// Do not run doctests, compile them if should_test is active. pub(crate) no_run: bool, /// What sources are being mapped. @@ -215,9 +211,8 @@ impl fmt::Debug for Options { .field("persist_doctests", &self.persist_doctests) .field("show_coverage", &self.show_coverage) .field("crate_version", &self.crate_version) - .field("runtool", &self.runtool) - .field("runtool_args", &self.runtool_args) - .field("enable-per-target-ignores", &self.enable_per_target_ignores) + .field("test_runtool", &self.test_runtool) + .field("test_runtool_args", &self.test_runtool_args) .field("run_check", &self.run_check) .field("no_run", &self.no_run) .field("test_builder_wrappers", &self.test_builder_wrappers) @@ -779,9 +774,8 @@ impl Options { let unstable_opts_strs = matches.opt_strs("Z"); let lib_strs = matches.opt_strs("L"); let extern_strs = matches.opt_strs("extern"); - let runtool = matches.opt_str("runtool"); - let runtool_args = matches.opt_strs("runtool-arg"); - let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores"); + let test_runtool = matches.opt_str("test-runtool"); + let test_runtool_args = matches.opt_strs("test-runtool-arg"); let document_private = matches.opt_present("document-private-items"); let document_hidden = matches.opt_present("document-hidden-items"); let run_check = matches.opt_present("check"); @@ -843,9 +837,8 @@ impl Options { crate_version, test_run_directory, persist_doctests, - runtool, - runtool_args, - enable_per_target_ignores, + test_runtool, + test_runtool_args, test_builder, run_check, no_run, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 88eaa52c6de..829a9ca6e7d 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -219,11 +219,9 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); let crate_attrs = tcx.hir_attrs(CRATE_HIR_ID); let opts = scrape_test_config(crate_name, crate_attrs, args_path); - let enable_per_target_ignores = options.enable_per_target_ignores; let hir_collector = HirCollector::new( ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), - enable_per_target_ignores, tcx, ); let tests = hir_collector.collect_crate(); @@ -782,10 +780,10 @@ fn run_test( let mut cmd; let output_file = make_maybe_absolute_path(output_file); - if let Some(tool) = &rustdoc_options.runtool { + if let Some(tool) = &rustdoc_options.test_runtool { let tool = make_maybe_absolute_path(tool.into()); cmd = Command::new(tool); - cmd.args(&rustdoc_options.runtool_args); + cmd.args(&rustdoc_options.test_runtool_args); cmd.arg(&output_file); } else { cmd = Command::new(&output_file); diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index a0d39ce749d..497a8d7c4a7 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -104,13 +104,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { }; let codes = ErrorCodes::from(options.unstable_features.is_nightly_build()); - find_testable_code( - &input_str, - &mut md_collector, - codes, - options.enable_per_target_ignores, - None, - ); + find_testable_code(&input_str, &mut md_collector, codes, None); let mut collector = CreateRunnableDocTests::new(options.clone(), opts); md_collector.tests.into_iter().for_each(|t| collector.add_test(t)); diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index be2dea641d7..43dcfab880b 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -63,19 +63,18 @@ impl DocTestVisitor for RustCollector { pub(super) struct HirCollector<'tcx> { codes: ErrorCodes, tcx: TyCtxt<'tcx>, - enable_per_target_ignores: bool, collector: RustCollector, } impl<'tcx> HirCollector<'tcx> { - pub fn new(codes: ErrorCodes, enable_per_target_ignores: bool, tcx: TyCtxt<'tcx>) -> Self { + pub fn new(codes: ErrorCodes, tcx: TyCtxt<'tcx>) -> Self { let collector = RustCollector { source_map: tcx.sess.psess.clone_source_map(), cur_path: vec![], position: DUMMY_SP, tests: vec![], }; - Self { codes, enable_per_target_ignores, tcx, collector } + Self { codes, tcx, collector } } pub fn collect_crate(mut self) -> Vec<ScrapedDocTest> { @@ -131,7 +130,6 @@ impl HirCollector<'_> { &doc, &mut self.collector, self.codes, - self.enable_per_target_ignores, Some(&crate::html::markdown::ExtraInfo::new(self.tcx, def_id, span)), ); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 44134bda5ea..fc46293e7ea 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -246,7 +246,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { match kind { CodeBlockKind::Fenced(ref lang) => { let parse_result = - LangString::parse_without_check(lang, self.check_error_codes, false); + LangString::parse_without_check(lang, self.check_error_codes); if !parse_result.rust { let added_classes = parse_result.added_classes; let lang_string = if let Some(lang) = parse_result.unknown.first() { @@ -707,17 +707,15 @@ pub(crate) fn find_testable_code<T: doctest::DocTestVisitor>( doc: &str, tests: &mut T, error_codes: ErrorCodes, - enable_per_target_ignores: bool, extra_info: Option<&ExtraInfo<'_>>, ) { - find_codes(doc, tests, error_codes, enable_per_target_ignores, extra_info, false) + find_codes(doc, tests, error_codes, extra_info, false) } pub(crate) fn find_codes<T: doctest::DocTestVisitor>( doc: &str, tests: &mut T, error_codes: ErrorCodes, - enable_per_target_ignores: bool, extra_info: Option<&ExtraInfo<'_>>, include_non_rust: bool, ) { @@ -733,12 +731,7 @@ pub(crate) fn find_codes<T: doctest::DocTestVisitor>( if lang.is_empty() { Default::default() } else { - LangString::parse( - lang, - error_codes, - enable_per_target_ignores, - extra_info, - ) + LangString::parse(lang, error_codes, extra_info) } } CodeBlockKind::Indented => Default::default(), @@ -1162,18 +1155,13 @@ impl Default for LangString { } impl LangString { - fn parse_without_check( - string: &str, - allow_error_code_check: ErrorCodes, - enable_per_target_ignores: bool, - ) -> Self { - Self::parse(string, allow_error_code_check, enable_per_target_ignores, None) + fn parse_without_check(string: &str, allow_error_code_check: ErrorCodes) -> Self { + Self::parse(string, allow_error_code_check, None) } fn parse( string: &str, allow_error_code_check: ErrorCodes, - enable_per_target_ignores: bool, extra: Option<&ExtraInfo<'_>>, ) -> Self { let allow_error_code_check = allow_error_code_check.as_bool(); @@ -1203,10 +1191,8 @@ impl LangString { LangStringToken::LangToken(x) if let Some(ignore) = x.strip_prefix("ignore-") => { - if enable_per_target_ignores { - ignores.push(ignore.to_owned()); - seen_rust_tags = !seen_other_tags; - } + ignores.push(ignore.to_owned()); + seen_rust_tags = !seen_other_tags; } LangStringToken::LangToken("rust") => { data.rust = true; @@ -1968,7 +1954,7 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust let lang_string = if syntax.is_empty() { Default::default() } else { - LangString::parse(syntax, ErrorCodes::Yes, false, Some(extra_info)) + LangString::parse(syntax, ErrorCodes::Yes, Some(extra_info)) }; if !lang_string.rust { continue; diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index bb42b877a2c..784d0c5d21e 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -49,7 +49,7 @@ fn test_unique_id() { fn test_lang_string_parse() { fn t(lg: LangString) { let s = &lg.original; - assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None), lg) + assert_eq!(LangString::parse(s, ErrorCodes::Yes, None), lg) } t(Default::default()); @@ -479,7 +479,7 @@ fn test_markdown_html_escape() { fn test_find_testable_code_line() { fn t(input: &str, expect: &[usize]) { let mut lines = Vec::<usize>::new(); - find_testable_code(input, &mut lines, ErrorCodes::No, false, None); + find_testable_code(input, &mut lines, ErrorCodes::No, None); assert_eq!(lines, expect); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 7e17f09aecd..beaa6497b8c 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2086,6 +2086,7 @@ fn render_impl( .split_summary_and_content() }) .unwrap_or((None, None)); + write!( w, "{}", @@ -2097,24 +2098,19 @@ fn render_impl( use_absolute, aliases, before_dox.as_deref(), + trait_.is_none() && impl_.items.is_empty(), ) )?; if toggled { w.write_str("</summary>")?; } - if before_dox.is_some() { - if trait_.is_none() && impl_.items.is_empty() { - w.write_str( - "<div class=\"item-info\">\ - <div class=\"stab empty-impl\">This impl block contains no items.</div>\ - </div>", - )?; - } - if let Some(after_dox) = after_dox { - write!(w, "<div class=\"docblock\">{after_dox}</div>")?; - } + if before_dox.is_some() + && let Some(after_dox) = after_dox + { + write!(w, "<div class=\"docblock\">{after_dox}</div>")?; } + if !default_impl_items.is_empty() || !impl_items.is_empty() { w.write_str("<div class=\"impl-items\">")?; close_tags.push("</div>"); @@ -2182,6 +2178,7 @@ fn render_impl_summary( // in documentation pages for trait with automatic implementations like "Send" and "Sync". aliases: &[String], doc: Option<&str>, + impl_is_empty: bool, ) -> impl fmt::Display { fmt::from_fn(move |w| { let inner_impl = i.inner_impl(); @@ -2237,6 +2234,13 @@ fn render_impl_summary( } if let Some(doc) = doc { + if impl_is_empty { + w.write_str( + "<div class=\"item-info\">\ + <div class=\"stab empty-impl\">This impl block contains no items.</div>\ + </div>", + )?; + } write!(w, "<div class=\"docblock\">{doc}</div>")?; } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a6dd06b76ea..19ac24a5d6e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2319,7 +2319,10 @@ details.toggle > summary:not(.hideme)::before { doc block while aligning it with the impl block items. */ .implementors-toggle > .docblock, /* We indent trait items as well. */ -#main-content > .methods > :not(.item-info) { +#main-content > .methods > :not(.item-info), +.impl > .item-info, +.impl > .docblock, +.impl + .docblock { margin-left: var(--impl-items-indent); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4fe5e13c3af..44bd96a7e45 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -507,28 +507,20 @@ fn opts() -> Vec<RustcOptGroup> { "", ), opt( - Unstable, - FlagMulti, - "", - "enable-per-target-ignores", - "parse ignore-foo for ignoring doctests on a per-target basis", - "", - ), - opt( - Unstable, + Stable, Opt, "", - "runtool", + "test-runtool", "", "The tool to run tests with when building for a different target than host", ), opt( - Unstable, + Stable, Multi, "", - "runtool-arg", + "test-runtool-arg", "", - "One (of possibly many) arguments to pass to the runtool", + "One argument (of possibly many) to pass to the runtool", ), opt( Unstable, diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 761282bde7c..c9f0baaaa4c 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -212,7 +212,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> { let has_docs = !i.attrs.doc_strings.is_empty(); let mut tests = Tests { found_tests: 0 }; - find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, false, None); + find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, None); let has_doc_example = tests.found_tests != 0; let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap(); diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 70dbb944d4c..8028afea363 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -122,7 +122,7 @@ pub(crate) fn look_for_tests(cx: &DocContext<'_>, dox: &str, item: &Item) { let mut tests = Tests { found_tests: 0 }; - find_testable_code(dox, &mut tests, ErrorCodes::No, false, None); + find_testable_code(dox, &mut tests, ErrorCodes::No, None); if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples() { if should_have_doc_example(cx, item) { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index e0132056d6c..b5bbe70c48c 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -414,13 +414,10 @@ pub struct Config { /// ABI tests. pub minicore_path: Utf8PathBuf, - /// If true, disable the "new" executor, and use the older libtest-based - /// executor to run tests instead. This is a temporary fallback, to make - /// manual comparative testing easier if bugs are found in the new executor. - /// - /// FIXME(Zalathar): Eventually remove this flag and remove the libtest - /// dependency. - pub no_new_executor: bool, + /// If true, run tests with the "new" executor that was written to replace + /// compiletest's dependency on libtest. Eventually this will become the + /// default, and the libtest dependency will be removed. + pub new_executor: bool, } impl Config { diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 0a3888a7d50..3cf13671ef0 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -202,7 +202,7 @@ pub fn parse_config(args: Vec<String>) -> Config { "COMMAND", ) .reqopt("", "minicore-path", "path to minicore aux library", "PATH") - .optflag("N", "no-new-executor", "disables the new test executor, and uses libtest instead") + .optflag("n", "new-executor", "enables the new test executor instead of using libtest") .optopt( "", "debugger", @@ -448,7 +448,7 @@ pub fn parse_config(args: Vec<String>) -> Config { minicore_path: opt_path(matches, "minicore-path"), - no_new_executor: matches.opt_present("no-new-executor"), + new_executor: matches.opt_present("new-executor"), } } @@ -575,10 +575,9 @@ pub fn run_tests(config: Arc<Config>) { // Delegate to the executor to filter and run the big list of test structures // created during test discovery. When the executor decides to run a test, // it will return control to the rest of compiletest by calling `runtest::run`. - let res = if !config.no_new_executor { + let res = if config.new_executor { Ok(executor::run_tests(&config, tests)) } else { - // FIXME(Zalathar): Eventually remove the libtest executor entirely. crate::executor::libtest::execute_tests(&config, tests) }; diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs index 7d9f77f3752..322ef0a6c2a 100644 --- a/src/tools/miri/cargo-miri/src/main.rs +++ b/src/tools/miri/cargo-miri/src/main.rs @@ -53,7 +53,7 @@ fn main() { // with `RustcPhase::Rustdoc`. There we perform a check-build (needed to get the expected // build failures for `compile_fail` doctests) and then store a JSON file with the // information needed to run this test. - // - We also set `--runtool` to ourselves, which ends up in `phase_runner` with + // - We also set `--test-runtool` to ourselves, which ends up in `phase_runner` with // `RunnerPhase::Rustdoc`. There we parse the JSON file written in `phase_rustc` and invoke // the Miri driver for interpretation. diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 71ea07f3463..cb62e12413c 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -666,8 +666,8 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) { if arg == "--extern" { // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. forward_patched_extern_arg(&mut args, &mut cmd); - } else if arg == "--runtool" { - // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. + } else if arg == "--test-runtool" { + // An existing --test-runtool flag indicates cargo is running in cross-target mode, which we don't support. // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; // otherwise, we won't be called as rustdoc at all. show_error!("cross-interpreting doctests is not currently supported by Miri."); @@ -693,8 +693,8 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) { // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); - // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, - // which are disabled by default. We first need to enable them explicitly: + // The `--test-builder` is an unstable rustdoc features, + // which is disabled by default. We first need to enable them explicitly: cmd.arg("-Zunstable-options"); // rustdoc needs to know the right sysroot. @@ -705,7 +705,7 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) { // Make rustdoc call us back. let cargo_miri_path = env::current_exe().expect("current executable path invalid"); cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments - cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument + cmd.arg("--test-runtool").arg(&cargo_miri_path); // invoked with just a single path argument debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); exec(cmd) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 46e045ac769..1ecaf8675c2 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -847e3ee6b0e614937eee4e6d8f61094411eadcc0 +555e1d0386f024a8359645c3217f4b3eae9be042 diff --git a/src/tools/tidy/src/gcc_submodule.rs b/src/tools/tidy/src/gcc_submodule.rs new file mode 100644 index 00000000000..952ebe9e0cf --- /dev/null +++ b/src/tools/tidy/src/gcc_submodule.rs @@ -0,0 +1,47 @@ +//! Tidy check to ensure that the commit SHA of the `src/gcc` submodule is the same as the +//! required GCC version of the GCC codegen backend. + +use std::path::Path; +use std::process::Command; + +pub fn check(root_path: &Path, compiler_path: &Path, bad: &mut bool) { + let cg_gcc_version_path = compiler_path.join("rustc_codegen_gcc/libgccjit.version"); + let cg_gcc_version = std::fs::read_to_string(&cg_gcc_version_path) + .expect(&format!("Cannot read GCC version from {}", cg_gcc_version_path.display())) + .trim() + .to_string(); + + let git_output = Command::new("git") + .current_dir(root_path) + .arg("submodule") + .arg("status") + // --cached asks for the version that is actually committed in the repository, not the one + // that is currently checked out. + .arg("--cached") + .arg("src/gcc") + .output() + .expect("Cannot determine git SHA of the src/gcc checkout"); + + // This can return e.g. + // -e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc + // e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc (master-e607be166673a8de9fc07f6f02c60426e556c5f2.e607be) + // +e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc (master-e607be166673a8de9fc07f6f02c60426e556c5f2.e607be) + let git_output = String::from_utf8_lossy(&git_output.stdout) + .trim() + .split_whitespace() + .next() + .unwrap_or_default() + .to_string(); + + // The SHA can start with + if the submodule is modified or - if it is not checked out. + let gcc_submodule_sha = git_output.trim_start_matches(&['+', '-']); + if gcc_submodule_sha != cg_gcc_version { + *bad = true; + eprintln!( + r#"Commit SHA of the src/gcc submodule (`{gcc_submodule_sha}`) does not match the required GCC version of the GCC codegen backend (`{cg_gcc_version}`). +Make sure to set the src/gcc submodule to commit {cg_gcc_version}. +The GCC codegen backend commit is configured at {}."#, + cg_gcc_version_path.display(), + ); + } +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 66856f5247b..ca45f8bb84b 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -75,6 +75,7 @@ pub mod features; pub mod fluent_alphabetical; pub mod fluent_period; mod fluent_used; +pub mod gcc_submodule; pub(crate) mod iter_header; pub mod known_bug; pub mod mir_opt_tests; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 4078d462f55..48122129b01 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -116,6 +116,7 @@ fn main() { check!(fluent_alphabetical, &compiler_path, bless); check!(fluent_period, &compiler_path); check!(target_policy, &root_path); + check!(gcc_submodule, &root_path, &compiler_path); // Checks that only make sense for the std libs. check!(pal, &library_path); diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index c7be829c215..817001c514b 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -1,4 +1,4 @@ -// Tests behavior of rustdoc `--runtool`. +// Tests behavior of rustdoc `--test-runtool`. use std::path::PathBuf; @@ -11,7 +11,7 @@ fn mkdir(name: &str) -> PathBuf { dir } -// Behavior with --runtool with relative paths and --test-run-directory. +// Behavior with --test-runtool with relative paths and --test-run-directory. fn main() { let run_dir_name = "rundir"; let run_dir = mkdir(run_dir_name); @@ -27,7 +27,7 @@ fn main() { .arg("--test") .arg("--test-run-directory") .arg(run_dir_name) - .arg("--runtool") + .arg("--test-runtool") .arg(&run_tool_binary) .extern_("t", "libt.rlib") .run(); diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout index 3f47623cb03..78ca8c863eb 100644 --- a/tests/run-make/rustdoc-default-output/output-default.stdout +++ b/tests/run-make/rustdoc-default-output/output-default.stdout @@ -138,12 +138,9 @@ Options: --show-coverage calculate percentage of public items with documentation - --enable-per-target-ignores - parse ignore-foo for ignoring doctests on a per-target - basis - --runtool The tool to run tests with when building for a different target than host + --test-runtool The tool to run tests with when building for a different target than host - --runtool-arg One (of possibly many) arguments to pass to the runtool + --test-runtool-arg One argument (of possibly many) to pass to the runtool --test-builder PATH The rustc-like binary to use as the test builder diff --git a/tests/rustdoc-gui/docblock-table-overflow.goml b/tests/rustdoc-gui/docblock-table-overflow.goml index 18e5b4d7f35..e603c3a4d22 100644 --- a/tests/rustdoc-gui/docblock-table-overflow.goml +++ b/tests/rustdoc-gui/docblock-table-overflow.goml @@ -11,7 +11,7 @@ assert-property: (".top-doc .docblock table", {"scrollWidth": "1572"}) // Checking it works on other doc blocks as well... // Logically, the ".docblock" and the "<p>" should have the same scroll width (if we exclude the margin). -assert-property: ("#implementations-list > details .docblock", {"scrollWidth": 816}) +assert-property: ("#implementations-list > details .docblock", {"scrollWidth": 835}) assert-property: ("#implementations-list > details .docblock > p", {"scrollWidth": 835}) // However, since there is overflow in the <table>, its scroll width is bigger. assert-property: ("#implementations-list > details .docblock table", {"scrollWidth": "1572"}) diff --git a/tests/rustdoc-gui/impl-doc-indent.goml b/tests/rustdoc-gui/impl-doc-indent.goml new file mode 100644 index 00000000000..d647fec6d73 --- /dev/null +++ b/tests/rustdoc-gui/impl-doc-indent.goml @@ -0,0 +1,16 @@ +// Checks the impl block docs have the correct indent. +go-to: "file://" + |DOC_PATH| + "/test_docs/impls_indent/struct.Context.html" + +// First we ensure that the impl items are indent (more on the right of the screen) than the +// impl itself. +store-position: ("#impl-Context", {"x": impl_x}) +store-position: ("#impl-Context > .item-info", {"x": impl_item_x}) +assert: |impl_x| < |impl_item_x| + +// And we ensure that all impl items have the same indent. +assert-position: ("#impl-Context > .docblock", {"x": |impl_item_x|}) +assert-position: ("#impl-Context + .docblock", {"x": |impl_item_x|}) + +// Same with the collapsible impl block. +assert-position: ("#impl-Context-1 > .docblock", {"x": |impl_item_x|}) +assert-position: (".implementors-toggle > summary + .docblock", {"x": |impl_item_x|}) diff --git a/tests/rustdoc-gui/item-info-overflow.goml b/tests/rustdoc-gui/item-info-overflow.goml index c325beb6d06..2c4e06e297c 100644 --- a/tests/rustdoc-gui/item-info-overflow.goml +++ b/tests/rustdoc-gui/item-info-overflow.goml @@ -21,7 +21,7 @@ compare-elements-property: ( ) assert-property: ( "#impl-SimpleTrait-for-LongItemInfo2 .item-info", - {"scrollWidth": "916"}, + {"scrollWidth": "935"}, ) // Just to be sure we're comparing the correct "item-info": assert-text: ( diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 31f6b7f09b7..bb0015b8f9c 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -740,3 +740,29 @@ pub mod SidebarSort { impl Sort for Cell<u8> {} impl<'a> Sort for &'a str {} } + +pub mod impls_indent { + pub struct Context; + + /// Working with objects. + /// + /// # Safety + /// + /// Functions that take indices of locals do not check bounds on these indices; + /// the caller must ensure that the indices are less than the number of locals + /// in the current stack frame. + impl Context { + } + + /// Working with objects. + /// + /// # Safety + /// + /// Functions that take indices of locals do not check bounds on these indices; + /// the caller must ensure that the indices are less than the number of locals + /// in the current stack frame. + impl Context { + /// bla + pub fn bar() {} + } +} diff --git a/tests/rustdoc/doctest/auxiliary/doctest-runtool.rs b/tests/rustdoc/doctest/auxiliary/doctest-runtool.rs new file mode 100644 index 00000000000..a21ae0664fe --- /dev/null +++ b/tests/rustdoc/doctest/auxiliary/doctest-runtool.rs @@ -0,0 +1,21 @@ +// For some reason on Windows, the PATH to the libstd dylib doesn't seem to +// carry over to running the runtool. +//@ no-prefer-dynamic + +use std::path::Path; +use std::process::Command; + +fn main() { + let args: Vec<_> = std::env::args().collect(); + eprintln!("{args:#?}"); + assert_eq!(args.len(), 4); + assert_eq!(args[1], "arg1"); + assert_eq!(args[2], "arg2 with space"); + let path = Path::new(&args[3]); + let output = Command::new(path).output().unwrap(); + // Should fail without env var. + assert!(!output.status.success()); + let output = Command::new(path).env("DOCTEST_RUNTOOL_CHECK", "xyz").output().unwrap(); + // Should pass with env var. + assert!(output.status.success()); +} diff --git a/tests/rustdoc/doctest/doctest-runtool.rs b/tests/rustdoc/doctest/doctest-runtool.rs new file mode 100644 index 00000000000..c4fb02e5228 --- /dev/null +++ b/tests/rustdoc/doctest/doctest-runtool.rs @@ -0,0 +1,13 @@ +// Tests that the --test-runtool argument works. + +//@ ignore-cross-compile +//@ aux-bin: doctest-runtool.rs +//@ compile-flags: --test +//@ compile-flags: --test-runtool=auxiliary/bin/doctest-runtool +//@ compile-flags: --test-runtool-arg=arg1 --test-runtool-arg +//@ compile-flags: 'arg2 with space' + +/// ``` +/// assert_eq!(std::env::var("DOCTEST_RUNTOOL_CHECK"), Ok("xyz".to_string())); +/// ``` +pub fn main() {} diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs index c3a3131ee46..6ac9cb9e3a9 100644 --- a/tests/ui/asm/naked-invalid-attr.rs +++ b/tests/ui/asm/naked-invalid-attr.rs @@ -51,3 +51,12 @@ fn main() { #[unsafe(naked)] //~ ERROR should be applied to a function definition || {}; } + +// Check that the path of an attribute without a name is printed correctly (issue #140082) +#[::a] +//~^ ERROR attribute incompatible with `#[unsafe(naked)]` +//~| ERROR failed to resolve: use of unresolved module or unlinked crate `a` +#[unsafe(naked)] +extern "C" fn issue_140082() { + naked_asm!("") +} diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 81d30e6475d..ef389e7d921 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -1,3 +1,9 @@ +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `a` + --> $DIR/naked-invalid-attr.rs:56:5 + | +LL | #[::a] + | ^ use of unresolved module or unlinked crate `a` + error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:13:1 | @@ -27,6 +33,15 @@ LL | #[unsafe(naked)] LL | || {}; | ----- not a function definition +error[E0736]: attribute incompatible with `#[unsafe(naked)]` + --> $DIR/naked-invalid-attr.rs:56:1 + | +LL | #[::a] + | ^^^^^^ the `{{root}}::a` attribute is incompatible with `#[unsafe(naked)]` +... +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here + error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:22:5 | @@ -49,5 +64,7 @@ error: attribute should be applied to a function definition LL | #![unsafe(naked)] | ^^^^^^^^^^^^^^^^^ cannot be applied to crates -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors +Some errors have detailed explanations: E0433, E0736. +For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/cfg/disallowed-cli-cfgs.reliable_f128_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f128_.stderr new file mode 100644 index 00000000000..1b6e0506001 --- /dev/null +++ b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f128_.stderr @@ -0,0 +1,8 @@ +error: unexpected `--cfg target_has_reliable_f128` flag + | + = note: config `target_has_reliable_f128` is only supposed to be controlled by `--target` + = note: manually setting a built-in cfg can and does create incoherent behaviors + = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/cfg/disallowed-cli-cfgs.reliable_f128_math_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f128_math_.stderr new file mode 100644 index 00000000000..86e7342b8fc --- /dev/null +++ b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f128_math_.stderr @@ -0,0 +1,8 @@ +error: unexpected `--cfg target_has_reliable_f128_math` flag + | + = note: config `target_has_reliable_f128_math` is only supposed to be controlled by `--target` + = note: manually setting a built-in cfg can and does create incoherent behaviors + = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/cfg/disallowed-cli-cfgs.reliable_f16_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f16_.stderr new file mode 100644 index 00000000000..cf5000ecf27 --- /dev/null +++ b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f16_.stderr @@ -0,0 +1,8 @@ +error: unexpected `--cfg target_has_reliable_f16` flag + | + = note: config `target_has_reliable_f16` is only supposed to be controlled by `--target` + = note: manually setting a built-in cfg can and does create incoherent behaviors + = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/cfg/disallowed-cli-cfgs.reliable_f16_math_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f16_math_.stderr new file mode 100644 index 00000000000..079e5627e4c --- /dev/null +++ b/tests/ui/cfg/disallowed-cli-cfgs.reliable_f16_math_.stderr @@ -0,0 +1,8 @@ +error: unexpected `--cfg target_has_reliable_f16_math` flag + | + = note: config `target_has_reliable_f16_math` is only supposed to be controlled by `--target` + = note: manually setting a built-in cfg can and does create incoherent behaviors + = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs index e9661abf3ab..f7f9d2b5cd7 100644 --- a/tests/ui/cfg/disallowed-cli-cfgs.rs +++ b/tests/ui/cfg/disallowed-cli-cfgs.rs @@ -8,6 +8,7 @@ //@ revisions: target_thread_local_ relocation_model_ //@ revisions: fmt_debug_ //@ revisions: emscripten_wasm_eh_ +//@ revisions: reliable_f16_ reliable_f16_math_ reliable_f128_ reliable_f128_math_ //@ [overflow_checks_]compile-flags: --cfg overflow_checks //@ [debug_assertions_]compile-flags: --cfg debug_assertions @@ -35,6 +36,10 @@ //@ [relocation_model_]compile-flags: --cfg relocation_model="a" //@ [fmt_debug_]compile-flags: --cfg fmt_debug="shallow" //@ [emscripten_wasm_eh_]compile-flags: --cfg emscripten_wasm_eh +//@ [reliable_f16_]compile-flags: --cfg target_has_reliable_f16 +//@ [reliable_f16_math_]compile-flags: --cfg target_has_reliable_f16_math +//@ [reliable_f128_]compile-flags: --cfg target_has_reliable_f128 +//@ [reliable_f128_math_]compile-flags: --cfg target_has_reliable_f128_math fn main() {} diff --git a/tests/ui/coercion/issue-73886.stderr b/tests/ui/coercion/issue-73886.stderr index a6f8ba65ab5..0d4c90017cf 100644 --- a/tests/ui/coercion/issue-73886.stderr +++ b/tests/ui/coercion/issue-73886.stderr @@ -8,9 +8,14 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/issue-73886.rs:4:13 | LL | let _ = 7u32 as Option<_>; - | ^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `Option<_>::from(7u32)` + | ^^^^^^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object +help: consider using the `From` trait instead + | +LL - let _ = 7u32 as Option<_>; +LL + let _ = Option::<_>::from(7u32); + | error: aborting due to 2 previous errors diff --git a/tests/ui/coercion/non-primitive-cast-135412.fixed b/tests/ui/coercion/non-primitive-cast-135412.fixed new file mode 100644 index 00000000000..5cadc9368d5 --- /dev/null +++ b/tests/ui/coercion/non-primitive-cast-135412.fixed @@ -0,0 +1,10 @@ +//@ run-rustfix + +use std::sync::Arc; + +fn main() { + let _ = Option::<_>::from(7u32); + //~^ ERROR non-primitive cast: `u32` as `Option<_>` + let _ = Arc::<str>::from("String"); + //~^ ERROR non-primitive cast: `&'static str` as `Arc<str>` +} diff --git a/tests/ui/coercion/non-primitive-cast-135412.rs b/tests/ui/coercion/non-primitive-cast-135412.rs new file mode 100644 index 00000000000..67a3ef340d2 --- /dev/null +++ b/tests/ui/coercion/non-primitive-cast-135412.rs @@ -0,0 +1,10 @@ +//@ run-rustfix + +use std::sync::Arc; + +fn main() { + let _ = 7u32 as Option<_>; + //~^ ERROR non-primitive cast: `u32` as `Option<_>` + let _ = "String" as Arc<str>; + //~^ ERROR non-primitive cast: `&'static str` as `Arc<str>` +} diff --git a/tests/ui/coercion/non-primitive-cast-135412.stderr b/tests/ui/coercion/non-primitive-cast-135412.stderr new file mode 100644 index 00000000000..7e5861f83e9 --- /dev/null +++ b/tests/ui/coercion/non-primitive-cast-135412.stderr @@ -0,0 +1,29 @@ +error[E0605]: non-primitive cast: `u32` as `Option<_>` + --> $DIR/non-primitive-cast-135412.rs:6:13 + | +LL | let _ = 7u32 as Option<_>; + | ^^^^^^^^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object +help: consider using the `From` trait instead + | +LL - let _ = 7u32 as Option<_>; +LL + let _ = Option::<_>::from(7u32); + | + +error[E0605]: non-primitive cast: `&'static str` as `Arc<str>` + --> $DIR/non-primitive-cast-135412.rs:8:13 + | +LL | let _ = "String" as Arc<str>; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object +help: consider using the `From` trait instead + | +LL - let _ = "String" as Arc<str>; +LL + let _ = Arc::<str>::from("String"); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0605`. diff --git a/tests/ui/copy-a-resource.rs b/tests/ui/copy-a-resource.rs deleted file mode 100644 index 55f2dd4ee6d..00000000000 --- a/tests/ui/copy-a-resource.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[derive(Debug)] -struct Foo { - i: isize, -} - -impl Drop for Foo { - fn drop(&mut self) {} -} - -fn foo(i:isize) -> Foo { - Foo { - i: i - } -} - -fn main() { - let x = foo(10); - let _y = x.clone(); - //~^ ERROR no method named `clone` found - println!("{:?}", x); -} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 6170250992c..8178f54b2aa 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -18,13 +18,16 @@ LL | where LL | T: AsExpression<Self::SqlType>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` -error[E0271]: type mismatch resolving `Integer == Text` +error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied --> $DIR/as_expression.rs:56:5 | LL | SelectInt.check("bar"); - | ^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str` + | + = help: the trait `AsExpression<Integer>` is not implemented for `&str` + but trait `AsExpression<Text>` is implemented for it + = help: for that trait implementation, expected `Text`, found `Integer` error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 673adb82870..86f39e43484 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -55,5 +55,5 @@ impl<T> Foo for T where T: Expression {} fn main() { SelectInt.check("bar"); //~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied - //[next]~| ERROR type mismatch + //[next]~| ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied } diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-has-reliable-f16-f128.rs b/tests/ui/feature-gates/feature-gate-cfg-target-has-reliable-f16-f128.rs new file mode 100644 index 00000000000..f1b0e3b01a4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-target-has-reliable-f16-f128.rs @@ -0,0 +1,12 @@ +//@ compile-flags: --check-cfg=cfg(target_has_reliable_f16,target_has_reliable_f16_math,target_has_reliable_f128,target_has_reliable_f128_math) + +fn main() { + cfg!(target_has_reliable_f16); + //~^ ERROR `cfg(target_has_reliable_f16)` is experimental and subject to change + cfg!(target_has_reliable_f16_math); + //~^ ERROR `cfg(target_has_reliable_f16_math)` is experimental and subject to change + cfg!(target_has_reliable_f128); + //~^ ERROR `cfg(target_has_reliable_f128)` is experimental and subject to change + cfg!(target_has_reliable_f128_math); + //~^ ERROR `cfg(target_has_reliable_f128_math)` is experimental and subject to change +} diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-has-reliable-f16-f128.stderr b/tests/ui/feature-gates/feature-gate-cfg-target-has-reliable-f16-f128.stderr new file mode 100644 index 00000000000..9b90d18699e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-target-has-reliable-f16-f128.stderr @@ -0,0 +1,39 @@ +error[E0658]: `cfg(target_has_reliable_f16)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-reliable-f16-f128.rs:4:10 + | +LL | cfg!(target_has_reliable_f16); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(cfg_target_has_reliable_f16_f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(target_has_reliable_f16_math)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-reliable-f16-f128.rs:6:10 + | +LL | cfg!(target_has_reliable_f16_math); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(cfg_target_has_reliable_f16_f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(target_has_reliable_f128)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-reliable-f16-f128.rs:8:10 + | +LL | cfg!(target_has_reliable_f128); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(cfg_target_has_reliable_f16_f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(target_has_reliable_f128_math)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-reliable-f16-f128.rs:10:10 + | +LL | cfg!(target_has_reliable_f128_math); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(cfg_target_has_reliable_f16_f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.rs b/tests/ui/feature-gates/feature-gate-concat_idents.rs index 68caf3d71e9..4fc3b691597 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents.rs +++ b/tests/ui/feature-gates/feature-gate-concat_idents.rs @@ -1,3 +1,5 @@ +#![expect(deprecated)] // concat_idents is deprecated + const XY_1: i32 = 10; fn main() { diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.stderr b/tests/ui/feature-gates/feature-gate-concat_idents.stderr index d0f4fe62d04..6399424eecd 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents.stderr +++ b/tests/ui/feature-gates/feature-gate-concat_idents.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents.rs:5:13 + --> $DIR/feature-gate-concat_idents.rs:7:13 | LL | let a = concat_idents!(X, Y_1); | ^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let a = concat_idents!(X, Y_1); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents.rs:6:13 + --> $DIR/feature-gate-concat_idents.rs:8:13 | LL | let b = concat_idents!(X, Y_2); | ^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.rs b/tests/ui/feature-gates/feature-gate-concat_idents2.rs index 9660ffeafa5..bc2b4f7cddf 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents2.rs +++ b/tests/ui/feature-gates/feature-gate-concat_idents2.rs @@ -1,3 +1,5 @@ +#![expect(deprecated)] // concat_idents is deprecated + fn main() { concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough //~| ERROR cannot find value `ab` in this scope diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr b/tests/ui/feature-gates/feature-gate-concat_idents2.stderr index b42a1d999e4..a770c1a348b 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr +++ b/tests/ui/feature-gates/feature-gate-concat_idents2.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents2.rs:2:5 + --> $DIR/feature-gate-concat_idents2.rs:4:5 | LL | concat_idents!(a, b); | ^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | concat_idents!(a, b); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0425]: cannot find value `ab` in this scope - --> $DIR/feature-gate-concat_idents2.rs:2:5 + --> $DIR/feature-gate-concat_idents2.rs:4:5 | LL | concat_idents!(a, b); | ^^^^^^^^^^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.rs b/tests/ui/feature-gates/feature-gate-concat_idents3.rs index 81710fd9fb0..d4a0d2e6bb0 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents3.rs +++ b/tests/ui/feature-gates/feature-gate-concat_idents3.rs @@ -1,3 +1,5 @@ +#![expect(deprecated)] // concat_idents is deprecated + const XY_1: i32 = 10; fn main() { diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr b/tests/ui/feature-gates/feature-gate-concat_idents3.stderr index b186601d0ed..7d929322bc0 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr +++ b/tests/ui/feature-gates/feature-gate-concat_idents3.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents3.rs:5:20 + --> $DIR/feature-gate-concat_idents3.rs:7:20 | LL | assert_eq!(10, concat_idents!(X, Y_1)); | ^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | assert_eq!(10, concat_idents!(X, Y_1)); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents3.rs:6:20 + --> $DIR/feature-gate-concat_idents3.rs:8:20 | LL | assert_eq!(20, concat_idents!(X, Y_2)); | ^^^^^^^^^^^^^ diff --git a/tests/ui/float/target-has-reliable-nightly-float.rs b/tests/ui/float/target-has-reliable-nightly-float.rs new file mode 100644 index 00000000000..ad8600fc635 --- /dev/null +++ b/tests/ui/float/target-has-reliable-nightly-float.rs @@ -0,0 +1,31 @@ +//@ run-pass +//@ compile-flags: --check-cfg=cfg(target_has_reliable_f16,target_has_reliable_f16_math,target_has_reliable_f128,target_has_reliable_f128_math) +// Verify that the feature gates and config work and are registered as known config +// options. + +#![deny(unexpected_cfgs)] +#![feature(cfg_target_has_reliable_f16_f128)] + +#[cfg(target_has_reliable_f16)] +pub fn has_f16() {} + +#[cfg(target_has_reliable_f16_math)] +pub fn has_f16_math() {} + +#[cfg(target_has_reliable_f128 )] +pub fn has_f128() {} + +#[cfg(target_has_reliable_f128_math)] +pub fn has_f128_math() {} + +fn main() { + if cfg!(target_arch = "aarch64") && cfg!(target_os = "linux") { + // Aarch64+Linux is one target that has support for all features, so use it to spot + // check that the compiler does indeed enable these gates. + + assert!(cfg!(target_has_reliable_f16)); + assert!(cfg!(target_has_reliable_f16_math)); + assert!(cfg!(target_has_reliable_f128)); + assert!(cfg!(target_has_reliable_f128_math)); + } +} diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.rs new file mode 100644 index 00000000000..1ee3bfd1233 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.rs @@ -0,0 +1,23 @@ +trait ServerFn { + type Output; + fn run_body() -> impl Sized; +} +struct MyServerFn {} + +macro_rules! f { + () => { + impl ServerFn for MyServerFn { + type Output = (); + fn run_body() -> impl Sized {} + } + }; +} + +f! {} + +fn problem<T: ServerFn<Output = i64>>(_: T) {} + +fn main() { + problem(MyServerFn {}); + //~^ ERROR type mismatch resolving `<MyServerFn as ServerFn>::Output == i64` +} diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.stderr new file mode 100644 index 00000000000..b4c022d3521 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.stderr @@ -0,0 +1,26 @@ +error[E0271]: type mismatch resolving `<MyServerFn as ServerFn>::Output == i64` + --> $DIR/dont-probe-missing-item-name-4.rs:21:13 + | +LL | problem(MyServerFn {}); + | ------- ^^^^^^^^^^^^^ type mismatch resolving `<MyServerFn as ServerFn>::Output == i64` + | | + | required by a bound introduced by this call + | +note: expected this to be `i64` + --> $DIR/dont-probe-missing-item-name-4.rs:10:27 + | +LL | type Output = (); + | ^^ +... +LL | f! {} + | ----- in this macro invocation +note: required by a bound in `problem` + --> $DIR/dont-probe-missing-item-name-4.rs:18:24 + | +LL | fn problem<T: ServerFn<Output = i64>>(_: T) {} + | ^^^^^^^^^^^^ required by this bound in `problem` + = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/issues/issue-32950.rs b/tests/ui/issues/issue-32950.rs index 27d68a11c1f..b51ac296776 100644 --- a/tests/ui/issues/issue-32950.rs +++ b/tests/ui/issues/issue-32950.rs @@ -1,4 +1,5 @@ #![feature(concat_idents)] +#![expect(deprecated)] // concat_idents is deprecated #[derive(Debug)] struct Baz<T>( diff --git a/tests/ui/issues/issue-32950.stderr b/tests/ui/issues/issue-32950.stderr index 3cdf35af1d8..38a82542f89 100644 --- a/tests/ui/issues/issue-32950.stderr +++ b/tests/ui/issues/issue-32950.stderr @@ -1,11 +1,11 @@ error: `derive` cannot be used on items with type macros - --> $DIR/issue-32950.rs:5:5 + --> $DIR/issue-32950.rs:6:5 | LL | concat_idents!(Foo, Bar) | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0412]: cannot find type `FooBar` in this scope - --> $DIR/issue-32950.rs:5:5 + --> $DIR/issue-32950.rs:6:5 | LL | concat_idents!(Foo, Bar) | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/issues/issue-50403.rs b/tests/ui/issues/issue-50403.rs index ab22aff26d9..f14958afc34 100644 --- a/tests/ui/issues/issue-50403.rs +++ b/tests/ui/issues/issue-50403.rs @@ -1,4 +1,5 @@ #![feature(concat_idents)] +#![expect(deprecated)] // concat_idents is deprecated fn main() { let x = concat_idents!(); //~ ERROR `concat_idents!()` takes 1 or more arguments diff --git a/tests/ui/issues/issue-50403.stderr b/tests/ui/issues/issue-50403.stderr index 193d815d519..e7dd05bb018 100644 --- a/tests/ui/issues/issue-50403.stderr +++ b/tests/ui/issues/issue-50403.stderr @@ -1,5 +1,5 @@ error: `concat_idents!()` takes 1 or more arguments - --> $DIR/issue-50403.rs:4:13 + --> $DIR/issue-50403.rs:5:13 | LL | let x = concat_idents!(); | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs index 79beffbe986..091d64ea5d9 100644 --- a/tests/ui/macros/macros-nonfatal-errors.rs +++ b/tests/ui/macros/macros-nonfatal-errors.rs @@ -5,6 +5,7 @@ #![feature(trace_macros, concat_idents)] #![feature(stmt_expr_attributes)] +#![expect(deprecated)] // concat_idents is deprecated use std::arch::asm; diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr index 44194b506a4..2f990cb24e2 100644 --- a/tests/ui/macros/macros-nonfatal-errors.stderr +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -1,5 +1,5 @@ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:13:5 + --> $DIR/macros-nonfatal-errors.rs:14:5 | LL | #[default] | ^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[default] = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:18:36 + --> $DIR/macros-nonfatal-errors.rs:19:36 | LL | struct DefaultInnerAttrTupleStruct(#[default] ()); | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | struct DefaultInnerAttrTupleStruct(#[default] ()); = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:22:1 + --> $DIR/macros-nonfatal-errors.rs:23:1 | LL | #[default] | ^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | #[default] = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:26:1 + --> $DIR/macros-nonfatal-errors.rs:27:1 | LL | #[default] | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | #[default] = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:36:11 + --> $DIR/macros-nonfatal-errors.rs:37:11 | LL | Foo = #[default] 0, | ^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | Foo = #[default] 0, = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:37:14 + --> $DIR/macros-nonfatal-errors.rs:38:14 | LL | Bar([u8; #[default] 1]), | ^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | Bar([u8; #[default] 1]), = help: consider a manual implementation of `Default` error[E0665]: `#[derive(Default)]` on enum with no `#[default]` - --> $DIR/macros-nonfatal-errors.rs:42:10 + --> $DIR/macros-nonfatal-errors.rs:43:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -67,7 +67,7 @@ LL | #[default] Bar, | ++++++++++ error[E0665]: `#[derive(Default)]` on enum with no `#[default]` - --> $DIR/macros-nonfatal-errors.rs:48:10 + --> $DIR/macros-nonfatal-errors.rs:49:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -78,7 +78,7 @@ LL | | } | |_- this enum needs a unit variant marked with `#[default]` error: multiple declared defaults - --> $DIR/macros-nonfatal-errors.rs:54:10 + --> $DIR/macros-nonfatal-errors.rs:55:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -95,7 +95,7 @@ LL | Baz, = note: only one variant can be default error: `#[default]` attribute does not accept a value - --> $DIR/macros-nonfatal-errors.rs:66:5 + --> $DIR/macros-nonfatal-errors.rs:67:5 | LL | #[default = 1] | ^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | #[default = 1] = help: try using `#[default]` error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:74:5 + --> $DIR/macros-nonfatal-errors.rs:75:5 | LL | #[default] | ---------- `#[default]` used here @@ -114,13 +114,13 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing this - --> $DIR/macros-nonfatal-errors.rs:73:5 + --> $DIR/macros-nonfatal-errors.rs:74:5 | LL | #[default] | ^^^^^^^^^^ error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:84:5 + --> $DIR/macros-nonfatal-errors.rs:85:5 | LL | #[default] | ---------- `#[default]` used here @@ -132,7 +132,7 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing these - --> $DIR/macros-nonfatal-errors.rs:81:5 + --> $DIR/macros-nonfatal-errors.rs:82:5 | LL | #[default] | ^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | #[default] | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:91:5 + --> $DIR/macros-nonfatal-errors.rs:92:5 | LL | Foo {}, | ^^^ @@ -150,7 +150,7 @@ LL | Foo {}, = help: consider a manual implementation of `Default` error: default variant must be exhaustive - --> $DIR/macros-nonfatal-errors.rs:99:5 + --> $DIR/macros-nonfatal-errors.rs:100:5 | LL | #[non_exhaustive] | ----------------- declared `#[non_exhaustive]` here @@ -160,37 +160,37 @@ LL | Foo, = help: consider a manual implementation of `Default` error: asm template must be a string literal - --> $DIR/macros-nonfatal-errors.rs:104:10 + --> $DIR/macros-nonfatal-errors.rs:105:10 | LL | asm!(invalid); | ^^^^^^^ error: `concat_idents!()` requires ident args - --> $DIR/macros-nonfatal-errors.rs:107:5 + --> $DIR/macros-nonfatal-errors.rs:108:5 | LL | concat_idents!("not", "idents"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:109:17 + --> $DIR/macros-nonfatal-errors.rs:110:17 | LL | option_env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:110:10 + --> $DIR/macros-nonfatal-errors.rs:111:10 | LL | env!(invalid); | ^^^^^^^ error: `env!()` takes 1 or 2 arguments - --> $DIR/macros-nonfatal-errors.rs:111:5 + --> $DIR/macros-nonfatal-errors.rs:112:5 | LL | env!(foo, abr, baz); | ^^^^^^^^^^^^^^^^^^^ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time - --> $DIR/macros-nonfatal-errors.rs:112:5 + --> $DIR/macros-nonfatal-errors.rs:113:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); = help: use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time error: format argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:114:13 + --> $DIR/macros-nonfatal-errors.rs:115:13 | LL | format!(invalid); | ^^^^^^^ @@ -209,43 +209,43 @@ LL | format!("{}", invalid); | +++++ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:116:14 + --> $DIR/macros-nonfatal-errors.rs:117:14 | LL | include!(invalid); | ^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:118:18 + --> $DIR/macros-nonfatal-errors.rs:119:18 | LL | include_str!(invalid); | ^^^^^^^ error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG - --> $DIR/macros-nonfatal-errors.rs:119:5 + --> $DIR/macros-nonfatal-errors.rs:120:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:120:20 + --> $DIR/macros-nonfatal-errors.rs:121:20 | LL | include_bytes!(invalid); | ^^^^^^^ error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG - --> $DIR/macros-nonfatal-errors.rs:121:5 + --> $DIR/macros-nonfatal-errors.rs:122:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` - --> $DIR/macros-nonfatal-errors.rs:123:5 + --> $DIR/macros-nonfatal-errors.rs:124:5 | LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^ error: default variant must be exhaustive - --> $DIR/macros-nonfatal-errors.rs:133:9 + --> $DIR/macros-nonfatal-errors.rs:134:9 | LL | #[non_exhaustive] | ----------------- declared `#[non_exhaustive]` here @@ -255,7 +255,7 @@ LL | Foo, = help: consider a manual implementation of `Default` error: cannot find macro `llvm_asm` in this scope - --> $DIR/macros-nonfatal-errors.rs:105:5 + --> $DIR/macros-nonfatal-errors.rs:106:5 | LL | llvm_asm!(invalid); | ^^^^^^^^ diff --git a/tests/ui/fail-simple.rs b/tests/ui/macros/no-matching-rule.rs index 55e547ee72b..55e547ee72b 100644 --- a/tests/ui/fail-simple.rs +++ b/tests/ui/macros/no-matching-rule.rs diff --git a/tests/ui/fail-simple.stderr b/tests/ui/macros/no-matching-rule.stderr index 50c350b3ef5..a6312a843f3 100644 --- a/tests/ui/fail-simple.stderr +++ b/tests/ui/macros/no-matching-rule.stderr @@ -1,5 +1,5 @@ error: no rules expected `@` - --> $DIR/fail-simple.rs:2:12 + --> $DIR/no-matching-rule.rs:2:12 | LL | panic!(@); | ^ no rules expected this token in macro call diff --git a/tests/ui/methods/clone-missing.rs b/tests/ui/methods/clone-missing.rs new file mode 100644 index 00000000000..f2e4ad268c6 --- /dev/null +++ b/tests/ui/methods/clone-missing.rs @@ -0,0 +1,19 @@ +// This test checks that calling `.clone()` on a type that does not implement the `Clone` trait +// results in a compilation error. The `Foo` struct does not derive or implement `Clone`, +// so attempting to clone it should fail. + +struct Foo { + i: isize, +} + +fn foo(i:isize) -> Foo { + Foo { + i: i + } +} + +fn main() { + let x = foo(10); + let _y = x.clone(); + //~^ ERROR no method named `clone` found +} diff --git a/tests/ui/copy-a-resource.stderr b/tests/ui/methods/clone-missing.stderr index ff1e28bf961..4ab1aae4934 100644 --- a/tests/ui/copy-a-resource.stderr +++ b/tests/ui/methods/clone-missing.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `clone` found for struct `Foo` in the current scope - --> $DIR/copy-a-resource.rs:18:16 + --> $DIR/clone-missing.rs:17:16 | LL | struct Foo { | ---------- method `clone` not found for this struct diff --git a/tests/ui/modules/mod-pub-access.rs b/tests/ui/modules/mod-pub-access.rs new file mode 100644 index 00000000000..c07e7a2ff30 --- /dev/null +++ b/tests/ui/modules/mod-pub-access.rs @@ -0,0 +1,11 @@ +//@ run-pass +// This is a name resolution smoke test that ensures paths with more than one +// segment (e.g., `foo::bar`) resolve correctly. +// It also serves as a basic visibility test — confirming that a `pub` item +// inside a private module can still be accessed from outside that module. + +mod foo { + pub fn bar(_offset: usize) {} +} + +fn main() { foo::bar(0); } diff --git a/tests/ui/path.rs b/tests/ui/path.rs deleted file mode 100644 index bd7b99ac01a..00000000000 --- a/tests/ui/path.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -mod foo { - pub fn bar(_offset: usize) { } -} - -pub fn main() { foo::bar(0); } diff --git a/tests/ui/capture1.rs b/tests/ui/resolve/fn-item-cant-capture-dynamic-env.rs index 4f8c04e3fa9..4f8c04e3fa9 100644 --- a/tests/ui/capture1.rs +++ b/tests/ui/resolve/fn-item-cant-capture-dynamic-env.rs diff --git a/tests/ui/capture1.stderr b/tests/ui/resolve/fn-item-cant-capture-dynamic-env.stderr index 8027430de52..6b3e8792011 100644 --- a/tests/ui/capture1.stderr +++ b/tests/ui/resolve/fn-item-cant-capture-dynamic-env.stderr @@ -1,5 +1,5 @@ error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/capture1.rs:3:32 + --> $DIR/fn-item-cant-capture-dynamic-env.rs:3:32 | LL | fn foo() -> isize { return bar; } | ^^^ diff --git a/tests/ui/simd/intrinsic/generic-comparison-pass.rs b/tests/ui/simd/intrinsic/generic-comparison-pass.rs index 2ee164cdfd8..50a05eecb03 100644 --- a/tests/ui/simd/intrinsic/generic-comparison-pass.rs +++ b/tests/ui/simd/intrinsic/generic-comparison-pass.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(repr_simd, core_intrinsics, concat_idents)] +#![feature(repr_simd, core_intrinsics, macro_metavar_expr_concat)] #![allow(non_camel_case_types)] use std::intrinsics::simd::{simd_eq, simd_ge, simd_gt, simd_le, simd_lt, simd_ne}; @@ -19,7 +19,7 @@ macro_rules! cmp { ($method: ident($lhs: expr, $rhs: expr)) => {{ let lhs = $lhs; let rhs = $rhs; - let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); + let e: u32x4 = ${concat(simd_, $method)}($lhs, $rhs); // assume the scalar version is correct/the behaviour we want. assert!((e.0[0] != 0) == lhs.0[0].$method(&rhs.0[0])); assert!((e.0[1] != 0) == lhs.0[1].$method(&rhs.0[1])); diff --git a/tests/ui/syntax-extension-minor.rs b/tests/ui/syntax-extension-minor.rs index cdd572b50fc..826990a89a5 100644 --- a/tests/ui/syntax-extension-minor.rs +++ b/tests/ui/syntax-extension-minor.rs @@ -1,6 +1,7 @@ //@ run-pass #![feature(concat_idents)] +#![expect(deprecated)] // concat_idents is deprecated pub fn main() { struct Foo; diff --git a/tests/ui/traits/next-solver/normalize/eager-norm-pre-normalizes-to.rs b/tests/ui/traits/next-solver/normalize/eager-norm-pre-normalizes-to.rs new file mode 100644 index 00000000000..ea18ac54c05 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/eager-norm-pre-normalizes-to.rs @@ -0,0 +1,44 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// A regression test for trait-system-refactor-initiative#184. +// +// When adding nested goals we replace aliases with infer vars +// and add `AliasRelate` goals to constrain them. When doing this +// for `NormalizesTo` goals, we then first tries to prove the +// `NormalizesTo` goal and then normalized the nested aliases. + +trait Trait<T> { + type Assoc; +} +impl<T, U> Trait<U> for T { + type Assoc = (); +} + +trait Id { + type This; +} +impl<T> Id for T { + type This = T; +} +trait Relate<T> { + type Alias; +} +impl<T, U> Relate<U> for T { + type Alias = <T as Trait<<U as Id>::This>>::Assoc; +} + + +fn guide_me<T: Trait<u32>>() { + // Normalizing `<T as Relate<i32>>::Alias` relates the associated type with an unconstrained + // term. This resulted in a `NormalizesTo(<T as Trait<<U as Id>::This>>::Assoc, ?x)` goal. + // We replace `<i32 as Id>::This` with an infer var `?y`, resulting in the following goals: + // - `NormalizesTo(<T as Trait<?y>::Assoc, ?x)` + // - `AliasRelate(<i32 as Id>::This, ?y)` + // + // When proving the `NormalizesTo` goal first, we incompletely constrain `?y` to `u32`, + // causing an unexpected type mismatch. + let _: <T as Relate<i32>>::Alias; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs b/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs index 5284220ac38..3150d9a88d0 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver // When canonicalizing a response in the trait solver, we bail with overflow // if there are too many non-region inference variables. Doing so in normalizes-to diff --git a/tests/ui/transmute/auxiliary/unnecessary-transmute-path-remap-ice-140277-trans.rs b/tests/ui/transmute/auxiliary/unnecessary-transmute-path-remap-ice-140277-trans.rs new file mode 100644 index 00000000000..0f273a6f536 --- /dev/null +++ b/tests/ui/transmute/auxiliary/unnecessary-transmute-path-remap-ice-140277-trans.rs @@ -0,0 +1,10 @@ +//@ compile-flags: --remap-path-prefix=/=/non-existent +// helper for ../unnecessary-transmute-path-remap-ice-140277.rs + +#[macro_export] +macro_rules! transmute { + ($e:expr) => {{ + let e = $e; + std::mem::transmute(e) + }}; +} diff --git a/tests/ui/transmute/unnecessary-transmute-path-remap-ice-140277.rs b/tests/ui/transmute/unnecessary-transmute-path-remap-ice-140277.rs new file mode 100644 index 00000000000..756ce7b3d50 --- /dev/null +++ b/tests/ui/transmute/unnecessary-transmute-path-remap-ice-140277.rs @@ -0,0 +1,10 @@ +//@ aux-crate: zerocopy=unnecessary-transmute-path-remap-ice-140277-trans.rs +//@ check-pass +// tests for a regression in linting for unnecessary transmutes +// where a span was inacessible for snippet procuring, +// when remap-path-prefix was set, causing a panic. + +fn bytes_at_home(x: [u8; 4]) -> u32 { + unsafe { zerocopy::transmute!(x) } +} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs index 4391bf01dc9..7a540d2a574 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs @@ -22,7 +22,7 @@ impl<In, Out> Trait<Bar, In> for Out { type Out = Out; #[define_opaque(Bar)] fn convert(_i: In) -> Self::Out { - //[next]~^ ERROR: cannot satisfy `Bar == _` + //[next]~^ ERROR: type annotations needed: cannot satisfy `Bar == _` //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}` unreachable!(); } diff --git a/tests/ui/type-alias/type-param.rs b/tests/ui/type-alias/type-param.rs new file mode 100644 index 00000000000..f8e73518bad --- /dev/null +++ b/tests/ui/type-alias/type-param.rs @@ -0,0 +1,11 @@ +//@ run-pass +// This is a smoke test to ensure that type aliases with type parameters +// are accepted by the compiler and that the parameters are correctly +// resolved in the aliased item type. + +#![allow(dead_code)] + +type Foo<T> = extern "C" fn(T) -> bool; +type Bar<T> = fn(T) -> bool; + +fn main() {} diff --git a/tests/ui/type-param.rs b/tests/ui/type-param.rs deleted file mode 100644 index e7cf0e5446b..00000000000 --- a/tests/ui/type-param.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass - -#![allow(non_camel_case_types)] -#![allow(dead_code)] - - - -type lteq<T> = extern "C" fn(T) -> bool; - -pub fn main() { } diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 0fb5a26c5aa..5697f615b97 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -839,6 +839,7 @@ mod types { } /// TyKind::MacCall + #[expect(deprecated)] // concat_idents is deprecated fn ty_mac_call() { let _: concat_idents!(T); let _: concat_idents![T]; diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 8febd2d6d49..841edf63c91 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -359,6 +359,7 @@ mod expressions { + // concat_idents is deprecated @@ -674,6 +675,7 @@ mod types { /*! there is no syntax for this */ } /// TyKind::MacCall + #[expect(deprecated)] fn ty_mac_call() { let _: T; let _: T; let _: T; } /// TyKind::CVarArgs fn ty_c_var_args() { |
