| author | bors <bors@rust-lang.org> 2025-06-16 14:25:08 UTC |
| committer | bors <bors@rust-lang.org> 2025-06-16 14:25:08 UTC |
| log | 3bc767e1a215c4bf8f099b32e84edb85780591b1 |
| tree | 3da6113318c7c7b0fb401939b8888137c2c7388b |
| parent | d9ca9bd014074e2bac567eaa2b66bfacb2591028 |
| parent | 78d12b7e56ef5691d31b6f1697aba79eabe4bb2f |
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#141639 (Expose discriminant values in stable_mir)
- rust-lang/rust#142082 (Refactor `rustc_attr_data_structures` documentation)
- rust-lang/rust#142125 (Stabilize "file_lock" feature)
- rust-lang/rust#142236 (Add documentation for `PathBuf`'s `FromIterator` and `Extend` impls)
- rust-lang/rust#142373 (Fix Debug for Location)
- rust-lang/rust#142416 (Assorted bootstrap cleanups (step 2))
- rust-lang/rust#142431 (Add initial version of snapshot tests to bootstrap)
- rust-lang/rust#142450 (Add documentation on top of `rustc_middle/src/query/mod.rs`)
- rust-lang/rust#142528 (clarify `rustc_do_not_const_check` comment)
- rust-lang/rust#142530 (use `if let` guards where possible)
- rust-lang/rust#142561 (Remove an `njn:` comment accidentaly left behind.)
- rust-lang/rust#142566 (Fix `-nopt` CI jobs)
r? `@ghost`
`@rustbot` modify labels: rollup41 files changed, 721 insertions(+), 231 deletions(-)
compiler/rustc_attr_data_structures/src/attributes.rs+44-14| ... | ... | @@ -130,24 +130,54 @@ impl Deprecation { |
| 130 | 130 | } |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | /// Represent parsed, *built in*, inert attributes. | |
| 133 | /// Represents parsed *built-in* inert attributes. | |
| 134 | 134 | /// |
| 135 | /// That means attributes that are not actually ever expanded. | |
| 136 | /// For more information on this, see the module docs on the [`rustc_attr_parsing`] crate. | |
| 137 | /// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler. | |
| 138 | /// These are kept around after the AST, into the HIR and further on. | |
| 135 | /// ## Overview | |
| 136 | /// These attributes are markers that guide the compilation process and are never expanded into other code. | |
| 137 | /// They persist throughout the compilation phases, from AST to HIR and beyond. | |
| 139 | 138 | /// |
| 140 | /// The word "parsed" could be a little misleading here, because the parser already parses | |
| 141 | /// attributes early on. However, the result, an [`ast::Attribute`] | |
| 142 | /// is only parsed at a high level, still containing a token stream in many cases. That is | |
| 143 | /// because the structure of the contents varies from attribute to attribute. | |
| 144 | /// With a parsed attribute I mean that each attribute is processed individually into a | |
| 145 | /// final structure, which on-site (the place where the attribute is useful for, think the | |
| 146 | /// the place where `must_use` is checked) little to no extra parsing or validating needs to | |
| 147 | /// happen. | |
| 139 | /// ## Attribute Processing | |
| 140 | /// While attributes are initially parsed by [`rustc_parse`] into [`ast::Attribute`], they still contain raw token streams | |
| 141 | /// because different attributes have different internal structures. This enum represents the final, | |
| 142 | /// fully parsed form of these attributes, where each variant contains contains all the information and | |
| 143 | /// structure relevant for the specific attribute. | |
| 148 | 144 | /// |
| 149 | /// For more docs, look in [`rustc_attr_parsing`]. | |
| 145 | /// Some attributes can be applied multiple times to the same item, and they are "collapsed" into a single | |
| 146 | /// semantic attribute. For example: | |
| 147 | /// ```rust | |
| 148 | /// #[repr(C)] | |
| 149 | /// #[repr(packed)] | |
| 150 | /// struct S { } | |
| 151 | /// ``` | |
| 152 | /// This is equivalent to `#[repr(C, packed)]` and results in a single [`AttributeKind::Repr`] containing | |
| 153 | /// both `C` and `packed` annotations. This collapsing happens during parsing and is reflected in the | |
| 154 | /// data structures defined in this enum. | |
| 150 | 155 | /// |
| 156 | /// ## Usage | |
| 157 | /// These parsed attributes are used throughout the compiler to: | |
| 158 | /// - Control code generation (e.g., `#[repr]`) | |
| 159 | /// - Mark API stability (`#[stable]`, `#[unstable]`) | |
| 160 | /// - Provide documentation (`#[doc]`) | |
| 161 | /// - Guide compiler behavior (e.g., `#[allow_internal_unstable]`) | |
| 162 | /// | |
| 163 | /// ## Note on Attribute Organization | |
| 164 | /// Some attributes like `InlineAttr`, `OptimizeAttr`, and `InstructionSetAttr` are defined separately | |
| 165 | /// from this enum because they are used in specific compiler phases (like code generation) and don't | |
| 166 | /// need to persist throughout the entire compilation process. They are typically processed and | |
| 167 | /// converted into their final form earlier in the compilation pipeline. | |
| 168 | /// | |
| 169 | /// For example: | |
| 170 | /// - `InlineAttr` is used during code generation to control function inlining | |
| 171 | /// - `OptimizeAttr` is used to control optimization levels | |
| 172 | /// - `InstructionSetAttr` is used for target-specific code generation | |
| 173 | /// | |
| 174 | /// These attributes are handled by their respective compiler passes in the [`rustc_codegen_ssa`] crate | |
| 175 | /// and don't need to be preserved in the same way as the attributes in this enum. | |
| 176 | /// | |
| 177 | /// For more details on attribute parsing, see the [`rustc_attr_parsing`] crate. | |
| 178 | /// | |
| 179 | /// [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html | |
| 180 | /// [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html | |
| 151 | 181 | /// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html |
| 152 | 182 | #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] |
| 153 | 183 | pub enum AttributeKind { |
compiler/rustc_attr_data_structures/src/lib.rs+4| ... | ... | @@ -1,3 +1,7 @@ |
| 1 | //! Data structures for representing parsed attributes in the Rust compiler. | |
| 2 | //! For detailed documentation about attribute processing, | |
| 3 | //! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html). | |
| 4 | ||
| 1 | 5 | // tidy-alphabetical-start |
| 2 | 6 | #![allow(internal_features)] |
| 3 | 7 | #![doc(rust_logo)] |
compiler/rustc_builtin_macros/src/test.rs+1-4| ... | ... | @@ -118,10 +118,7 @@ pub(crate) fn expand_test_or_bench( |
| 118 | 118 | |
| 119 | 119 | let (item, is_stmt) = match item { |
| 120 | 120 | Annotatable::Item(i) => (i, false), |
| 121 | Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { | |
| 122 | // FIXME: Use an 'if let' guard once they are implemented | |
| 123 | if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() } | |
| 124 | } | |
| 121 | Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true), | |
| 125 | 122 | other => { |
| 126 | 123 | not_testable_error(cx, attr_sp, None); |
| 127 | 124 | return vec![other]; |
compiler/rustc_expand/src/base.rs+2-1| ... | ... | @@ -35,6 +35,7 @@ use crate::base::ast::MetaItemInner; |
| 35 | 35 | use crate::errors; |
| 36 | 36 | use crate::expand::{self, AstFragment, Invocation}; |
| 37 | 37 | use crate::module::DirOwnership; |
| 38 | use crate::stats::MacroStat; | |
| 38 | 39 | |
| 39 | 40 | // When adding new variants, make sure to |
| 40 | 41 | // adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector` |
| ... | ... | @@ -1191,7 +1192,7 @@ pub struct ExtCtxt<'a> { |
| 1191 | 1192 | /// not to expand it again. |
| 1192 | 1193 | pub(super) expanded_inert_attrs: MarkedAttrs, |
| 1193 | 1194 | /// `-Zmacro-stats` data. |
| 1194 | pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals | |
| 1195 | pub macro_stats: FxHashMap<(Symbol, MacroKind), MacroStat>, | |
| 1195 | 1196 | } |
| 1196 | 1197 | |
| 1197 | 1198 | impl<'a> ExtCtxt<'a> { |
compiler/rustc_feature/src/builtin_attrs.rs+1-1| ... | ... | @@ -887,7 +887,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ |
| 887 | 887 | rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing, |
| 888 | 888 | EncodeCrossCrate::Yes, |
| 889 | 889 | ), |
| 890 | // Do not const-check this function's body. It will always get replaced during CTFE. | |
| 890 | // Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`. | |
| 891 | 891 | rustc_attr!( |
| 892 | 892 | rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, |
| 893 | 893 | EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body", |
compiler/rustc_middle/src/query/mod.rs+60-4| ... | ... | @@ -1,8 +1,64 @@ |
| 1 | //! Defines the various compiler queries. | |
| 2 | 1 | //! |
| 3 | //! For more information on the query system, see | |
| 4 | //! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html). | |
| 5 | //! This chapter includes instructions for adding new queries. | |
| 2 | //! # The rustc Query System: Query Definitions and Modifiers | |
| 3 | //! | |
| 4 | //! The core processes in rustc are shipped as queries. Each query is a demand-driven function from some key to a value. | |
| 5 | //! The execution result of the function is cached and directly read during the next request, thereby improving compilation efficiency. | |
| 6 | //! Some results are saved locally and directly read during the next compilation, which are core of incremental compilation. | |
| 7 | //! | |
| 8 | //! ## How to Read This Module | |
| 9 | //! | |
| 10 | //! Each `query` block in this file defines a single query, specifying its key and value types, along with various modifiers. | |
| 11 | //! These query definitions are processed by the [`rustc_macros`], which expands them into the necessary boilerplate code | |
| 12 | //! for the query system—including the [`Providers`] struct (a function table for all query implementations, where each field is | |
| 13 | //! a function pointer to the actual provider), caching, and dependency graph integration. | |
| 14 | //! **Note:** The `Providers` struct is not a Rust trait, but a struct generated by the `rustc_macros` to hold all provider functions. | |
| 15 | //! The `rustc_macros` also supports a set of **query modifiers** (see below) that control the behavior of each query. | |
| 16 | //! | |
| 17 | //! The actual provider functions are implemented in various modules and registered into the `Providers` struct | |
| 18 | //! during compiler initialization (see [`rustc_interface::passes::DEFAULT_QUERY_PROVIDERS`]). | |
| 19 | //! | |
| 20 | //! [`rustc_macros`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/index.html | |
| 21 | //! [`rustc_interface::passes::DEFAULT_QUERY_PROVIDERS`]: ../../rustc_interface/passes/static.DEFAULT_QUERY_PROVIDERS.html | |
| 22 | //! | |
| 23 | //! ## Query Modifiers | |
| 24 | //! | |
| 25 | //! Query modifiers are special flags that alter the behavior of a query. They are parsed and processed by the `rustc_macros` | |
| 26 | //! The main modifiers are: | |
| 27 | //! | |
| 28 | //! - `desc { ... }`: Sets the human-readable description for diagnostics and profiling. Required for every query. | |
| 29 | //! - `arena_cache`: Use an arena for in-memory caching of the query result. | |
| 30 | //! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to true. | |
| 31 | //! - `fatal_cycle`: If a dependency cycle is detected, abort compilation with a fatal error. | |
| 32 | //! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately. | |
| 33 | //! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling. | |
| 34 | //! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed. | |
| 35 | //! - `anon`: Make the query anonymous in the dependency graph (no dep node is created). | |
| 36 | //! - `eval_always`: Always evaluate the query, ignoring its dependencies and cached results. | |
| 37 | //! - `depth_limit`: Impose a recursion depth limit on the query to prevent stack overflows. | |
| 38 | //! - `separate_provide_extern`: Use separate provider functions for local and external crates. | |
| 39 | //! - `feedable`: Allow the query result to be set from another query ("fed" externally). | |
| 40 | //! - `return_result_from_ensure_ok`: When called via `tcx.ensure_ok()`, return `Result<(), ErrorGuaranteed>` instead of `()`. | |
| 41 | //! If the query needs to be executed and returns an error, the error is returned to the caller. | |
| 42 | //! Only valid for queries returning `Result<_, ErrorGuaranteed>`. | |
| 43 | //! | |
| 44 | //! For the up-to-date list, see the `QueryModifiers` struct in | |
| 45 | //! [`rustc_macros/src/query.rs`](https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/query.rs) | |
| 46 | //! and for more details in incremental compilation, see the | |
| 47 | //! [Query modifiers in incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation-in-detail.html#query-modifiers) section of the rustc-dev-guide. | |
| 48 | //! | |
| 49 | //! ## Query Expansion and Code Generation | |
| 50 | //! | |
| 51 | //! The [`rustc_macros::rustc_queries`] macro expands each query definition into: | |
| 52 | //! - A method on [`TyCtxt`] (and [`TyCtxtAt`]) for invoking the query. | |
| 53 | //! - Provider traits and structs for supplying the query's value. | |
| 54 | //! - Caching and dependency graph integration. | |
| 55 | //! - Support for incremental compilation, disk caching, and arena allocation as controlled by the modifiers. | |
| 56 | //! | |
| 57 | //! [`rustc_macros::rustc_queries`]: ../../rustc_macros/macro.rustc_queries.html | |
| 58 | //! | |
| 59 | //! The macro-based approach allows the query system to be highly flexible and maintainable, while minimizing boilerplate. | |
| 60 | //! | |
| 61 | //! For more details, see the [rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/query.html). | |
| 6 | 62 | |
| 7 | 63 | #![allow(unused_parens)] |
| 8 | 64 |
compiler/rustc_parse/src/parser/diagnostics.rs+11-16| ... | ... | @@ -2273,23 +2273,18 @@ impl<'a> Parser<'a> { |
| 2273 | 2273 | ), |
| 2274 | 2274 | // Also catches `fn foo(&a)`. |
| 2275 | 2275 | PatKind::Ref(ref inner_pat, mutab) |
| 2276 | if matches!(inner_pat.clone().kind, PatKind::Ident(..)) => | |
| 2276 | if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind => | |
| 2277 | 2277 | { |
| 2278 | match inner_pat.clone().kind { | |
| 2279 | PatKind::Ident(_, ident, _) => { | |
| 2280 | let mutab = mutab.prefix_str(); | |
| 2281 | ( | |
| 2282 | ident, | |
| 2283 | "self: ", | |
| 2284 | format!("{ident}: &{mutab}TypeName"), | |
| 2285 | "_: ", | |
| 2286 | pat.span.shrink_to_lo(), | |
| 2287 | pat.span, | |
| 2288 | pat.span.shrink_to_lo(), | |
| 2289 | ) | |
| 2290 | } | |
| 2291 | _ => unreachable!(), | |
| 2292 | } | |
| 2278 | let mutab = mutab.prefix_str(); | |
| 2279 | ( | |
| 2280 | ident, | |
| 2281 | "self: ", | |
| 2282 | format!("{ident}: &{mutab}TypeName"), | |
| 2283 | "_: ", | |
| 2284 | pat.span.shrink_to_lo(), | |
| 2285 | pat.span, | |
| 2286 | pat.span.shrink_to_lo(), | |
| 2287 | ) | |
| 2293 | 2288 | } |
| 2294 | 2289 | _ => { |
| 2295 | 2290 | // Otherwise, try to get a type and emit a suggestion. |
compiler/rustc_smir/src/rustc_smir/context.rs+29-4| ... | ... | @@ -12,7 +12,8 @@ use rustc_middle::ty::layout::{ |
| 12 | 12 | }; |
| 13 | 13 | use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; |
| 14 | 14 | use rustc_middle::ty::{ |
| 15 | GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, | |
| 15 | CoroutineArgsExt, GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, | |
| 16 | ValTree, | |
| 16 | 17 | }; |
| 17 | 18 | use rustc_middle::{mir, ty}; |
| 18 | 19 | use rustc_span::def_id::LOCAL_CRATE; |
| ... | ... | @@ -22,9 +23,9 @@ use stable_mir::mir::mono::{InstanceDef, StaticDef}; |
| 22 | 23 | use stable_mir::mir::{BinOp, Body, Place, UnOp}; |
| 23 | 24 | use stable_mir::target::{MachineInfo, MachineSize}; |
| 24 | 25 | use stable_mir::ty::{ |
| 25 | AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef, | |
| 26 | ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, Ty, | |
| 27 | TyConst, TyKind, UintTy, VariantDef, | |
| 26 | AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef, | |
| 27 | ForeignDef, ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, | |
| 28 | Span, Ty, TyConst, TyKind, UintTy, VariantDef, VariantIdx, | |
| 28 | 29 | }; |
| 29 | 30 | use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol}; |
| 30 | 31 | |
| ... | ... | @@ -447,6 +448,30 @@ impl<'tcx> SmirCtxt<'tcx> { |
| 447 | 448 | def.internal(&mut *tables, tcx).variants().len() |
| 448 | 449 | } |
| 449 | 450 | |
| 451 | /// Discriminant for a given variant index of AdtDef | |
| 452 | pub fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr { | |
| 453 | let mut tables = self.0.borrow_mut(); | |
| 454 | let tcx = tables.tcx; | |
| 455 | let adt = adt.internal(&mut *tables, tcx); | |
| 456 | let variant = variant.internal(&mut *tables, tcx); | |
| 457 | adt.discriminant_for_variant(tcx, variant).stable(&mut *tables) | |
| 458 | } | |
| 459 | ||
| 460 | /// Discriminant for a given variand index and args of a coroutine | |
| 461 | pub fn coroutine_discr_for_variant( | |
| 462 | &self, | |
| 463 | coroutine: CoroutineDef, | |
| 464 | args: &GenericArgs, | |
| 465 | variant: VariantIdx, | |
| 466 | ) -> Discr { | |
| 467 | let mut tables = self.0.borrow_mut(); | |
| 468 | let tcx = tables.tcx; | |
| 469 | let coroutine = coroutine.def_id().internal(&mut *tables, tcx); | |
| 470 | let args = args.internal(&mut *tables, tcx); | |
| 471 | let variant = variant.internal(&mut *tables, tcx); | |
| 472 | args.as_coroutine().discriminant_for_variant(coroutine, tcx, variant).stable(&mut *tables) | |
| 473 | } | |
| 474 | ||
| 450 | 475 | /// The name of a variant. |
| 451 | 476 | pub fn variant_name(&self, def: VariantDef) -> Symbol { |
| 452 | 477 | let mut tables = self.0.borrow_mut(); |
compiler/rustc_smir/src/rustc_smir/convert/ty.rs+8| ... | ... | @@ -960,3 +960,11 @@ impl<'tcx> Stable<'tcx> for ty::ImplTraitInTraitData { |
| 960 | 960 | } |
| 961 | 961 | } |
| 962 | 962 | } |
| 963 | ||
| 964 | impl<'tcx> Stable<'tcx> for rustc_middle::ty::util::Discr<'tcx> { | |
| 965 | type T = stable_mir::ty::Discr; | |
| 966 | ||
| 967 | fn stable(&self, tables: &mut Tables<'_>) -> Self::T { | |
| 968 | stable_mir::ty::Discr { val: self.val, ty: self.ty.stable(tables) } | |
| 969 | } | |
| 970 | } |
compiler/rustc_smir/src/stable_mir/compiler_interface.rs+19-4| ... | ... | @@ -13,10 +13,10 @@ use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef}; |
| 13 | 13 | use stable_mir::mir::{BinOp, Body, Place, UnOp}; |
| 14 | 14 | use stable_mir::target::MachineInfo; |
| 15 | 15 | use stable_mir::ty::{ |
| 16 | AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef, | |
| 17 | ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics, | |
| 18 | ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, TraitDecl, | |
| 19 | TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, | |
| 16 | AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef, | |
| 17 | ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, | |
| 18 | Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, | |
| 19 | TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx, | |
| 20 | 20 | }; |
| 21 | 21 | use stable_mir::{ |
| 22 | 22 | AssocItems, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, |
| ... | ... | @@ -230,6 +230,21 @@ impl<'tcx> SmirInterface<'tcx> { |
| 230 | 230 | self.cx.adt_variants_len(def) |
| 231 | 231 | } |
| 232 | 232 | |
| 233 | /// Discriminant for a given variant index of AdtDef | |
| 234 | pub(crate) fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr { | |
| 235 | self.cx.adt_discr_for_variant(adt, variant) | |
| 236 | } | |
| 237 | ||
| 238 | /// Discriminant for a given variand index and args of a coroutine | |
| 239 | pub(crate) fn coroutine_discr_for_variant( | |
| 240 | &self, | |
| 241 | coroutine: CoroutineDef, | |
| 242 | args: &GenericArgs, | |
| 243 | variant: VariantIdx, | |
| 244 | ) -> Discr { | |
| 245 | self.cx.coroutine_discr_for_variant(coroutine, args, variant) | |
| 246 | } | |
| 247 | ||
| 233 | 248 | /// The name of a variant. |
| 234 | 249 | pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol { |
| 235 | 250 | self.cx.variant_name(def) |
compiler/rustc_smir/src/stable_mir/ty.rs+15| ... | ... | @@ -756,6 +756,12 @@ crate_def! { |
| 756 | 756 | pub CoroutineDef; |
| 757 | 757 | } |
| 758 | 758 | |
| 759 | impl CoroutineDef { | |
| 760 | pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr { | |
| 761 | with(|cx| cx.coroutine_discr_for_variant(*self, args, idx)) | |
| 762 | } | |
| 763 | } | |
| 764 | ||
| 759 | 765 | crate_def! { |
| 760 | 766 | #[derive(Serialize)] |
| 761 | 767 | pub CoroutineClosureDef; |
| ... | ... | @@ -831,6 +837,15 @@ impl AdtDef { |
| 831 | 837 | pub fn repr(&self) -> ReprOptions { |
| 832 | 838 | with(|cx| cx.adt_repr(*self)) |
| 833 | 839 | } |
| 840 | ||
| 841 | pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr { | |
| 842 | with(|cx| cx.adt_discr_for_variant(*self, idx)) | |
| 843 | } | |
| 844 | } | |
| 845 | ||
| 846 | pub struct Discr { | |
| 847 | pub val: u128, | |
| 848 | pub ty: Ty, | |
| 834 | 849 | } |
| 835 | 850 | |
| 836 | 851 | /// Definition of a variant, which can be either a struct / union field or an enum variant. |
library/core/src/panic/location.rs+12-1| ... | ... | @@ -30,7 +30,7 @@ use crate::fmt; |
| 30 | 30 | /// Files are compared as strings, not `Path`, which could be unexpected. |
| 31 | 31 | /// See [`Location::file`]'s documentation for more discussion. |
| 32 | 32 | #[lang = "panic_location"] |
| 33 | #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] | |
| 33 | #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] | |
| 34 | 34 | #[stable(feature = "panic_hooks", since = "1.10.0")] |
| 35 | 35 | pub struct Location<'a> { |
| 36 | 36 | // Note: this filename will have exactly one nul byte at its end, but otherwise |
| ... | ... | @@ -43,6 +43,17 @@ pub struct Location<'a> { |
| 43 | 43 | col: u32, |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | #[stable(feature = "panic_hooks", since = "1.10.0")] | |
| 47 | impl fmt::Debug for Location<'_> { | |
| 48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 49 | f.debug_struct("Location") | |
| 50 | .field("file", &self.file()) | |
| 51 | .field("line", &self.line) | |
| 52 | .field("column", &self.col) | |
| 53 | .finish() | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 46 | 57 | impl<'a> Location<'a> { |
| 47 | 58 | /// Returns the source location of the caller of this function. If that function's caller is |
| 48 | 59 | /// annotated then its call location will be returned, and so on up the stack to the first call |
library/coretests/tests/panic/location.rs+8| ... | ... | @@ -29,3 +29,11 @@ fn location_const_column() { |
| 29 | 29 | const COLUMN: u32 = CALLER.column(); |
| 30 | 30 | assert_eq!(COLUMN, 40); |
| 31 | 31 | } |
| 32 | ||
| 33 | #[test] | |
| 34 | fn location_debug() { | |
| 35 | let f = format!("{:?}", Location::caller()); | |
| 36 | assert!(f.contains(&format!("{:?}", file!()))); | |
| 37 | assert!(f.contains("35")); | |
| 38 | assert!(f.contains("29")); | |
| 39 | } |
library/std/src/fs.rs+10-15| ... | ... | @@ -121,7 +121,7 @@ pub struct File { |
| 121 | 121 | /// |
| 122 | 122 | /// [`try_lock`]: File::try_lock |
| 123 | 123 | /// [`try_lock_shared`]: File::try_lock_shared |
| 124 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 124 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 125 | 125 | pub enum TryLockError { |
| 126 | 126 | /// The lock could not be acquired due to an I/O error on the file. The standard library will |
| 127 | 127 | /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`] |
| ... | ... | @@ -366,10 +366,10 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result |
| 366 | 366 | inner(path.as_ref(), contents.as_ref()) |
| 367 | 367 | } |
| 368 | 368 | |
| 369 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 369 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 370 | 370 | impl error::Error for TryLockError {} |
| 371 | 371 | |
| 372 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 372 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 373 | 373 | impl fmt::Debug for TryLockError { |
| 374 | 374 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 375 | 375 | match self { |
| ... | ... | @@ -379,7 +379,7 @@ impl fmt::Debug for TryLockError { |
| 379 | 379 | } |
| 380 | 380 | } |
| 381 | 381 | |
| 382 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 382 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 383 | 383 | impl fmt::Display for TryLockError { |
| 384 | 384 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 385 | 385 | match self { |
| ... | ... | @@ -390,7 +390,7 @@ impl fmt::Display for TryLockError { |
| 390 | 390 | } |
| 391 | 391 | } |
| 392 | 392 | |
| 393 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 393 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 394 | 394 | impl From<TryLockError> for io::Error { |
| 395 | 395 | fn from(err: TryLockError) -> io::Error { |
| 396 | 396 | match err { |
| ... | ... | @@ -713,7 +713,6 @@ impl File { |
| 713 | 713 | /// # Examples |
| 714 | 714 | /// |
| 715 | 715 | /// ```no_run |
| 716 | /// #![feature(file_lock)] | |
| 717 | 716 | /// use std::fs::File; |
| 718 | 717 | /// |
| 719 | 718 | /// fn main() -> std::io::Result<()> { |
| ... | ... | @@ -722,7 +721,7 @@ impl File { |
| 722 | 721 | /// Ok(()) |
| 723 | 722 | /// } |
| 724 | 723 | /// ``` |
| 725 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 724 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 726 | 725 | pub fn lock(&self) -> io::Result<()> { |
| 727 | 726 | self.inner.lock() |
| 728 | 727 | } |
| ... | ... | @@ -766,7 +765,6 @@ impl File { |
| 766 | 765 | /// # Examples |
| 767 | 766 | /// |
| 768 | 767 | /// ```no_run |
| 769 | /// #![feature(file_lock)] | |
| 770 | 768 | /// use std::fs::File; |
| 771 | 769 | /// |
| 772 | 770 | /// fn main() -> std::io::Result<()> { |
| ... | ... | @@ -775,7 +773,7 @@ impl File { |
| 775 | 773 | /// Ok(()) |
| 776 | 774 | /// } |
| 777 | 775 | /// ``` |
| 778 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 776 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 779 | 777 | pub fn lock_shared(&self) -> io::Result<()> { |
| 780 | 778 | self.inner.lock_shared() |
| 781 | 779 | } |
| ... | ... | @@ -824,7 +822,6 @@ impl File { |
| 824 | 822 | /// # Examples |
| 825 | 823 | /// |
| 826 | 824 | /// ```no_run |
| 827 | /// #![feature(file_lock)] | |
| 828 | 825 | /// use std::fs::{File, TryLockError}; |
| 829 | 826 | /// |
| 830 | 827 | /// fn main() -> std::io::Result<()> { |
| ... | ... | @@ -840,7 +837,7 @@ impl File { |
| 840 | 837 | /// Ok(()) |
| 841 | 838 | /// } |
| 842 | 839 | /// ``` |
| 843 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 840 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 844 | 841 | pub fn try_lock(&self) -> Result<(), TryLockError> { |
| 845 | 842 | self.inner.try_lock() |
| 846 | 843 | } |
| ... | ... | @@ -888,7 +885,6 @@ impl File { |
| 888 | 885 | /// # Examples |
| 889 | 886 | /// |
| 890 | 887 | /// ```no_run |
| 891 | /// #![feature(file_lock)] | |
| 892 | 888 | /// use std::fs::{File, TryLockError}; |
| 893 | 889 | /// |
| 894 | 890 | /// fn main() -> std::io::Result<()> { |
| ... | ... | @@ -905,7 +901,7 @@ impl File { |
| 905 | 901 | /// Ok(()) |
| 906 | 902 | /// } |
| 907 | 903 | /// ``` |
| 908 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 904 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 909 | 905 | pub fn try_lock_shared(&self) -> Result<(), TryLockError> { |
| 910 | 906 | self.inner.try_lock_shared() |
| 911 | 907 | } |
| ... | ... | @@ -933,7 +929,6 @@ impl File { |
| 933 | 929 | /// # Examples |
| 934 | 930 | /// |
| 935 | 931 | /// ```no_run |
| 936 | /// #![feature(file_lock)] | |
| 937 | 932 | /// use std::fs::File; |
| 938 | 933 | /// |
| 939 | 934 | /// fn main() -> std::io::Result<()> { |
| ... | ... | @@ -943,7 +938,7 @@ impl File { |
| 943 | 938 | /// Ok(()) |
| 944 | 939 | /// } |
| 945 | 940 | /// ``` |
| 946 | #[unstable(feature = "file_lock", issue = "130994")] | |
| 941 | #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] | |
| 947 | 942 | pub fn unlock(&self) -> io::Result<()> { |
| 948 | 943 | self.inner.unlock() |
| 949 | 944 | } |
library/std/src/path.rs+27| ... | ... | @@ -1882,6 +1882,19 @@ impl FromStr for PathBuf { |
| 1882 | 1882 | |
| 1883 | 1883 | #[stable(feature = "rust1", since = "1.0.0")] |
| 1884 | 1884 | impl<P: AsRef<Path>> FromIterator<P> for PathBuf { |
| 1885 | /// Creates a new `PathBuf` from the [`Path`] elements of an iterator. | |
| 1886 | /// | |
| 1887 | /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path | |
| 1888 | /// [components](Components). | |
| 1889 | /// | |
| 1890 | /// # Examples | |
| 1891 | /// ``` | |
| 1892 | /// # use std::path::PathBuf; | |
| 1893 | /// let path = PathBuf::from_iter(["/tmp", "foo", "bar"]); | |
| 1894 | /// assert_eq!(path, PathBuf::from("/tmp/foo/bar")); | |
| 1895 | /// ``` | |
| 1896 | /// | |
| 1897 | /// See documentation for [`push`](Self::push) for more details on how the path is constructed. | |
| 1885 | 1898 | fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf { |
| 1886 | 1899 | let mut buf = PathBuf::new(); |
| 1887 | 1900 | buf.extend(iter); |
| ... | ... | @@ -1891,6 +1904,20 @@ impl<P: AsRef<Path>> FromIterator<P> for PathBuf { |
| 1891 | 1904 | |
| 1892 | 1905 | #[stable(feature = "rust1", since = "1.0.0")] |
| 1893 | 1906 | impl<P: AsRef<Path>> Extend<P> for PathBuf { |
| 1907 | /// Extends `self` with [`Path`] elements from `iter`. | |
| 1908 | /// | |
| 1909 | /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path | |
| 1910 | /// [components](Components). | |
| 1911 | /// | |
| 1912 | /// # Examples | |
| 1913 | /// ``` | |
| 1914 | /// # use std::path::PathBuf; | |
| 1915 | /// let mut path = PathBuf::from("/tmp"); | |
| 1916 | /// path.extend(["foo", "bar", "file.txt"]); | |
| 1917 | /// assert_eq!(path, PathBuf::from("/tmp/foo/bar/file.txt")); | |
| 1918 | /// ``` | |
| 1919 | /// | |
| 1920 | /// See documentation for [`push`](Self::push) for more details on how the path is constructed. | |
| 1894 | 1921 | fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) { |
| 1895 | 1922 | iter.into_iter().for_each(move |p| self.push(p.as_ref())); |
| 1896 | 1923 | } |
src/bootstrap/Cargo.lock+36| ... | ... | @@ -44,6 +44,7 @@ dependencies = [ |
| 44 | 44 | "fd-lock", |
| 45 | 45 | "home", |
| 46 | 46 | "ignore", |
| 47 | "insta", | |
| 47 | 48 | "junction", |
| 48 | 49 | "libc", |
| 49 | 50 | "object", |
| ... | ... | @@ -158,6 +159,18 @@ dependencies = [ |
| 158 | 159 | "cc", |
| 159 | 160 | ] |
| 160 | 161 | |
| 162 | [[package]] | |
| 163 | name = "console" | |
| 164 | version = "0.15.11" | |
| 165 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 166 | checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" | |
| 167 | dependencies = [ | |
| 168 | "encode_unicode", | |
| 169 | "libc", | |
| 170 | "once_cell", | |
| 171 | "windows-sys 0.59.0", | |
| 172 | ] | |
| 173 | ||
| 161 | 174 | [[package]] |
| 162 | 175 | name = "cpufeatures" |
| 163 | 176 | version = "0.2.15" |
| ... | ... | @@ -218,6 +231,12 @@ dependencies = [ |
| 218 | 231 | "crypto-common", |
| 219 | 232 | ] |
| 220 | 233 | |
| 234 | [[package]] | |
| 235 | name = "encode_unicode" | |
| 236 | version = "1.0.0" | |
| 237 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 238 | checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" | |
| 239 | ||
| 221 | 240 | [[package]] |
| 222 | 241 | name = "errno" |
| 223 | 242 | version = "0.3.11" |
| ... | ... | @@ -323,6 +342,17 @@ dependencies = [ |
| 323 | 342 | "winapi-util", |
| 324 | 343 | ] |
| 325 | 344 | |
| 345 | [[package]] | |
| 346 | name = "insta" | |
| 347 | version = "1.43.1" | |
| 348 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 349 | checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371" | |
| 350 | dependencies = [ | |
| 351 | "console", | |
| 352 | "once_cell", | |
| 353 | "similar", | |
| 354 | ] | |
| 355 | ||
| 326 | 356 | [[package]] |
| 327 | 357 | name = "itoa" |
| 328 | 358 | version = "1.0.11" |
| ... | ... | @@ -675,6 +705,12 @@ version = "1.3.0" |
| 675 | 705 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 676 | 706 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" |
| 677 | 707 | |
| 708 | [[package]] | |
| 709 | name = "similar" | |
| 710 | version = "2.7.0" | |
| 711 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 712 | checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" | |
| 713 | ||
| 678 | 714 | [[package]] |
| 679 | 715 | name = "smallvec" |
| 680 | 716 | version = "1.13.2" |
src/bootstrap/Cargo.toml+1| ... | ... | @@ -84,6 +84,7 @@ features = [ |
| 84 | 84 | [dev-dependencies] |
| 85 | 85 | pretty_assertions = "1.4" |
| 86 | 86 | tempfile = "3.15.0" |
| 87 | insta = "1.43" | |
| 87 | 88 | |
| 88 | 89 | # We care a lot about bootstrap's compile times, so don't include debuginfo for |
| 89 | 90 | # dependencies, only bootstrap itself. |
src/bootstrap/README.md+4| ... | ... | @@ -200,6 +200,10 @@ please file issues on the [Rust issue tracker][rust-issue-tracker]. |
| 200 | 200 | [rust-bootstrap-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/t-infra.2Fbootstrap |
| 201 | 201 | [rust-issue-tracker]: https://github.com/rust-lang/rust/issues |
| 202 | 202 | |
| 203 | ## Testing | |
| 204 | ||
| 205 | To run bootstrap tests, execute `x test bootstrap`. If you want to bless snapshot tests, then install `cargo-insta` (`cargo install cargo-insta`) and then run `cargo insta review --manifest-path src/bootstrap/Cargo.toml`. | |
| 206 | ||
| 203 | 207 | ## Changelog |
| 204 | 208 | |
| 205 | 209 | Because we do not release bootstrap with versions, we also do not maintain CHANGELOG files. To |
src/bootstrap/src/core/build_steps/test.rs+4-3| ... | ... | @@ -2009,7 +2009,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the |
| 2009 | 2009 | // Note that if we encounter `PATH` we make sure to append to our own `PATH` |
| 2010 | 2010 | // rather than stomp over it. |
| 2011 | 2011 | if !builder.config.dry_run() && target.is_msvc() { |
| 2012 | for (k, v) in builder.cc.borrow()[&target].env() { | |
| 2012 | for (k, v) in builder.cc[&target].env() { | |
| 2013 | 2013 | if k != "PATH" { |
| 2014 | 2014 | cmd.env(k, v); |
| 2015 | 2015 | } |
| ... | ... | @@ -2026,8 +2026,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the |
| 2026 | 2026 | // address sanitizer enabled (e.g., ntdll.dll). |
| 2027 | 2027 | cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1"); |
| 2028 | 2028 | // Add the address sanitizer runtime to the PATH - it is located next to cl.exe. |
| 2029 | let asan_runtime_path = | |
| 2030 | builder.cc.borrow()[&target].path().parent().unwrap().to_path_buf(); | |
| 2029 | let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf(); | |
| 2031 | 2030 | let old_path = cmd |
| 2032 | 2031 | .get_envs() |
| 2033 | 2032 | .find_map(|(k, v)| (k == "PATH").then_some(v)) |
| ... | ... | @@ -3059,6 +3058,8 @@ impl Step for Bootstrap { |
| 3059 | 3058 | cargo |
| 3060 | 3059 | .rustflag("-Cdebuginfo=2") |
| 3061 | 3060 | .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) |
| 3061 | // Needed for insta to correctly write pending snapshots to the right directories. | |
| 3062 | .env("INSTA_WORKSPACE_ROOT", &builder.src) | |
| 3062 | 3063 | .env("RUSTC_BOOTSTRAP", "1"); |
| 3063 | 3064 | |
| 3064 | 3065 | // bootstrap tests are racy on directory creation so just run them one at a time. |
src/bootstrap/src/core/build_steps/tool.rs+1-1| ... | ... | @@ -1334,7 +1334,7 @@ impl Builder<'_> { |
| 1334 | 1334 | if compiler.host.is_msvc() { |
| 1335 | 1335 | let curpaths = env::var_os("PATH").unwrap_or_default(); |
| 1336 | 1336 | let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>(); |
| 1337 | for (k, v) in self.cc.borrow()[&compiler.host].env() { | |
| 1337 | for (k, v) in self.cc[&compiler.host].env() { | |
| 1338 | 1338 | if k != "PATH" { |
| 1339 | 1339 | continue; |
| 1340 | 1340 | } |
src/bootstrap/src/core/builder/cargo.rs+1-3| ... | ... | @@ -278,9 +278,7 @@ impl Cargo { |
| 278 | 278 | self.rustdocflags.arg(&arg); |
| 279 | 279 | } |
| 280 | 280 | |
| 281 | if !builder.config.dry_run() | |
| 282 | && builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz") | |
| 283 | { | |
| 281 | if !builder.config.dry_run() && builder.cc[&target].args().iter().any(|arg| arg == "-gz") { | |
| 284 | 282 | self.rustflags.arg("-Clink-arg=-gz"); |
| 285 | 283 | } |
| 286 | 284 |
src/bootstrap/src/core/builder/mod.rs+19-2| ... | ... | @@ -5,7 +5,7 @@ use std::fmt::{self, Debug, Write}; |
| 5 | 5 | use std::hash::Hash; |
| 6 | 6 | use std::ops::Deref; |
| 7 | 7 | use std::path::{Path, PathBuf}; |
| 8 | use std::sync::LazyLock; | |
| 8 | use std::sync::{LazyLock, OnceLock}; | |
| 9 | 9 | use std::time::{Duration, Instant}; |
| 10 | 10 | use std::{env, fs}; |
| 11 | 11 | |
| ... | ... | @@ -60,6 +60,9 @@ pub struct Builder<'a> { |
| 60 | 60 | /// to do. For example: with `./x check foo bar` we get `paths=["foo", |
| 61 | 61 | /// "bar"]`. |
| 62 | 62 | pub paths: Vec<PathBuf>, |
| 63 | ||
| 64 | /// Cached list of submodules from self.build.src. | |
| 65 | submodule_paths_cache: OnceLock<Vec<String>>, | |
| 63 | 66 | } |
| 64 | 67 | |
| 65 | 68 | impl Deref for Builder<'_> { |
| ... | ... | @@ -687,7 +690,7 @@ impl<'a> ShouldRun<'a> { |
| 687 | 690 | /// |
| 688 | 691 | /// [`path`]: ShouldRun::path |
| 689 | 692 | pub fn paths(mut self, paths: &[&str]) -> Self { |
| 690 | let submodules_paths = build_helper::util::parse_gitmodules(&self.builder.src); | |
| 693 | let submodules_paths = self.builder.submodule_paths(); | |
| 691 | 694 | |
| 692 | 695 | self.paths.insert(PathSet::Set( |
| 693 | 696 | paths |
| ... | ... | @@ -1180,6 +1183,7 @@ impl<'a> Builder<'a> { |
| 1180 | 1183 | stack: RefCell::new(Vec::new()), |
| 1181 | 1184 | time_spent_on_dependencies: Cell::new(Duration::new(0, 0)), |
| 1182 | 1185 | paths, |
| 1186 | submodule_paths_cache: Default::default(), | |
| 1183 | 1187 | } |
| 1184 | 1188 | } |
| 1185 | 1189 | |
| ... | ... | @@ -1510,6 +1514,19 @@ impl<'a> Builder<'a> { |
| 1510 | 1514 | None |
| 1511 | 1515 | } |
| 1512 | 1516 | |
| 1517 | /// Updates all submodules, and exits with an error if submodule | |
| 1518 | /// management is disabled and the submodule does not exist. | |
| 1519 | pub fn require_and_update_all_submodules(&self) { | |
| 1520 | for submodule in self.submodule_paths() { | |
| 1521 | self.require_submodule(submodule, None); | |
| 1522 | } | |
| 1523 | } | |
| 1524 | ||
| 1525 | /// Get all submodules from the src directory. | |
| 1526 | pub fn submodule_paths(&self) -> &[String] { | |
| 1527 | self.submodule_paths_cache.get_or_init(|| build_helper::util::parse_gitmodules(&self.src)) | |
| 1528 | } | |
| 1529 | ||
| 1513 | 1530 | /// Ensure that a given step is built, returning its output. This will |
| 1514 | 1531 | /// cache the step, so it is safe (and good!) to call this as often as |
| 1515 | 1532 | /// needed to ensure that all dependencies are built. |
src/bootstrap/src/core/builder/tests.rs+86-10| ... | ... | @@ -15,11 +15,12 @@ static TEST_TRIPLE_2: &str = "i686-unknown-hurd-gnu"; |
| 15 | 15 | static TEST_TRIPLE_3: &str = "i686-unknown-netbsd"; |
| 16 | 16 | |
| 17 | 17 | fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { |
| 18 | configure_with_args(&[cmd.to_owned()], host, target) | |
| 18 | configure_with_args(&[cmd], host, target) | |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config { | |
| 22 | let mut config = Config::parse(Flags::parse(cmd)); | |
| 21 | fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config { | |
| 22 | let cmd = cmd.iter().copied().map(String::from).collect::<Vec<_>>(); | |
| 23 | let mut config = Config::parse(Flags::parse(&cmd)); | |
| 23 | 24 | // don't save toolstates |
| 24 | 25 | config.save_toolstates = None; |
| 25 | 26 | config.set_dry_run(DryRun::SelfCheck); |
| ... | ... | @@ -67,7 +68,7 @@ fn run_build(paths: &[PathBuf], config: Config) -> Cache { |
| 67 | 68 | fn check_cli<const N: usize>(paths: [&str; N]) { |
| 68 | 69 | run_build( |
| 69 | 70 | &paths.map(PathBuf::from), |
| 70 | configure_with_args(&paths.map(String::from), &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]), | |
| 71 | configure_with_args(&paths, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]), | |
| 71 | 72 | ); |
| 72 | 73 | } |
| 73 | 74 | |
| ... | ... | @@ -1000,8 +1001,7 @@ mod sysroot_target_dirs { |
| 1000 | 1001 | /// cg_gcc tests instead. |
| 1001 | 1002 | #[test] |
| 1002 | 1003 | fn test_test_compiler() { |
| 1003 | let cmd = &["test", "compiler"].map(str::to_owned); | |
| 1004 | let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); | |
| 1004 | let config = configure_with_args(&["test", "compiler"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); | |
| 1005 | 1005 | let cache = run_build(&config.paths.clone(), config); |
| 1006 | 1006 | |
| 1007 | 1007 | let compiler = cache.contains::<test::CrateLibrustc>(); |
| ... | ... | @@ -1034,8 +1034,7 @@ fn test_test_coverage() { |
| 1034 | 1034 | // Print each test case so that if one fails, the most recently printed |
| 1035 | 1035 | // case is the one that failed. |
| 1036 | 1036 | println!("Testing case: {cmd:?}"); |
| 1037 | let cmd = cmd.iter().copied().map(str::to_owned).collect::<Vec<_>>(); | |
| 1038 | let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); | |
| 1037 | let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); | |
| 1039 | 1038 | let mut cache = run_build(&config.paths.clone(), config); |
| 1040 | 1039 | |
| 1041 | 1040 | let modes = |
| ... | ... | @@ -1207,8 +1206,7 @@ fn test_get_tool_rustc_compiler() { |
| 1207 | 1206 | /// of `Any { .. }`. |
| 1208 | 1207 | #[test] |
| 1209 | 1208 | fn step_cycle_debug() { |
| 1210 | let cmd = ["run", "cyclic-step"].map(str::to_owned); | |
| 1211 | let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); | |
| 1209 | let config = configure_with_args(&["run", "cyclic-step"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); | |
| 1212 | 1210 | |
| 1213 | 1211 | let err = panic::catch_unwind(|| run_build(&config.paths.clone(), config)).unwrap_err(); |
| 1214 | 1212 | let err = err.downcast_ref::<String>().unwrap().as_str(); |
| ... | ... | @@ -1233,3 +1231,81 @@ fn any_debug() { |
| 1233 | 1231 | // Downcasting to the underlying type should succeed. |
| 1234 | 1232 | assert_eq!(x.downcast_ref::<MyStruct>(), Some(&MyStruct { x: 7 })); |
| 1235 | 1233 | } |
| 1234 | ||
| 1235 | /// The staging tests use insta for snapshot testing. | |
| 1236 | /// See bootstrap's README on how to bless the snapshots. | |
| 1237 | mod staging { | |
| 1238 | use crate::core::builder::tests::{ | |
| 1239 | TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build, | |
| 1240 | }; | |
| 1241 | ||
| 1242 | #[test] | |
| 1243 | fn build_compiler_stage_1() { | |
| 1244 | let mut cache = run_build( | |
| 1245 | &["compiler".into()], | |
| 1246 | configure_with_args(&["build", "--stage", "1"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]), | |
| 1247 | ); | |
| 1248 | let steps = cache.into_executed_steps(); | |
| 1249 | insta::assert_snapshot!(render_steps(&steps), @r" | |
| 1250 | [build] rustc 0 <target1> -> std 0 <target1> | |
| 1251 | [build] llvm <target1> | |
| 1252 | [build] rustc 0 <target1> -> rustc 1 <target1> | |
| 1253 | [build] rustc 0 <target1> -> rustc 1 <target1> | |
| 1254 | "); | |
| 1255 | } | |
| 1256 | } | |
| 1257 | ||
| 1258 | /// Renders the executed bootstrap steps for usage in snapshot tests with insta. | |
| 1259 | /// Only renders certain important steps. | |
| 1260 | /// Each value in `steps` should be a tuple of (Step, step output). | |
| 1261 | fn render_steps(steps: &[(Box<dyn Any>, Box<dyn Any>)]) -> String { | |
| 1262 | steps | |
| 1263 | .iter() | |
| 1264 | .filter_map(|(step, output)| { | |
| 1265 | // FIXME: implement an optional method on Step to produce metadata for test, instead | |
| 1266 | // of this downcasting | |
| 1267 | if let Some((rustc, output)) = downcast_step::<compile::Rustc>(step, output) { | |
| 1268 | Some(format!( | |
| 1269 | "[build] {} -> {}", | |
| 1270 | render_compiler(rustc.build_compiler), | |
| 1271 | // FIXME: return the correct stage from the `Rustc` step, now it behaves weirdly | |
| 1272 | render_compiler(Compiler::new(rustc.build_compiler.stage + 1, rustc.target)), | |
| 1273 | )) | |
| 1274 | } else if let Some((std, output)) = downcast_step::<compile::Std>(step, output) { | |
| 1275 | Some(format!( | |
| 1276 | "[build] {} -> std {} <{}>", | |
| 1277 | render_compiler(std.compiler), | |
| 1278 | std.compiler.stage, | |
| 1279 | std.target | |
| 1280 | )) | |
| 1281 | } else if let Some((llvm, output)) = downcast_step::<llvm::Llvm>(step, output) { | |
| 1282 | Some(format!("[build] llvm <{}>", llvm.target)) | |
| 1283 | } else { | |
| 1284 | None | |
| 1285 | } | |
| 1286 | }) | |
| 1287 | .map(|line| { | |
| 1288 | line.replace(TEST_TRIPLE_1, "target1") | |
| 1289 | .replace(TEST_TRIPLE_2, "target2") | |
| 1290 | .replace(TEST_TRIPLE_3, "target3") | |
| 1291 | }) | |
| 1292 | .collect::<Vec<_>>() | |
| 1293 | .join("\n") | |
| 1294 | } | |
| 1295 | ||
| 1296 | fn downcast_step<'a, S: Step>( | |
| 1297 | step: &'a Box<dyn Any>, | |
| 1298 | output: &'a Box<dyn Any>, | |
| 1299 | ) -> Option<(&'a S, &'a S::Output)> { | |
| 1300 | let Some(step) = step.downcast_ref::<S>() else { | |
| 1301 | return None; | |
| 1302 | }; | |
| 1303 | let Some(output) = output.downcast_ref::<S::Output>() else { | |
| 1304 | return None; | |
| 1305 | }; | |
| 1306 | Some((step, output)) | |
| 1307 | } | |
| 1308 | ||
| 1309 | fn render_compiler(compiler: Compiler) -> String { | |
| 1310 | format!("rustc {} <{}>", compiler.stage, compiler.host) | |
| 1311 | } |
src/bootstrap/src/lib.rs+22-27| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | //! also check out the `src/bootstrap/README.md` file for more information. |
| 18 | 18 | #![cfg_attr(test, allow(unused))] |
| 19 | 19 | |
| 20 | use std::cell::{Cell, RefCell}; | |
| 20 | use std::cell::Cell; | |
| 21 | 21 | use std::collections::{BTreeSet, HashMap, HashSet}; |
| 22 | 22 | use std::fmt::Display; |
| 23 | 23 | use std::path::{Path, PathBuf}; |
| ... | ... | @@ -189,10 +189,12 @@ pub struct Build { |
| 189 | 189 | |
| 190 | 190 | // Runtime state filled in later on |
| 191 | 191 | // C/C++ compilers and archiver for all targets |
| 192 | cc: RefCell<HashMap<TargetSelection, cc::Tool>>, | |
| 193 | cxx: RefCell<HashMap<TargetSelection, cc::Tool>>, | |
| 194 | ar: RefCell<HashMap<TargetSelection, PathBuf>>, | |
| 195 | ranlib: RefCell<HashMap<TargetSelection, PathBuf>>, | |
| 192 | cc: HashMap<TargetSelection, cc::Tool>, | |
| 193 | cxx: HashMap<TargetSelection, cc::Tool>, | |
| 194 | ar: HashMap<TargetSelection, PathBuf>, | |
| 195 | ranlib: HashMap<TargetSelection, PathBuf>, | |
| 196 | wasi_sdk_path: Option<PathBuf>, | |
| 197 | ||
| 196 | 198 | // Miscellaneous |
| 197 | 199 | // allow bidirectional lookups: both name -> path and path -> name |
| 198 | 200 | crates: HashMap<String, Crate>, |
| ... | ... | @@ -466,10 +468,11 @@ impl Build { |
| 466 | 468 | enzyme_info, |
| 467 | 469 | in_tree_llvm_info, |
| 468 | 470 | in_tree_gcc_info, |
| 469 | cc: RefCell::new(HashMap::new()), | |
| 470 | cxx: RefCell::new(HashMap::new()), | |
| 471 | ar: RefCell::new(HashMap::new()), | |
| 472 | ranlib: RefCell::new(HashMap::new()), | |
| 471 | cc: HashMap::new(), | |
| 472 | cxx: HashMap::new(), | |
| 473 | ar: HashMap::new(), | |
| 474 | ranlib: HashMap::new(), | |
| 475 | wasi_sdk_path: env::var_os("WASI_SDK_PATH").map(PathBuf::from), | |
| 473 | 476 | crates: HashMap::new(), |
| 474 | 477 | crate_paths: HashMap::new(), |
| 475 | 478 | is_sudo, |
| ... | ... | @@ -498,7 +501,7 @@ impl Build { |
| 498 | 501 | } |
| 499 | 502 | |
| 500 | 503 | build.verbose(|| println!("finding compilers")); |
| 501 | utils::cc_detect::find(&build); | |
| 504 | utils::cc_detect::fill_compilers(&mut build); | |
| 502 | 505 | // When running `setup`, the profile is about to change, so any requirements we have now may |
| 503 | 506 | // be different on the next invocation. Don't check for them until the next time x.py is |
| 504 | 507 | // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing. |
| ... | ... | @@ -593,14 +596,6 @@ impl Build { |
| 593 | 596 | } |
| 594 | 597 | } |
| 595 | 598 | |
| 596 | /// Updates all submodules, and exits with an error if submodule | |
| 597 | /// management is disabled and the submodule does not exist. | |
| 598 | pub fn require_and_update_all_submodules(&self) { | |
| 599 | for submodule in build_helper::util::parse_gitmodules(&self.src) { | |
| 600 | self.require_submodule(submodule, None); | |
| 601 | } | |
| 602 | } | |
| 603 | ||
| 604 | 599 | /// If any submodule has been initialized already, sync it unconditionally. |
| 605 | 600 | /// This avoids contributors checking in a submodule change by accident. |
| 606 | 601 | fn update_existing_submodules(&self) { |
| ... | ... | @@ -1143,17 +1138,17 @@ impl Build { |
| 1143 | 1138 | if self.config.dry_run() { |
| 1144 | 1139 | return PathBuf::new(); |
| 1145 | 1140 | } |
| 1146 | self.cc.borrow()[&target].path().into() | |
| 1141 | self.cc[&target].path().into() | |
| 1147 | 1142 | } |
| 1148 | 1143 | |
| 1149 | 1144 | /// Returns the internal `cc::Tool` for the C compiler. |
| 1150 | 1145 | fn cc_tool(&self, target: TargetSelection) -> Tool { |
| 1151 | self.cc.borrow()[&target].clone() | |
| 1146 | self.cc[&target].clone() | |
| 1152 | 1147 | } |
| 1153 | 1148 | |
| 1154 | 1149 | /// Returns the internal `cc::Tool` for the C++ compiler. |
| 1155 | 1150 | fn cxx_tool(&self, target: TargetSelection) -> Tool { |
| 1156 | self.cxx.borrow()[&target].clone() | |
| 1151 | self.cxx[&target].clone() | |
| 1157 | 1152 | } |
| 1158 | 1153 | |
| 1159 | 1154 | /// Returns C flags that `cc-rs` thinks should be enabled for the |
| ... | ... | @@ -1163,8 +1158,8 @@ impl Build { |
| 1163 | 1158 | return Vec::new(); |
| 1164 | 1159 | } |
| 1165 | 1160 | let base = match c { |
| 1166 | CLang::C => self.cc.borrow()[&target].clone(), | |
| 1167 | CLang::Cxx => self.cxx.borrow()[&target].clone(), | |
| 1161 | CLang::C => self.cc[&target].clone(), | |
| 1162 | CLang::Cxx => self.cxx[&target].clone(), | |
| 1168 | 1163 | }; |
| 1169 | 1164 | |
| 1170 | 1165 | // Filter out -O and /O (the optimization flags) that we picked up |
| ... | ... | @@ -1217,7 +1212,7 @@ impl Build { |
| 1217 | 1212 | if self.config.dry_run() { |
| 1218 | 1213 | return None; |
| 1219 | 1214 | } |
| 1220 | self.ar.borrow().get(&target).cloned() | |
| 1215 | self.ar.get(&target).cloned() | |
| 1221 | 1216 | } |
| 1222 | 1217 | |
| 1223 | 1218 | /// Returns the path to the `ranlib` utility for the target specified. |
| ... | ... | @@ -1225,7 +1220,7 @@ impl Build { |
| 1225 | 1220 | if self.config.dry_run() { |
| 1226 | 1221 | return None; |
| 1227 | 1222 | } |
| 1228 | self.ranlib.borrow().get(&target).cloned() | |
| 1223 | self.ranlib.get(&target).cloned() | |
| 1229 | 1224 | } |
| 1230 | 1225 | |
| 1231 | 1226 | /// Returns the path to the C++ compiler for the target specified. |
| ... | ... | @@ -1233,7 +1228,7 @@ impl Build { |
| 1233 | 1228 | if self.config.dry_run() { |
| 1234 | 1229 | return Ok(PathBuf::new()); |
| 1235 | 1230 | } |
| 1236 | match self.cxx.borrow().get(&target) { | |
| 1231 | match self.cxx.get(&target) { | |
| 1237 | 1232 | Some(p) => Ok(p.path().into()), |
| 1238 | 1233 | None => Err(format!("target `{target}` is not configured as a host, only as a target")), |
| 1239 | 1234 | } |
| ... | ... | @@ -1250,7 +1245,7 @@ impl Build { |
| 1250 | 1245 | } else if target.contains("vxworks") { |
| 1251 | 1246 | // need to use CXX compiler as linker to resolve the exception functions |
| 1252 | 1247 | // that are only existed in CXX libraries |
| 1253 | Some(self.cxx.borrow()[&target].path().into()) | |
| 1248 | Some(self.cxx[&target].path().into()) | |
| 1254 | 1249 | } else if !self.config.is_host_target(target) |
| 1255 | 1250 | && helpers::use_host_linker(target) |
| 1256 | 1251 | && !target.is_msvc() |
src/bootstrap/src/utils/build_stamp/tests.rs+10-14| ... | ... | @@ -1,32 +1,28 @@ |
| 1 | 1 | use std::path::PathBuf; |
| 2 | 2 | |
| 3 | use crate::{BuildStamp, Config, Flags}; | |
| 3 | use tempfile::TempDir; | |
| 4 | 4 | |
| 5 | fn temp_dir() -> PathBuf { | |
| 6 | let config = | |
| 7 | Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()])); | |
| 8 | config.tempdir() | |
| 9 | } | |
| 5 | use crate::{BuildStamp, Config, Flags}; | |
| 10 | 6 | |
| 11 | 7 | #[test] |
| 12 | 8 | #[should_panic(expected = "prefix can not start or end with '.'")] |
| 13 | 9 | fn test_with_invalid_prefix() { |
| 14 | let dir = temp_dir(); | |
| 15 | BuildStamp::new(&dir).with_prefix(".invalid"); | |
| 10 | let dir = TempDir::new().unwrap(); | |
| 11 | BuildStamp::new(dir.path()).with_prefix(".invalid"); | |
| 16 | 12 | } |
| 17 | 13 | |
| 18 | 14 | #[test] |
| 19 | 15 | #[should_panic(expected = "prefix can not start or end with '.'")] |
| 20 | 16 | fn test_with_invalid_prefix2() { |
| 21 | let dir = temp_dir(); | |
| 22 | BuildStamp::new(&dir).with_prefix("invalid."); | |
| 17 | let dir = TempDir::new().unwrap(); | |
| 18 | BuildStamp::new(dir.path()).with_prefix("invalid."); | |
| 23 | 19 | } |
| 24 | 20 | |
| 25 | 21 | #[test] |
| 26 | 22 | fn test_is_up_to_date() { |
| 27 | let dir = temp_dir(); | |
| 23 | let dir = TempDir::new().unwrap(); | |
| 28 | 24 | |
| 29 | let mut build_stamp = BuildStamp::new(&dir).add_stamp("v1.0.0"); | |
| 25 | let mut build_stamp = BuildStamp::new(dir.path()).add_stamp("v1.0.0"); | |
| 30 | 26 | build_stamp.write().unwrap(); |
| 31 | 27 | |
| 32 | 28 | assert!( |
| ... | ... | @@ -45,9 +41,9 @@ fn test_is_up_to_date() { |
| 45 | 41 | |
| 46 | 42 | #[test] |
| 47 | 43 | fn test_with_prefix() { |
| 48 | let dir = temp_dir(); | |
| 44 | let dir = TempDir::new().unwrap(); | |
| 49 | 45 | |
| 50 | let stamp = BuildStamp::new(&dir).add_stamp("v1.0.0"); | |
| 46 | let stamp = BuildStamp::new(dir.path()).add_stamp("v1.0.0"); | |
| 51 | 47 | assert_eq!(stamp.path.file_name().unwrap(), ".stamp"); |
| 52 | 48 | |
| 53 | 49 | let stamp = stamp.with_prefix("test"); |
src/bootstrap/src/utils/cache.rs+29-10| ... | ... | @@ -17,6 +17,7 @@ use std::borrow::Borrow; |
| 17 | 17 | use std::cell::RefCell; |
| 18 | 18 | use std::cmp::Ordering; |
| 19 | 19 | use std::collections::HashMap; |
| 20 | use std::fmt::Debug; | |
| 20 | 21 | use std::hash::{Hash, Hasher}; |
| 21 | 22 | use std::marker::PhantomData; |
| 22 | 23 | use std::ops::Deref; |
| ... | ... | @@ -208,25 +209,30 @@ pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default); |
| 208 | 209 | /// any type in its output. It is a write-once cache; values are never evicted, |
| 209 | 210 | /// which means that references to the value can safely be returned from the |
| 210 | 211 | /// `get()` method. |
| 211 | #[derive(Debug)] | |
| 212 | pub struct Cache( | |
| 213 | RefCell< | |
| 212 | #[derive(Debug, Default)] | |
| 213 | pub struct Cache { | |
| 214 | cache: RefCell< | |
| 214 | 215 | HashMap< |
| 215 | 216 | TypeId, |
| 216 | 217 | Box<dyn Any>, // actually a HashMap<Step, Interned<Step::Output>> |
| 217 | 218 | >, |
| 218 | 219 | >, |
| 219 | ); | |
| 220 | #[cfg(test)] | |
| 221 | /// Contains steps in the same order in which they were executed | |
| 222 | /// Useful for tests | |
| 223 | /// Tuples (step, step output) | |
| 224 | executed_steps: RefCell<Vec<(Box<dyn Any>, Box<dyn Any>)>>, | |
| 225 | } | |
| 220 | 226 | |
| 221 | 227 | impl Cache { |
| 222 | 228 | /// Creates a new empty cache. |
| 223 | 229 | pub fn new() -> Cache { |
| 224 | Cache(RefCell::new(HashMap::new())) | |
| 230 | Cache::default() | |
| 225 | 231 | } |
| 226 | 232 | |
| 227 | 233 | /// Stores the result of a computation step in the cache. |
| 228 | 234 | pub fn put<S: Step>(&self, step: S, value: S::Output) { |
| 229 | let mut cache = self.0.borrow_mut(); | |
| 235 | let mut cache = self.cache.borrow_mut(); | |
| 230 | 236 | let type_id = TypeId::of::<S>(); |
| 231 | 237 | let stepcache = cache |
| 232 | 238 | .entry(type_id) |
| ... | ... | @@ -234,12 +240,20 @@ impl Cache { |
| 234 | 240 | .downcast_mut::<HashMap<S, S::Output>>() |
| 235 | 241 | .expect("invalid type mapped"); |
| 236 | 242 | assert!(!stepcache.contains_key(&step), "processing {step:?} a second time"); |
| 243 | ||
| 244 | #[cfg(test)] | |
| 245 | { | |
| 246 | let step: Box<dyn Any> = Box::new(step.clone()); | |
| 247 | let output: Box<dyn Any> = Box::new(value.clone()); | |
| 248 | self.executed_steps.borrow_mut().push((step, output)); | |
| 249 | } | |
| 250 | ||
| 237 | 251 | stepcache.insert(step, value); |
| 238 | 252 | } |
| 239 | 253 | |
| 240 | 254 | /// Retrieves a cached result for the given step, if available. |
| 241 | 255 | pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> { |
| 242 | let mut cache = self.0.borrow_mut(); | |
| 256 | let mut cache = self.cache.borrow_mut(); | |
| 243 | 257 | let type_id = TypeId::of::<S>(); |
| 244 | 258 | let stepcache = cache |
| 245 | 259 | .entry(type_id) |
| ... | ... | @@ -252,8 +266,8 @@ impl Cache { |
| 252 | 266 | |
| 253 | 267 | #[cfg(test)] |
| 254 | 268 | impl Cache { |
| 255 | pub fn all<S: Ord + Clone + Step>(&mut self) -> Vec<(S, S::Output)> { | |
| 256 | let cache = self.0.get_mut(); | |
| 269 | pub fn all<S: Ord + Step>(&mut self) -> Vec<(S, S::Output)> { | |
| 270 | let cache = self.cache.get_mut(); | |
| 257 | 271 | let type_id = TypeId::of::<S>(); |
| 258 | 272 | let mut v = cache |
| 259 | 273 | .remove(&type_id) |
| ... | ... | @@ -265,7 +279,12 @@ impl Cache { |
| 265 | 279 | } |
| 266 | 280 | |
| 267 | 281 | pub fn contains<S: Step>(&self) -> bool { |
| 268 | self.0.borrow().contains_key(&TypeId::of::<S>()) | |
| 282 | self.cache.borrow().contains_key(&TypeId::of::<S>()) | |
| 283 | } | |
| 284 | ||
| 285 | #[cfg(test)] | |
| 286 | pub fn into_executed_steps(mut self) -> Vec<(Box<dyn Any>, Box<dyn Any>)> { | |
| 287 | mem::take(&mut self.executed_steps.borrow_mut()) | |
| 269 | 288 | } |
| 270 | 289 | } |
| 271 | 290 |
src/bootstrap/src/utils/cc_detect.rs+12-9| ... | ... | @@ -61,8 +61,8 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { |
| 61 | 61 | /// |
| 62 | 62 | /// This function determines which targets need a C compiler (and, if needed, a C++ compiler) |
| 63 | 63 | /// by combining the primary build target, host targets, and any additional targets. For |
| 64 | /// each target, it calls [`find_target`] to configure the necessary compiler tools. | |
| 65 | pub fn find(build: &Build) { | |
| 64 | /// each target, it calls [`fill_target_compiler`] to configure the necessary compiler tools. | |
| 65 | pub fn fill_compilers(build: &mut Build) { | |
| 66 | 66 | let targets: HashSet<_> = match build.config.cmd { |
| 67 | 67 | // We don't need to check cross targets for these commands. |
| 68 | 68 | crate::Subcommand::Clean { .. } |
| ... | ... | @@ -87,7 +87,7 @@ pub fn find(build: &Build) { |
| 87 | 87 | }; |
| 88 | 88 | |
| 89 | 89 | for target in targets.into_iter() { |
| 90 | find_target(build, target); | |
| 90 | fill_target_compiler(build, target); | |
| 91 | 91 | } |
| 92 | 92 | } |
| 93 | 93 | |
| ... | ... | @@ -96,7 +96,7 @@ pub fn find(build: &Build) { |
| 96 | 96 | /// This function uses both user-specified configuration (from `bootstrap.toml`) and auto-detection |
| 97 | 97 | /// logic to determine the correct C/C++ compilers for the target. It also determines the appropriate |
| 98 | 98 | /// archiver (`ar`) and sets up additional compilation flags (both handled and unhandled). |
| 99 | pub fn find_target(build: &Build, target: TargetSelection) { | |
| 99 | pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { | |
| 100 | 100 | let mut cfg = new_cc_build(build, target); |
| 101 | 101 | let config = build.config.target_config.get(&target); |
| 102 | 102 | if let Some(cc) = config |
| ... | ... | @@ -113,7 +113,7 @@ pub fn find_target(build: &Build, target: TargetSelection) { |
| 113 | 113 | cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok() |
| 114 | 114 | }; |
| 115 | 115 | |
| 116 | build.cc.borrow_mut().insert(target, compiler.clone()); | |
| 116 | build.cc.insert(target, compiler.clone()); | |
| 117 | 117 | let mut cflags = build.cc_handled_clags(target, CLang::C); |
| 118 | 118 | cflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C)); |
| 119 | 119 | |
| ... | ... | @@ -135,7 +135,7 @@ pub fn find_target(build: &Build, target: TargetSelection) { |
| 135 | 135 | // for VxWorks, record CXX compiler which will be used in lib.rs:linker() |
| 136 | 136 | if cxx_configured || target.contains("vxworks") { |
| 137 | 137 | let compiler = cfg.get_compiler(); |
| 138 | build.cxx.borrow_mut().insert(target, compiler); | |
| 138 | build.cxx.insert(target, compiler); | |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | 141 | build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); |
| ... | ... | @@ -148,11 +148,11 @@ pub fn find_target(build: &Build, target: TargetSelection) { |
| 148 | 148 | } |
| 149 | 149 | if let Some(ar) = ar { |
| 150 | 150 | build.verbose(|| println!("AR_{} = {ar:?}", target.triple)); |
| 151 | build.ar.borrow_mut().insert(target, ar); | |
| 151 | build.ar.insert(target, ar); | |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | 154 | if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) { |
| 155 | build.ranlib.borrow_mut().insert(target, ranlib); | |
| 155 | build.ranlib.insert(target, ranlib); | |
| 156 | 156 | } |
| 157 | 157 | } |
| 158 | 158 | |
| ... | ... | @@ -221,7 +221,10 @@ fn default_compiler( |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | 223 | t if t.contains("-wasi") => { |
| 224 | let root = PathBuf::from(std::env::var_os("WASI_SDK_PATH")?); | |
| 224 | let root = build | |
| 225 | .wasi_sdk_path | |
| 226 | .as_ref() | |
| 227 | .expect("WASI_SDK_PATH mut be configured for a -wasi target"); | |
| 225 | 228 | let compiler = match compiler { |
| 226 | 229 | Language::C => format!("{t}-clang"), |
| 227 | 230 | Language::CPlusPlus => format!("{t}-clang++"), |
src/bootstrap/src/utils/cc_detect/tests.rs+14-22| ... | ... | @@ -77,11 +77,11 @@ fn test_new_cc_build() { |
| 77 | 77 | |
| 78 | 78 | #[test] |
| 79 | 79 | fn test_default_compiler_wasi() { |
| 80 | let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); | |
| 80 | let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); | |
| 81 | 81 | let target = TargetSelection::from_user("wasm32-wasi"); |
| 82 | 82 | let wasi_sdk = PathBuf::from("/wasi-sdk"); |
| 83 | // SAFETY: bootstrap tests run on a single thread | |
| 84 | unsafe { env::set_var("WASI_SDK_PATH", &wasi_sdk) }; | |
| 83 | build.wasi_sdk_path = Some(wasi_sdk.clone()); | |
| 84 | ||
| 85 | 85 | let mut cfg = cc::Build::new(); |
| 86 | 86 | if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { |
| 87 | 87 | let expected = { |
| ... | ... | @@ -94,10 +94,6 @@ fn test_default_compiler_wasi() { |
| 94 | 94 | "default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set" |
| 95 | 95 | ); |
| 96 | 96 | } |
| 97 | // SAFETY: bootstrap tests run on a single thread | |
| 98 | unsafe { | |
| 99 | env::remove_var("WASI_SDK_PATH"); | |
| 100 | } | |
| 101 | 97 | } |
| 102 | 98 | |
| 103 | 99 | #[test] |
| ... | ... | @@ -119,18 +115,14 @@ fn test_find_target_with_config() { |
| 119 | 115 | target_config.ar = Some(PathBuf::from("dummy-ar")); |
| 120 | 116 | target_config.ranlib = Some(PathBuf::from("dummy-ranlib")); |
| 121 | 117 | build.config.target_config.insert(target.clone(), target_config); |
| 122 | find_target(&build, target.clone()); | |
| 123 | let binding = build.cc.borrow(); | |
| 124 | let cc_tool = binding.get(&target).unwrap(); | |
| 118 | fill_target_compiler(&mut build, target.clone()); | |
| 119 | let cc_tool = build.cc.get(&target).unwrap(); | |
| 125 | 120 | assert_eq!(cc_tool.path(), &PathBuf::from("dummy-cc")); |
| 126 | let binding = build.cxx.borrow(); | |
| 127 | let cxx_tool = binding.get(&target).unwrap(); | |
| 121 | let cxx_tool = build.cxx.get(&target).unwrap(); | |
| 128 | 122 | assert_eq!(cxx_tool.path(), &PathBuf::from("dummy-cxx")); |
| 129 | let binding = build.ar.borrow(); | |
| 130 | let ar = binding.get(&target).unwrap(); | |
| 123 | let ar = build.ar.get(&target).unwrap(); | |
| 131 | 124 | assert_eq!(ar, &PathBuf::from("dummy-ar")); |
| 132 | let binding = build.ranlib.borrow(); | |
| 133 | let ranlib = binding.get(&target).unwrap(); | |
| 125 | let ranlib = build.ranlib.get(&target).unwrap(); | |
| 134 | 126 | assert_eq!(ranlib, &PathBuf::from("dummy-ranlib")); |
| 135 | 127 | } |
| 136 | 128 | |
| ... | ... | @@ -139,12 +131,12 @@ fn test_find_target_without_config() { |
| 139 | 131 | let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); |
| 140 | 132 | let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); |
| 141 | 133 | build.config.target_config.clear(); |
| 142 | find_target(&build, target.clone()); | |
| 143 | assert!(build.cc.borrow().contains_key(&target)); | |
| 134 | fill_target_compiler(&mut build, target.clone()); | |
| 135 | assert!(build.cc.contains_key(&target)); | |
| 144 | 136 | if !target.triple.contains("vxworks") { |
| 145 | assert!(build.cxx.borrow().contains_key(&target)); | |
| 137 | assert!(build.cxx.contains_key(&target)); | |
| 146 | 138 | } |
| 147 | assert!(build.ar.borrow().contains_key(&target)); | |
| 139 | assert!(build.ar.contains_key(&target)); | |
| 148 | 140 | } |
| 149 | 141 | |
| 150 | 142 | #[test] |
| ... | ... | @@ -154,8 +146,8 @@ fn test_find() { |
| 154 | 146 | let target2 = TargetSelection::from_user("x86_64-unknown-openbsd"); |
| 155 | 147 | build.targets.push(target1.clone()); |
| 156 | 148 | build.hosts.push(target2.clone()); |
| 157 | find(&build); | |
| 149 | fill_compilers(&mut build); | |
| 158 | 150 | for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.host_target)) { |
| 159 | assert!(build.cc.borrow().contains_key(t), "CC not set for target {}", t.triple); | |
| 151 | assert!(build.cc.contains_key(t), "CC not set for target {}", t.triple); | |
| 160 | 152 | } |
| 161 | 153 | } |
src/bootstrap/src/utils/helpers.rs+1-1| ... | ... | @@ -98,7 +98,7 @@ pub fn is_dylib(path: &Path) -> bool { |
| 98 | 98 | |
| 99 | 99 | /// Return the path to the containing submodule if available. |
| 100 | 100 | pub fn submodule_path_of(builder: &Builder<'_>, path: &str) -> Option<String> { |
| 101 | let submodule_paths = build_helper::util::parse_gitmodules(&builder.src); | |
| 101 | let submodule_paths = builder.submodule_paths(); | |
| 102 | 102 | submodule_paths.iter().find_map(|submodule_path| { |
| 103 | 103 | if path.starts_with(submodule_path) { Some(submodule_path.to_string()) } else { None } |
| 104 | 104 | }) |
src/bootstrap/src/utils/shared_helpers.rs+3| ... | ... | @@ -6,6 +6,9 @@ |
| 6 | 6 | |
| 7 | 7 | #![allow(dead_code)] |
| 8 | 8 | |
| 9 | #[cfg(test)] | |
| 10 | mod tests; | |
| 11 | ||
| 9 | 12 | use std::env; |
| 10 | 13 | use std::ffi::OsString; |
| 11 | 14 | use std::fs::OpenOptions; |
src/bootstrap/src/utils/shared_helpers/tests.rs created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | use crate::utils::shared_helpers::parse_value_from_args; | |
| 2 | ||
| 3 | #[test] | |
| 4 | fn test_parse_value_from_args() { | |
| 5 | let args = vec![ | |
| 6 | "--stage".into(), | |
| 7 | "1".into(), | |
| 8 | "--version".into(), | |
| 9 | "2".into(), | |
| 10 | "--target".into(), | |
| 11 | "x86_64-unknown-linux".into(), | |
| 12 | ]; | |
| 13 | ||
| 14 | assert_eq!(parse_value_from_args(args.as_slice(), "--stage").unwrap(), "1"); | |
| 15 | assert_eq!(parse_value_from_args(args.as_slice(), "--version").unwrap(), "2"); | |
| 16 | assert_eq!(parse_value_from_args(args.as_slice(), "--target").unwrap(), "x86_64-unknown-linux"); | |
| 17 | assert!(parse_value_from_args(args.as_slice(), "random-key").is_none()); | |
| 18 | ||
| 19 | let args = vec![ | |
| 20 | "app-name".into(), | |
| 21 | "--key".into(), | |
| 22 | "value".into(), | |
| 23 | "random-value".into(), | |
| 24 | "--sysroot=/x/y/z".into(), | |
| 25 | ]; | |
| 26 | assert_eq!(parse_value_from_args(args.as_slice(), "--key").unwrap(), "value"); | |
| 27 | assert_eq!(parse_value_from_args(args.as_slice(), "--sysroot").unwrap(), "/x/y/z"); | |
| 28 | } |
src/bootstrap/src/utils/tests/mod.rs+2-1| ... | ... | @@ -1,2 +1,3 @@ |
| 1 | //! This module contains shared utilities for bootstrap tests. | |
| 2 | ||
| 1 | 3 | pub mod git; |
| 2 | mod shared_helpers_tests; |
src/bootstrap/src/utils/tests/shared_helpers_tests.rs deleted-35| ... | ... | @@ -1,35 +0,0 @@ |
| 1 | //! The `shared_helpers` module can't have its own tests submodule, because | |
| 2 | //! that would cause problems for the shim binaries that include it via | |
| 3 | //! `#[path]`, so instead those unit tests live here. | |
| 4 | //! | |
| 5 | //! To prevent tidy from complaining about this file not being named `tests.rs`, | |
| 6 | //! it lives inside a submodule directory named `tests`. | |
| 7 | ||
| 8 | use crate::utils::shared_helpers::parse_value_from_args; | |
| 9 | ||
| 10 | #[test] | |
| 11 | fn test_parse_value_from_args() { | |
| 12 | let args = vec![ | |
| 13 | "--stage".into(), | |
| 14 | "1".into(), | |
| 15 | "--version".into(), | |
| 16 | "2".into(), | |
| 17 | "--target".into(), | |
| 18 | "x86_64-unknown-linux".into(), | |
| 19 | ]; | |
| 20 | ||
| 21 | assert_eq!(parse_value_from_args(args.as_slice(), "--stage").unwrap(), "1"); | |
| 22 | assert_eq!(parse_value_from_args(args.as_slice(), "--version").unwrap(), "2"); | |
| 23 | assert_eq!(parse_value_from_args(args.as_slice(), "--target").unwrap(), "x86_64-unknown-linux"); | |
| 24 | assert!(parse_value_from_args(args.as_slice(), "random-key").is_none()); | |
| 25 | ||
| 26 | let args = vec![ | |
| 27 | "app-name".into(), | |
| 28 | "--key".into(), | |
| 29 | "value".into(), | |
| 30 | "random-value".into(), | |
| 31 | "--sysroot=/x/y/z".into(), | |
| 32 | ]; | |
| 33 | assert_eq!(parse_value_from_args(args.as_slice(), "--key").unwrap(), "value"); | |
| 34 | assert_eq!(parse_value_from_args(args.as_slice(), "--sysroot").unwrap(), "/x/y/z"); | |
| 35 | } |
src/build_helper/src/util.rs+10-16| ... | ... | @@ -2,7 +2,6 @@ use std::fs::File; |
| 2 | 2 | use std::io::{BufRead, BufReader}; |
| 3 | 3 | use std::path::Path; |
| 4 | 4 | use std::process::Command; |
| 5 | use std::sync::OnceLock; | |
| 6 | 5 | |
| 7 | 6 | /// Invokes `build_helper::util::detail_exit` with `cfg!(test)` |
| 8 | 7 | /// |
| ... | ... | @@ -51,25 +50,20 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> { |
| 51 | 50 | } |
| 52 | 51 | |
| 53 | 52 | /// Returns the submodule paths from the `.gitmodules` file in the given directory. |
| 54 | pub fn parse_gitmodules(target_dir: &Path) -> &[String] { | |
| 55 | static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new(); | |
| 53 | pub fn parse_gitmodules(target_dir: &Path) -> Vec<String> { | |
| 56 | 54 | let gitmodules = target_dir.join(".gitmodules"); |
| 57 | 55 | assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display()); |
| 58 | 56 | |
| 59 | let init_submodules_paths = || { | |
| 60 | let file = File::open(gitmodules).unwrap(); | |
| 57 | let file = File::open(gitmodules).unwrap(); | |
| 61 | 58 | |
| 62 | let mut submodules_paths = vec![]; | |
| 63 | for line in BufReader::new(file).lines().map_while(Result::ok) { | |
| 64 | let line = line.trim(); | |
| 65 | if line.starts_with("path") { | |
| 66 | let actual_path = line.split(' ').last().expect("Couldn't get value of path"); | |
| 67 | submodules_paths.push(actual_path.to_owned()); | |
| 68 | } | |
| 59 | let mut submodules_paths = vec![]; | |
| 60 | for line in BufReader::new(file).lines().map_while(Result::ok) { | |
| 61 | let line = line.trim(); | |
| 62 | if line.starts_with("path") { | |
| 63 | let actual_path = line.split(' ').last().expect("Couldn't get value of path"); | |
| 64 | submodules_paths.push(actual_path.to_owned()); | |
| 69 | 65 | } |
| 66 | } | |
| 70 | 67 | |
| 71 | submodules_paths | |
| 72 | }; | |
| 73 | ||
| 74 | SUBMODULES_PATHS.get_or_init(|| init_submodules_paths()) | |
| 68 | submodules_paths | |
| 75 | 69 | } |
src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile-4| ... | ... | @@ -22,10 +22,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 22 | 22 | COPY scripts/sccache.sh /scripts/ |
| 23 | 23 | RUN sh /scripts/sccache.sh |
| 24 | 24 | |
| 25 | RUN mkdir -p /config | |
| 26 | RUN echo "[rust]" > /config/nopt-std-config.toml | |
| 27 | RUN echo "optimize = false" >> /config/nopt-std-config.toml | |
| 28 | ||
| 29 | 25 | ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests |
| 30 | 26 | ARG SCRIPT_ARG |
| 31 | 27 | COPY scripts/stage_2_test_set1.sh /scripts/ |
src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile+1-5| ... | ... | @@ -22,12 +22,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 22 | 22 | COPY scripts/sccache.sh /scripts/ |
| 23 | 23 | RUN sh /scripts/sccache.sh |
| 24 | 24 | |
| 25 | RUN mkdir -p /config | |
| 26 | RUN echo "[rust]" > /config/nopt-std-config.toml | |
| 27 | RUN echo "optimize = false" >> /config/nopt-std-config.toml | |
| 28 | ||
| 29 | 25 | ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \ |
| 30 | 26 | --disable-optimize-tests \ |
| 31 | 27 | --set rust.test-compare-mode |
| 32 | ENV SCRIPT python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std \ | |
| 28 | ENV SCRIPT python3 ../x.py test --stage 1 --set rust.optimize=false library/std \ | |
| 33 | 29 | && python3 ../x.py --stage 2 test |
src/ci/github-actions/jobs.yml+1-1| ... | ... | @@ -300,7 +300,7 @@ auto: |
| 300 | 300 | env: |
| 301 | 301 | IMAGE: i686-gnu-nopt |
| 302 | 302 | DOCKER_SCRIPT: >- |
| 303 | python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std && | |
| 303 | python3 ../x.py test --stage 1 --set rust.optimize=false library/std && | |
| 304 | 304 | /scripts/stage_2_test_set2.sh |
| 305 | 305 | <<: *job-linux-4c |
| 306 | 306 |
src/tools/miri/src/lib.rs+1-1| ... | ... | @@ -16,7 +16,7 @@ |
| 16 | 16 | #![feature(unqualified_local_imports)] |
| 17 | 17 | #![feature(derive_coerce_pointee)] |
| 18 | 18 | #![feature(arbitrary_self_types)] |
| 19 | #![feature(file_lock)] | |
| 19 | #![cfg_attr(bootstrap, feature(file_lock))] | |
| 20 | 20 | // Configure clippy and other lints |
| 21 | 21 | #![allow( |
| 22 | 22 | clippy::collapsible_else_if, |
src/tools/miri/tests/pass/shims/fs.rs-1| ... | ... | @@ -2,7 +2,6 @@ |
| 2 | 2 | |
| 3 | 3 | #![feature(io_error_more)] |
| 4 | 4 | #![feature(io_error_uncategorized)] |
| 5 | #![feature(file_lock)] | |
| 6 | 5 | |
| 7 | 6 | use std::collections::BTreeMap; |
| 8 | 7 | use std::ffi::OsString; |
src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs+1-1| ... | ... | @@ -486,7 +486,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ |
| 486 | 486 | rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing, |
| 487 | 487 | INTERNAL_UNSTABLE |
| 488 | 488 | ), |
| 489 | // Do not const-check this function's body. It will always get replaced during CTFE. | |
| 489 | // Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`. | |
| 490 | 490 | rustc_attr!( |
| 491 | 491 | rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE |
| 492 | 492 | ), |
tests/ui-fulldeps/stable-mir/check_variant.rs created+183| ... | ... | @@ -0,0 +1,183 @@ |
| 1 | //@ run-pass | |
| 2 | //! Test that users are able to use stable mir APIs to retrieve | |
| 3 | //! discriminant value and type for AdtDef and Coroutine variants | |
| 4 | ||
| 5 | //@ ignore-stage1 | |
| 6 | //@ ignore-cross-compile | |
| 7 | //@ ignore-remote | |
| 8 | //@ edition: 2024 | |
| 9 | ||
| 10 | #![feature(rustc_private)] | |
| 11 | #![feature(assert_matches)] | |
| 12 | ||
| 13 | extern crate rustc_middle; | |
| 14 | #[macro_use] | |
| 15 | extern crate rustc_smir; | |
| 16 | extern crate rustc_driver; | |
| 17 | extern crate rustc_interface; | |
| 18 | extern crate stable_mir; | |
| 19 | ||
| 20 | use std::io::Write; | |
| 21 | use std::ops::ControlFlow; | |
| 22 | ||
| 23 | use stable_mir::CrateItem; | |
| 24 | use stable_mir::crate_def::CrateDef; | |
| 25 | use stable_mir::mir::{AggregateKind, Rvalue, Statement, StatementKind}; | |
| 26 | use stable_mir::ty::{IntTy, RigidTy, Ty}; | |
| 27 | ||
| 28 | const CRATE_NAME: &str = "crate_variant_ty"; | |
| 29 | ||
| 30 | /// Test if we can retrieve discriminant info for different types. | |
| 31 | fn test_def_tys() -> ControlFlow<()> { | |
| 32 | check_adt_mono(); | |
| 33 | check_adt_poly(); | |
| 34 | check_adt_poly2(); | |
| 35 | ||
| 36 | ControlFlow::Continue(()) | |
| 37 | } | |
| 38 | ||
| 39 | fn check_adt_mono() { | |
| 40 | let mono = get_fn("mono").expect_body(); | |
| 41 | ||
| 42 | check_statement_is_aggregate_assign( | |
| 43 | &mono.blocks[0].statements[0], | |
| 44 | 0, | |
| 45 | RigidTy::Int(IntTy::Isize), | |
| 46 | ); | |
| 47 | check_statement_is_aggregate_assign( | |
| 48 | &mono.blocks[1].statements[0], | |
| 49 | 1, | |
| 50 | RigidTy::Int(IntTy::Isize), | |
| 51 | ); | |
| 52 | check_statement_is_aggregate_assign( | |
| 53 | &mono.blocks[2].statements[0], | |
| 54 | 2, | |
| 55 | RigidTy::Int(IntTy::Isize), | |
| 56 | ); | |
| 57 | } | |
| 58 | ||
| 59 | fn check_adt_poly() { | |
| 60 | let poly = get_fn("poly").expect_body(); | |
| 61 | ||
| 62 | check_statement_is_aggregate_assign( | |
| 63 | &poly.blocks[0].statements[0], | |
| 64 | 0, | |
| 65 | RigidTy::Int(IntTy::Isize), | |
| 66 | ); | |
| 67 | check_statement_is_aggregate_assign( | |
| 68 | &poly.blocks[1].statements[0], | |
| 69 | 1, | |
| 70 | RigidTy::Int(IntTy::Isize), | |
| 71 | ); | |
| 72 | check_statement_is_aggregate_assign( | |
| 73 | &poly.blocks[2].statements[0], | |
| 74 | 2, | |
| 75 | RigidTy::Int(IntTy::Isize), | |
| 76 | ); | |
| 77 | } | |
| 78 | ||
| 79 | fn check_adt_poly2() { | |
| 80 | let poly = get_fn("poly2").expect_body(); | |
| 81 | ||
| 82 | check_statement_is_aggregate_assign( | |
| 83 | &poly.blocks[0].statements[0], | |
| 84 | 0, | |
| 85 | RigidTy::Int(IntTy::Isize), | |
| 86 | ); | |
| 87 | check_statement_is_aggregate_assign( | |
| 88 | &poly.blocks[1].statements[0], | |
| 89 | 1, | |
| 90 | RigidTy::Int(IntTy::Isize), | |
| 91 | ); | |
| 92 | check_statement_is_aggregate_assign( | |
| 93 | &poly.blocks[2].statements[0], | |
| 94 | 2, | |
| 95 | RigidTy::Int(IntTy::Isize), | |
| 96 | ); | |
| 97 | } | |
| 98 | ||
| 99 | fn get_fn(name: &str) -> CrateItem { | |
| 100 | stable_mir::all_local_items().into_iter().find(|it| it.name().eq(name)).unwrap() | |
| 101 | } | |
| 102 | ||
| 103 | fn check_statement_is_aggregate_assign( | |
| 104 | statement: &Statement, | |
| 105 | expected_discr_val: u128, | |
| 106 | expected_discr_ty: RigidTy, | |
| 107 | ) { | |
| 108 | if let Statement { kind: StatementKind::Assign(_, rvalue), .. } = statement | |
| 109 | && let Rvalue::Aggregate(aggregate, _) = rvalue | |
| 110 | && let AggregateKind::Adt(adt_def, variant_idx, ..) = aggregate | |
| 111 | { | |
| 112 | let discr = adt_def.discriminant_for_variant(*variant_idx); | |
| 113 | ||
| 114 | assert_eq!(discr.val, expected_discr_val); | |
| 115 | assert_eq!(discr.ty, Ty::from_rigid_kind(expected_discr_ty)); | |
| 116 | } else { | |
| 117 | unreachable!("Unexpected statement"); | |
| 118 | } | |
| 119 | } | |
| 120 | ||
| 121 | /// This test will generate and analyze a dummy crate using the stable mir. | |
| 122 | /// For that, it will first write the dummy crate into a file. | |
| 123 | /// Then it will create a `StableMir` using custom arguments and then | |
| 124 | /// it will run the compiler. | |
| 125 | fn main() { | |
| 126 | let path = "defs_ty_input.rs"; | |
| 127 | generate_input(&path).unwrap(); | |
| 128 | let args = &[ | |
| 129 | "rustc".to_string(), | |
| 130 | "-Cpanic=abort".to_string(), | |
| 131 | "--crate-name".to_string(), | |
| 132 | CRATE_NAME.to_string(), | |
| 133 | path.to_string(), | |
| 134 | ]; | |
| 135 | run!(args, test_def_tys).unwrap(); | |
| 136 | } | |
| 137 | ||
| 138 | fn generate_input(path: &str) -> std::io::Result<()> { | |
| 139 | let mut file = std::fs::File::create(path)?; | |
| 140 | write!( | |
| 141 | file, | |
| 142 | r#" | |
| 143 | use std::hint::black_box; | |
| 144 | ||
| 145 | enum Mono {{ | |
| 146 | A, | |
| 147 | B(i32), | |
| 148 | C {{ a: i32, b: u32 }}, | |
| 149 | }} | |
| 150 | ||
| 151 | enum Poly<T> {{ | |
| 152 | A, | |
| 153 | B(T), | |
| 154 | C {{ t: T }}, | |
| 155 | }} | |
| 156 | ||
| 157 | pub fn main() {{ | |
| 158 | mono(); | |
| 159 | poly(); | |
| 160 | poly2::<i32>(1); | |
| 161 | }} | |
| 162 | ||
| 163 | fn mono() {{ | |
| 164 | black_box(Mono::A); | |
| 165 | black_box(Mono::B(6)); | |
| 166 | black_box(Mono::C {{a: 1, b: 10 }}); | |
| 167 | }} | |
| 168 | ||
| 169 | fn poly() {{ | |
| 170 | black_box(Poly::<i32>::A); | |
| 171 | black_box(Poly::B(1i32)); | |
| 172 | black_box(Poly::C {{ t: 1i32 }}); | |
| 173 | }} | |
| 174 | ||
| 175 | fn poly2<T: Copy>(t: T) {{ | |
| 176 | black_box(Poly::<T>::A); | |
| 177 | black_box(Poly::B(t)); | |
| 178 | black_box(Poly::C {{ t: t }}); | |
| 179 | }} | |
| 180 | "# | |
| 181 | )?; | |
| 182 | Ok(()) | |
| 183 | } |