diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 2d67608609e39..0ebd3dc826d48 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -133,6 +133,7 @@ fn eii_( macro_name, foreign_item_name, impl_unsafe, + &attrs_from_decl, ))); return_items.into_iter().map(wrap_item).collect() @@ -416,9 +417,14 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, + attrs_from_decl: &[Attribute], ) -> ast::Item { let mut macro_attrs = ThinVec::new(); + // To avoid e.g. `error: attribute macro has missing stability attribute` + // errors for eii's in std. + macro_attrs.extend_from_slice(attrs_from_decl); + // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 08c53179bc142..2b04f81c267fd 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -187,6 +187,10 @@ fn check_and_apply_linkage<'ll, 'tcx>( }; llvm::set_linkage(g1, base::linkage_to_llvm(linkage)); + // Normally this is done in `get_static_inner`, but when as we generate an internal global, + // it will apply the dso_local to the internal global instead, so do it here, too. + cx.assume_dso_local(g1, true); + // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is // discarded during linking (for example, if `foo` has weak diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 1d87dc5da8d2d..4875f309cca5f 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -10,6 +10,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty +codegen_ssa_bpf_staticlib_not_supported = linking static libraries is not supported for BPF + codegen_ssa_cgu_not_recorded = CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 93f6cb3b87e66..3f12e857391b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -22,10 +22,11 @@ use tracing::trace; use super::metadata::{create_compressed_metadata_file, search_for_section}; use crate::common; -// Re-exporting for rustc_codegen_llvm::back::archive -pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind}; +// Public for ArchiveBuilderBuilder::extract_bundled_libs +pub use crate::errors::ExtractBundledLibsError; use crate::errors::{ - DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, + ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, + ErrorWritingDEFFile, UnknownArchiveKind, }; /// An item to be included in an import library. diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index b47652092ed5c..637d54dd06c65 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -2075,7 +2075,7 @@ impl<'a> Linker for BpfLinker<'a> { } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { - panic!("staticlibs not supported") + self.sess.dcx().emit_fatal(errors::BpfStaticlibNotSupported) } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 95306c140895c..39727685aec1a 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -661,7 +661,7 @@ pub(crate) struct RlibArchiveBuildFailure { } #[derive(Diagnostic)] -// Public for rustc_codegen_llvm::back::archive +// Public for ArchiveBuilderBuilder::extract_bundled_libs pub enum ExtractBundledLibsError<'a> { #[diag(codegen_ssa_extract_bundled_libs_open_file)] OpenFile { rlib: &'a Path, error: Box }, @@ -700,19 +700,21 @@ pub(crate) struct UnsupportedLinkSelfContained; #[derive(Diagnostic)] #[diag(codegen_ssa_archive_build_failure)] -// Public for rustc_codegen_llvm::back::archive -pub struct ArchiveBuildFailure { +pub(crate) struct ArchiveBuildFailure { pub path: PathBuf, pub error: std::io::Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_unknown_archive_kind)] -// Public for rustc_codegen_llvm::back::archive -pub struct UnknownArchiveKind<'a> { +pub(crate) struct UnknownArchiveKind<'a> { pub kind: &'a str, } +#[derive(Diagnostic)] +#[diag(codegen_ssa_bpf_staticlib_not_supported)] +pub(crate) struct BpfStaticlibNotSupported; + #[derive(Diagnostic)] #[diag(codegen_ssa_multiple_main_functions)] #[help] diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 113e0d66c48a2..02615e3bbc18c 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -6,9 +6,7 @@ // having basically only two use-cases that act in different ways. use rustc_errors::ErrorGuaranteed; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::def::DefKind; -use rustc_hir::{LangItem, find_attr}; +use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty::{self, AdtDef, Ty}; @@ -366,14 +364,10 @@ where // check performed after the promotion. Verify that with an assertion. assert!(promoted.is_none() || Q::ALLOW_PROMOTED); - // Avoid looking at attrs of anon consts as that will ICE - let is_type_const_item = - matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst) - && find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_)); - // Don't peak inside trait associated constants, also `#[type_const] const` items // don't have bodies so there's nothing to look at - if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item { + if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def) + { let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); if !Q::in_qualifs(&qualifs) { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 13c1f2219bed2..43032bf938c0b 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -235,7 +235,7 @@ declare_features! ( (accepted, generic_param_attrs, "1.27.0", Some(48848)), /// Allows the `#[global_allocator]` attribute. (accepted, global_allocator, "1.28.0", Some(27389)), - // FIXME: explain `globs`. + /// Allows globs imports (`use module::*;`) to import all public items from a module. (accepted, globs, "1.0.0", None), /// Allows using `..=X` as a pattern. (accepted, half_open_range_patterns, "1.66.0", Some(67264)), diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index aa0e5c7fd7101..910176a0689c7 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -420,7 +420,22 @@ fn infer_placeholder_type<'tcx>( kind: &'static str, ) -> Ty<'tcx> { let tcx = cx.tcx(); - let ty = tcx.typeck(def_id).node_type(hir_id); + // If the type is omitted on a #[type_const] we can't run + // type check on since that requires the const have a body + // which type_consts don't. + let ty = if tcx.is_type_const(def_id.to_def_id()) { + if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) { + tcx.type_of(trait_item_def_id).instantiate_identity() + } else { + Ty::new_error_with_message( + tcx, + ty_span, + "constant with #[type_const] requires an explicit type", + ) + } + } else { + tcx.typeck(def_id).node_type(hir_id) + }; // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3683c1cfb7ddb..e538c2182924a 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -643,10 +643,26 @@ pub struct FieldPat<'tcx> { pub pattern: Pat<'tcx>, } +/// Additional per-node data that is not present on most THIR pattern nodes. +#[derive(Clone, Debug, Default, HashStable, TypeVisitable)] +pub struct PatExtra<'tcx> { + /// If present, this node represents a named constant that was lowered to + /// a pattern using `const_to_pat`. + /// + /// This is used by some diagnostics for non-exhaustive matches, to map + /// the pattern node back to the `DefId` of its original constant. + pub expanded_const: Option, + + /// User-written types that must be preserved into MIR so that they can be + /// checked. + pub ascriptions: Vec>, +} + #[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, + pub extra: Option>>, pub kind: PatKind<'tcx>, } @@ -762,11 +778,6 @@ pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, - AscribeUserType { - ascription: Ascription<'tcx>, - subpattern: Box>, - }, - /// `x`, `ref x`, `x @ P`, etc. Binding { name: Symbol, @@ -831,21 +842,6 @@ pub enum PatKind<'tcx> { value: ty::Value<'tcx>, }, - /// Wrapper node representing a named constant that was lowered to a pattern - /// using `const_to_pat`. - /// - /// This is used by some diagnostics for non-exhaustive matches, to map - /// the pattern node back to the `DefId` of its original constant. - /// - /// FIXME(#150498): Can we make this an `Option` field on `Pat` - /// instead, so that non-diagnostic code can ignore it more easily? - ExpandedConstant { - /// [DefId] of the constant item. - def_id: DefId, - /// The pattern that the constant lowered to. - subpattern: Box>, - }, - Range(Arc>), /// Matches against a slice, checking the length and extracting elements. @@ -1119,7 +1115,7 @@ mod size_asserts { static_assert_size!(Block, 48); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 64); + static_assert_size!(Pat<'_>, 72); static_assert_size!(PatKind<'_>, 48); static_assert_size!(Stmt<'_>, 48); static_assert_size!(StmtKind<'_>, 48); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index d792bbe60c888..b611b23e52619 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -259,7 +259,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( pat: &'a Pat<'tcx>, mut callback: impl FnMut(&'a Pat<'tcx>), ) { - let Pat { kind, ty: _, span: _ } = pat; + let Pat { kind, ty: _, span: _, extra: _ } = pat; match kind { PatKind::Missing | PatKind::Wild @@ -269,11 +269,9 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( | PatKind::Never | PatKind::Error(_) => {} - PatKind::AscribeUserType { subpattern, .. } - | PatKind::Binding { subpattern: Some(subpattern), .. } + PatKind::Binding { subpattern: Some(subpattern), .. } | PatKind::Deref { subpattern } - | PatKind::DerefPattern { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern), + | PatKind::DerefPattern { subpattern, .. } => callback(subpattern), PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => { for field_pat in subpatterns { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a2f4714d1b2c2..a3eec72214c06 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1891,6 +1891,12 @@ impl<'tcx> TyCtxt<'tcx> { self.is_lang_item(self.parent(def_id), LangItem::AsyncDropInPlace) } + /// Check if the given `def_id` is a const with the `#[type_const]` attribute. + pub fn is_type_const(self, def_id: DefId) -> bool { + matches!(self.def_kind(def_id), DefKind::Const | DefKind::AssocConst) + && find_attr!(self.get_all_attrs(def_id), AttributeKind::TypeConst(_)) + } + /// Returns the movability of the coroutine of `def_id`, or panics /// if given a `def_id` that is not a coroutine. pub fn coroutine_movability(self, def_id: DefId) -> hir::Movability { diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index c6ef362c6ea5a..3ae4b1fadee9e 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -287,22 +287,14 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { self.parse_var(pattern) } - fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> { - // Make sure we throw out any `AscribeUserType` we find - loop { - match &pat.kind { - PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)), - PatKind::AscribeUserType { subpattern, .. } => { - pat = subpattern; - } - _ => { - break Err(ParseError { - span: pat.span, - item_description: format!("{:?}", pat.kind), - expected: "local".to_string(), - }); - } - } + fn parse_var(&mut self, pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> { + match &pat.kind { + PatKind::Binding { var, ty, .. } => Ok((*var, *ty, pat.span)), + _ => Err(ParseError { + span: pat.span, + item_description: format!("{:?}", pat.kind), + expected: "local".to_string(), + }), } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index ddaa61c6cc910..13082d408ec08 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -144,11 +144,6 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { PatKind::Constant { value } => value, - PatKind::ExpandedConstant { ref subpattern, def_id: _ } - if let PatKind::Constant { value } = subpattern.kind => - { - value - } _ => { return Err(ParseError { span: arm.pattern.span, diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 186fde4883df8..1772d66f5285a 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -1,7 +1,7 @@ //! See docs in build/expr/mod.rs use rustc_abi::Size; -use rustc_ast as ast; +use rustc_ast::{self as ast}; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, LitToConstInput, Scalar}; use rustc_middle::mir::*; @@ -47,6 +47,7 @@ pub(crate) fn as_constant_inner<'tcx>( tcx: TyCtxt<'tcx>, ) -> ConstOperand<'tcx> { let Expr { ty, temp_scope_id: _, span, ref kind } = *expr; + match *kind { ExprKind::Literal { lit, neg } => { let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg }); @@ -69,6 +70,13 @@ pub(crate) fn as_constant_inner<'tcx>( } ExprKind::NamedConst { def_id, args, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); + if tcx.is_type_const(def_id) { + let uneval = ty::UnevaluatedConst::new(def_id, args); + let ct = ty::Const::new_unevaluated(tcx, uneval); + + let const_ = Const::Ty(ty, ct); + return ConstOperand { span, user_ty, const_ }; + } let uneval = mir::UnevaluatedConst::new(def_id, args); let const_ = Const::Unevaluated(uneval, ty); diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index f0114c2193c3e..8cee3ff27e8f9 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -133,6 +133,20 @@ impl<'tcx> MatchPairTree<'tcx> { } let place = place_builder.try_to_place(cx); + + // Apply any type ascriptions to the value at `match_pair.place`. + if let Some(place) = place + && let Some(extra) = &pattern.extra + { + for &Ascription { ref annotation, variance } in &extra.ascriptions { + extra_data.ascriptions.push(super::Ascription { + source: place, + annotation: annotation.clone(), + variance, + }); + } + } + let mut subpairs = Vec::new(); let testable_case = match pattern.kind { PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None, @@ -195,28 +209,6 @@ impl<'tcx> MatchPairTree<'tcx> { Some(TestableCase::Constant { value, kind: const_kind }) } - PatKind::AscribeUserType { - ascription: Ascription { ref annotation, variance }, - ref subpattern, - .. - } => { - MatchPairTree::for_pattern( - place_builder, - subpattern, - cx, - &mut subpairs, - extra_data, - ); - - // Apply the type ascription to the value at `match_pair.place` - if let Some(source) = place { - let annotation = annotation.clone(); - extra_data.ascriptions.push(super::Ascription { source, annotation, variance }); - } - - None - } - PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => { // In order to please the borrow checker, when lowering a pattern // like `x @ subpat` we must establish any bindings in `subpat` @@ -263,11 +255,6 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::ExpandedConstant { subpattern: ref pattern, .. } => { - MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); - None - } - PatKind::Array { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix( &mut subpairs, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 9080e2ba801bf..590316a475549 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -576,7 +576,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer_id: ExprId, ) -> BlockAnd<()> { match irrefutable_pat.kind { - // Optimize the case of `let x = ...` to write directly into `x` + // Optimize `let x = ...` and `let x: T = ...` to write directly into `x`, + // and then require that `T == typeof(x)` if present. PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => { let place = self.storage_live_binding( block, @@ -592,43 +593,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(irrefutable_pat.span); self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); - block.unit() - } + let ascriptions: &[_] = + try { irrefutable_pat.extra.as_deref()?.ascriptions.as_slice() } + .unwrap_or_default(); + for thir::Ascription { annotation, variance: _ } in ascriptions { + let ty_source_info = self.source_info(annotation.span); - // Optimize the case of `let x: T = ...` to write directly - // into `x` and then require that `T == typeof(x)`. - PatKind::AscribeUserType { - ref subpattern, - ascription: thir::Ascription { ref annotation, variance: _ }, - } if let PatKind::Binding { - mode: BindingMode(ByRef::No, _), - var, - subpattern: None, - .. - } = subpattern.kind => - { - let place = self.storage_live_binding( - block, - var, - irrefutable_pat.span, - false, - OutsideGuard, - ScheduleDrops::Yes, - ); - block = self.expr_into_dest(place, block, initializer_id).into_block(); - - // Inject a fake read, see comments on `FakeReadCause::ForLet`. - let pattern_source_info = self.source_info(irrefutable_pat.span); - let cause_let = FakeReadCause::ForLet(None); - self.cfg.push_fake_read(block, pattern_source_info, cause_let, place); - - let ty_source_info = self.source_info(annotation.span); - - let base = self.canonical_user_type_annotations.push(annotation.clone()); - self.cfg.push( - block, - Statement::new( + let base = self.canonical_user_type_annotations.push(annotation.clone()); + let stmt = Statement::new( ty_source_info, StatementKind::AscribeUserType( Box::new((place, UserTypeProjection { base, projs: Vec::new() })), @@ -648,8 +620,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``. ty::Invariant, ), - ), - ); + ); + self.cfg.push(block, stmt); + } self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() @@ -879,6 +852,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &ProjectedUserTypesNode<'_>, ), ) { + // Ascriptions correspond to user-written types like `let A::<'a>(_): A<'static> = ...;`. + // + // Caution: Pushing user types here is load-bearing even for + // patterns containing no bindings, to ensure that the type ends + // up represented in MIR _somewhere_. + let user_tys = match pattern.extra.as_deref() { + Some(PatExtra { ascriptions, .. }) if !ascriptions.is_empty() => { + let base_user_tys = ascriptions + .iter() + .map(|thir::Ascription { annotation, variance: _ }| { + // Note that the variance doesn't apply here, as we are tracking the effect + // of user types on any bindings contained with subpattern. + self.canonical_user_type_annotations.push(annotation.clone()) + }) + .collect(); + &user_tys.push_user_types(base_user_tys) + } + _ => user_tys, + }; + // Avoid having to write the full method name at each recursive call. let visit_subpat = |this: &mut Self, subpat, user_tys: &_, f: &mut _| { this.visit_primary_bindings_special(subpat, user_tys, f) @@ -924,31 +917,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } - PatKind::AscribeUserType { - ref subpattern, - ascription: thir::Ascription { ref annotation, variance: _ }, - } => { - // This corresponds to something like - // - // ``` - // let A::<'a>(_): A<'static> = ...; - // ``` - // - // Note that the variance doesn't apply here, as we are tracking the effect - // of `user_ty` on any bindings contained with subpattern. - - // Caution: Pushing this user type here is load-bearing even for - // patterns containing no bindings, to ensure that the type ends - // up represented in MIR _somewhere_. - let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); - let subpattern_user_tys = user_tys.push_user_type(base_user_ty); - visit_subpat(self, subpattern, &subpattern_user_tys, f) - } - - PatKind::ExpandedConstant { ref subpattern, .. } => { - visit_subpat(self, subpattern, user_tys, f) - } - PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_tys = user_tys.leaf(subpattern.field); diff --git a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs index df9f93ac328a6..2dcfd3772902c 100644 --- a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs +++ b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs @@ -8,15 +8,20 @@ use std::assert_matches::assert_matches; use std::iter; use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_data_structures::smallvec::SmallVec; use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex}; use rustc_span::Symbol; +/// A single `thir::Pat` node should almost never have more than 0-2 user types. +/// We can store up to 4 inline in the same size as an ordinary `Vec`. +pub(crate) type UserTypeIndices = SmallVec<[UserTypeAnnotationIndex; 4]>; + /// One of a list of "operations" that can be used to lazily build projections /// of user-specified types. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) enum ProjectedUserTypesOp { - PushUserType { base: UserTypeAnnotationIndex }, + PushUserTypes { base_types: UserTypeIndices }, Index, Subslice { from: u64, to: u64 }, @@ -32,9 +37,10 @@ pub(crate) enum ProjectedUserTypesNode<'a> { } impl<'a> ProjectedUserTypesNode<'a> { - pub(crate) fn push_user_type(&'a self, base: UserTypeAnnotationIndex) -> Self { - // Pushing a base user type always causes the chain to become non-empty. - Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserType { base } } + pub(crate) fn push_user_types(&'a self, base_types: UserTypeIndices) -> Self { + assert!(!base_types.is_empty()); + // Pushing one or more base user types always causes the chain to become non-empty. + Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserTypes { base_types } } } /// Push another projection op onto the chain, but only if it is already non-empty. @@ -94,16 +100,19 @@ impl<'a> ProjectedUserTypesNode<'a> { return None; } - let ops_reversed = self.iter_ops_reversed().cloned().collect::>(); + let ops_reversed = self.iter_ops_reversed().collect::>(); // The "first" op should always be `PushUserType`. // Other projections are only added if there is at least one user type. - assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserType { .. })); + assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserTypes { .. })); let mut projections = vec![]; for op in ops_reversed.into_iter().rev() { - match op { - ProjectedUserTypesOp::PushUserType { base } => { - projections.push(UserTypeProjection { base, projs: vec![] }) + match *op { + ProjectedUserTypesOp::PushUserTypes { ref base_types } => { + assert!(!base_types.is_empty()); + for &base in base_types { + projections.push(UserTypeProjection { base, projs: vec![] }) + } } ProjectedUserTypesOp::Index => { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 4f03e3d965c6c..68b8a842a2a69 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -342,8 +342,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns, which we recurse on below. PatKind::Or { .. } | - PatKind::ExpandedConstant { .. } | - PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index bf480cf601ee3..d9a06de32bb0f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -680,20 +680,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut interpreted_as_const = None; let mut interpreted_as_const_sugg = None; - // These next few matches want to peek through `AscribeUserType` to see - // the underlying pattern. - let mut unpeeled_pat = pat; - while let PatKind::AscribeUserType { ref subpattern, .. } = unpeeled_pat.kind { - unpeeled_pat = subpattern; - } - - if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, unpeeled_pat) { + if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, pat) { let span = self.tcx.def_span(def_id); let variable = self.tcx.item_name(def_id).to_string(); // When we encounter a constant as the binding name, point at the `const` definition. interpreted_as_const = Some(InterpretedAsConst { span, variable: variable.clone() }); interpreted_as_const_sugg = Some(InterpretedAsConstSugg { span: pat.span, variable }); - } else if let PatKind::Constant { .. } = unpeeled_pat.kind + } else if let PatKind::Constant { .. } = pat.kind && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { // If the pattern to match is an integer literal: @@ -1213,7 +1206,7 @@ fn is_const_pat_that_looks_like_binding<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat<'tcx> // The pattern must be a named constant, and the name that appears in // the pattern's source text must resemble a plain identifier without any // `::` namespace separators or other non-identifier characters. - if let PatKind::ExpandedConstant { def_id, .. } = pat.kind + if let Some(def_id) = try { pat.extra.as_deref()?.expanded_const? } && matches!(tcx.def_kind(def_id), DefKind::Const) && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(pat.span) && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 2da9a43f71d86..02409d2bae9fa 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -90,7 +90,7 @@ impl<'tcx> ConstToPat<'tcx> { ); } } - Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) }) + Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()), extra: None }) } fn unevaluated_to_pat( @@ -174,10 +174,10 @@ impl<'tcx> ConstToPat<'tcx> { } }; - // Convert the valtree to a const. - let inlined_const_as_pat = self.valtree_to_pat(valtree, ty); + // Lower the valtree to a THIR pattern. + let mut thir_pat = self.valtree_to_pat(valtree, ty); - if !inlined_const_as_pat.references_error() { + if !thir_pat.references_error() { // Always check for `PartialEq` if we had no other errors yet. if !type_has_partial_eq_impl(self.tcx, typing_env, ty).has_impl { let mut err = self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty }); @@ -186,10 +186,10 @@ impl<'tcx> ConstToPat<'tcx> { } } - // Wrap the pattern in a marker node to indicate that it is the result of lowering a + // Mark the pattern to indicate that it is the result of lowering a named // constant. This is used for diagnostics. - let kind = PatKind::ExpandedConstant { subpattern: inlined_const_as_pat, def_id: uv.def }; - Box::new(Pat { kind, ty, span: self.span }) + thir_pat.extra.get_or_insert_default().expanded_const = Some(uv.def); + thir_pat } fn field_pats( @@ -351,7 +351,7 @@ impl<'tcx> ConstToPat<'tcx> { } }; - Box::new(Pat { span, ty, kind }) + Box::new(Pat { span, ty, kind, extra: None }) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 4128508955cb3..650650cbaac90 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -71,14 +71,11 @@ pub(super) fn pat_from_hir<'tcx>( span: let_stmt_type.span, inferred_ty: typeck_results.node_type(let_stmt_type.hir_id), }; - thir_pat = Box::new(Pat { - ty: thir_pat.ty, - span: thir_pat.span, - kind: PatKind::AscribeUserType { - ascription: Ascription { annotation, variance: ty::Covariant }, - subpattern: thir_pat, - }, - }); + thir_pat + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Covariant }); } if let Some(m) = pcx.rust_2024_migration { @@ -142,7 +139,7 @@ impl<'tcx> PatCtxt<'tcx> { } PatAdjust::PinDeref => PatKind::Deref { subpattern: thir_pat }, }; - Box::new(Pat { span, ty: adjust.source, kind }) + Box::new(Pat { span, ty: adjust.source, kind, extra: None }) }); if let Some(s) = &mut self.rust_2024_migration @@ -167,25 +164,14 @@ impl<'tcx> PatCtxt<'tcx> { // Return None in that case; the caller will use NegInfinity or PosInfinity instead. let Some(expr) = expr else { return Ok(None) }; - // Lower the endpoint into a temporary `PatKind` that will then be + // Lower the endpoint into a temporary `thir::Pat` that will then be // deconstructed to obtain the constant value and other data. - let mut kind: PatKind<'tcx> = self.lower_pat_expr(pat, expr); - - // Unpeel any ascription or inline-const wrapper nodes. - loop { - match kind { - PatKind::AscribeUserType { ascription, subpattern } => { - ascriptions.push(ascription); - kind = subpattern.kind; - } - PatKind::ExpandedConstant { def_id: _, subpattern } => { - // Expanded-constant nodes are currently only needed by - // diagnostics that don't apply to range patterns, so we - // can just discard them here. - kind = subpattern.kind; - } - _ => break, - } + let endpoint_pat: Box> = self.lower_pat_expr(pat, expr); + let box Pat { ref kind, extra, .. } = endpoint_pat; + + // Preserve any ascriptions from endpoint constants. + if let Some(extra) = extra { + ascriptions.extend(extra.ascriptions); } // The unpeeled kind should now be a constant, giving us the endpoint value. @@ -250,7 +236,7 @@ impl<'tcx> PatCtxt<'tcx> { lo_expr: Option<&'tcx hir::PatExpr<'tcx>>, hi_expr: Option<&'tcx hir::PatExpr<'tcx>>, end: RangeEnd, - ) -> Result, ErrorGuaranteed> { + ) -> Result>, ErrorGuaranteed> { let ty = self.typeck_results.node_type(pat.hir_id); let span = pat.span; @@ -306,27 +292,28 @@ impl<'tcx> PatCtxt<'tcx> { return Err(e); } } + let mut thir_pat = Box::new(Pat { ty, span, kind, extra: None }); // If we are handling a range with associated constants (e.g. // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated // constants somewhere. Have them on the range pattern. - for ascription in ascriptions { - let subpattern = Box::new(Pat { span, ty, kind }); - kind = PatKind::AscribeUserType { ascription, subpattern }; - } - // `PatKind::ExpandedConstant` wrappers from range endpoints used to + thir_pat.extra.get_or_insert_default().ascriptions.extend(ascriptions); + // IDs of expanded constants from range endpoints used to // also be preserved here, but that was only needed for unsafeck of // inline `const { .. }` patterns, which were removed by // . - Ok(kind) + Ok(thir_pat) } #[instrument(skip(self), level = "debug")] fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { - let mut ty = self.typeck_results.node_type(pat.hir_id); - let mut span = pat.span; + let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; + // Some of these match arms return a `Box` early, while others + // evaluate to a `PatKind` that will become a `Box` at the end of + // this function. let kind = match pat.kind { hir::PatKind::Missing => PatKind::Missing, @@ -334,10 +321,13 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Never => PatKind::Never, - hir::PatKind::Expr(value) => self.lower_pat_expr(pat, value), + hir::PatKind::Expr(value) => return self.lower_pat_expr(pat, value), hir::PatKind::Range(lo_expr, hi_expr, end) => { - self.lower_pattern_range(pat, lo_expr, hi_expr, end).unwrap_or_else(PatKind::Error) + match self.lower_pattern_range(pat, lo_expr, hi_expr, end) { + Ok(thir_pat) => return thir_pat, + Err(e) => PatKind::Error(e), + } } hir::PatKind::Deref(subpattern) => { @@ -360,7 +350,7 @@ impl<'tcx> PatCtxt<'tcx> { }, hir::PatKind::Slice(prefix, slice, suffix) => { - self.slice_or_array_pattern(pat, prefix, slice, suffix) + return self.slice_or_array_pattern(pat, prefix, slice, suffix); } hir::PatKind::Tuple(pats, ddpos) => { @@ -372,8 +362,9 @@ impl<'tcx> PatCtxt<'tcx> { } hir::PatKind::Binding(explicit_ba, id, ident, sub) => { + let mut thir_pat_span = span; if let Some(ident_span) = ident.span.find_ancestor_inside(span) { - span = span.with_hi(ident_span.hi()); + thir_pat_span = span.with_hi(ident_span.hi()); } let mode = *self @@ -389,22 +380,23 @@ impl<'tcx> PatCtxt<'tcx> { // A ref x pattern is the same node used for x, and as such it has // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; + let mut thir_pat_ty = ty; if let hir::ByRef::Yes(pinnedness, _) = mode.0 { match pinnedness { hir::Pinnedness::Pinned if let Some(pty) = ty.pinned_ty() && let &ty::Ref(_, rty, _) = pty.kind() => { - ty = rty; + thir_pat_ty = rty; } hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => { - ty = rty; + thir_pat_ty = rty; } _ => bug!("`ref {}` has wrong type {}", ident, ty), } }; - PatKind::Binding { + let kind = PatKind::Binding { mode, name: ident.name, var: LocalVarId(id), @@ -412,7 +404,10 @@ impl<'tcx> PatCtxt<'tcx> { subpattern: self.lower_opt_pattern(sub), is_primary: id == pat.hir_id, is_shorthand: false, - } + }; + // We might have modified the type or span, so use the modified + // values in the THIR pattern node. + return Box::new(Pat { ty: thir_pat_ty, span: thir_pat_span, kind, extra: None }); } hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => { @@ -422,7 +417,7 @@ impl<'tcx> PatCtxt<'tcx> { }; let variant_def = adt_def.variant_of_res(res); let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); - self.lower_variant_or_leaf(pat, None, res, subpatterns) + return self.lower_variant_or_leaf(pat, None, res, subpatterns); } hir::PatKind::Struct(ref qpath, fields, _) => { @@ -439,7 +434,7 @@ impl<'tcx> PatCtxt<'tcx> { }) .collect(); - self.lower_variant_or_leaf(pat, None, res, subpatterns) + return self.lower_variant_or_leaf(pat, None, res, subpatterns); } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, @@ -450,7 +445,9 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Err(guar) => PatKind::Error(guar), }; - Box::new(Pat { span, ty, kind }) + // For pattern kinds that haven't already returned, create a `thir::Pat` + // with the HIR pattern node's type and span. + Box::new(Pat { span, ty, kind, extra: None }) } fn lower_tuple_subpats( @@ -482,13 +479,14 @@ impl<'tcx> PatCtxt<'tcx> { prefix: &'tcx [hir::Pat<'tcx>], slice: Option<&'tcx hir::Pat<'tcx>>, suffix: &'tcx [hir::Pat<'tcx>], - ) -> PatKind<'tcx> { + ) -> Box> { let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); let suffix = self.lower_patterns(suffix); - match ty.kind() { + let kind = match ty.kind() { // Matching a slice, `[T]`. ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, // Fixed-length array, `[T; len]`. @@ -499,8 +497,9 @@ impl<'tcx> PatCtxt<'tcx> { assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatKind::Array { prefix, slice, suffix } } - _ => span_bug!(pat.span, "bad slice pattern type {ty:?}"), - } + _ => span_bug!(span, "bad slice pattern type {ty:?}"), + }; + Box::new(Pat { ty, span, kind, extra: None }) } fn lower_variant_or_leaf( @@ -509,7 +508,7 @@ impl<'tcx> PatCtxt<'tcx> { expr: Option<&'tcx hir::PatExpr<'tcx>>, res: Res, subpatterns: Vec>, - ) -> PatKind<'tcx> { + ) -> Box> { // Check whether the caller should have provided an `expr` for this pattern kind. assert_matches!( (pat.kind, expr), @@ -533,7 +532,7 @@ impl<'tcx> PatCtxt<'tcx> { res => res, }; - let mut kind = match res { + let kind = match res { Res::Def(DefKind::Variant, variant_id) => { let enum_id = self.tcx.parent(variant_id); let adt_def = self.tcx.adt_def(enum_id); @@ -542,7 +541,12 @@ impl<'tcx> PatCtxt<'tcx> { ty::Adt(_, args) | ty::FnDef(_, args) => args, ty::Error(e) => { // Avoid ICE (#50585) - return PatKind::Error(*e); + return Box::new(Pat { + ty, + span, + kind: PatKind::Error(*e), + extra: None, + }); } _ => bug!("inappropriate type for def: {:?}", ty), }; @@ -583,21 +587,23 @@ impl<'tcx> PatCtxt<'tcx> { PatKind::Error(e) } }; + let mut thir_pat = Box::new(Pat { ty, span, kind, extra: None }); if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) { - debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); + debug!(?thir_pat, ?user_ty, ?span, "lower_variant_or_leaf: applying ascription"); let annotation = CanonicalUserTypeAnnotation { user_ty: Box::new(user_ty), span, inferred_ty: self.typeck_results.node_type(hir_id), }; - kind = PatKind::AscribeUserType { - subpattern: Box::new(Pat { span, ty, kind }), - ascription: Ascription { annotation, variance: ty::Covariant }, - }; + thir_pat + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Covariant }); } - kind + thir_pat } fn user_args_applied_to_ty_of_hir_id( @@ -632,8 +638,7 @@ impl<'tcx> PatCtxt<'tcx> { _ => { // The path isn't the name of a constant, so it must actually // be a unit struct or unit variant (e.g. `Option::None`). - let kind = self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); - return Box::new(Pat { span, ty, kind }); + return self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); } }; @@ -652,16 +657,13 @@ impl<'tcx> PatCtxt<'tcx> { span, inferred_ty: self.typeck_results.node_type(id), }; - let kind = PatKind::AscribeUserType { - subpattern: pattern, - ascription: Ascription { - annotation, - // Note that we use `Contravariant` here. See the - // `variance` field documentation for details. - variance: ty::Contravariant, - }, - }; - pattern = Box::new(Pat { span, kind, ty }); + // Note that we use `Contravariant` here. See the + // `variance` field documentation for details. + pattern + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Contravariant }); } pattern @@ -674,10 +676,10 @@ impl<'tcx> PatCtxt<'tcx> { &mut self, pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr` expr: &'tcx hir::PatExpr<'tcx>, - ) -> PatKind<'tcx> { + ) -> Box> { assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..)); match &expr.kind { - hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath).kind, + hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath), hir::PatExprKind::Lit { lit, negated } => { // We handle byte string literal patterns by using the pattern's type instead of the // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, @@ -691,7 +693,7 @@ impl<'tcx> PatCtxt<'tcx> { let pat_ty = self.typeck_results.node_type(pat.hir_id); let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); - self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span).kind + self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span) } } } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 5a2d6cfef1cc7..e12909305961d 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -73,6 +73,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.fmt } + fn print_list( + &mut self, + label: &str, + list: &[T], + depth_lvl: usize, + print_fn: impl Fn(&mut Self, &T, usize), + ) { + if list.is_empty() { + print_indented!(self, format_args!("{label}: []"), depth_lvl); + } else { + print_indented!(self, format_args!("{label}: ["), depth_lvl); + for item in list { + print_fn(self, item, depth_lvl + 1) + } + print_indented!(self, "]", depth_lvl); + } + } + fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) { let Param { pat, ty, ty_span, self_kind, hir_id } = param; @@ -663,15 +681,37 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } fn print_pat(&mut self, pat: &Pat<'tcx>, depth_lvl: usize) { - let &Pat { ty, span, ref kind } = pat; + let &Pat { ty, span, ref kind, ref extra } = pat; print_indented!(self, "Pat: {", depth_lvl); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + self.print_pat_extra(extra.as_deref(), depth_lvl + 1); self.print_pat_kind(kind, depth_lvl + 1); print_indented!(self, "}", depth_lvl); } + fn print_pat_extra(&mut self, extra: Option<&PatExtra<'tcx>>, depth_lvl: usize) { + let Some(extra) = extra else { + // Skip printing in the common case of a pattern node with no extra data. + return; + }; + + let PatExtra { expanded_const, ascriptions } = extra; + + print_indented!(self, "extra: PatExtra {", depth_lvl); + print_indented!(self, format_args!("expanded_const: {expanded_const:?}"), depth_lvl + 1); + self.print_list( + "ascriptions", + ascriptions, + depth_lvl + 1, + |this, ascription, depth_lvl| { + print_indented!(this, format_args!("{ascription:?}"), depth_lvl); + }, + ); + print_indented!(self, "}", depth_lvl); + } + fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { print_indented!(self, "kind: PatKind {", depth_lvl); @@ -685,13 +725,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { PatKind::Never => { print_indented!(self, "Never", depth_lvl + 1); } - PatKind::AscribeUserType { ascription, subpattern } => { - print_indented!(self, "AscribeUserType: {", depth_lvl + 1); - print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); - print_indented!(self, "subpattern: ", depth_lvl + 2); - self.print_pat(subpattern, depth_lvl + 3); - print_indented!(self, "}", depth_lvl + 1); - } PatKind::Binding { name, mode, var, ty, subpattern, is_primary, is_shorthand } => { print_indented!(self, "Binding {", depth_lvl + 1); print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); @@ -756,13 +789,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::ExpandedConstant { def_id, subpattern } => { - print_indented!(self, "ExpandedConstant {", depth_lvl + 1); - print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); - print_indented!(self, "subpattern:", depth_lvl + 2); - self.print_pat(subpattern, depth_lvl + 2); - print_indented!(self, "}", depth_lvl + 1); - } PatKind::Range(pat_range) => { print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d66c303b17260..721635ed48ff5 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -462,8 +462,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let arity; let fields: Vec<_>; match &pat.kind { - PatKind::AscribeUserType { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 2f2477008206e..78ea1f1113258 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1190,7 +1190,7 @@ pub macro Ord($item:item) { /// every `a`. This isn't always the case for types that implement `PartialOrd`, for example: /// /// ``` -/// let a = f64::sqrt(-1.0); +/// let a = f64::NAN; /// assert_eq!(a <= a, false); /// ``` /// diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 43caf7734fdbd..5c9ae52d9e6c0 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -128,10 +128,6 @@ debug_refcell = ["core/debug_refcell"] llvm_enzyme = ["core/llvm_enzyme"] -# Enable std_detect features: -std_detect_file_io = ["std_detect/std_detect_file_io"] -std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] - # Enable using raw-dylib for Windows imports. # This will eventually be the default. windows_raw_dylib = ["windows-targets/windows_raw_dylib"] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 4edd35b310bd0..a24baad615012 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3446,30 +3446,48 @@ impl DirBuilder { } fn create_dir_all(&self, path: &Path) -> io::Result<()> { - if path == Path::new("") { + // if path's parent is None, it is "/" path, which should + // return Ok immediately + if path == Path::new("") || path.parent() == None { return Ok(()); } - match self.inner.mkdir(path) { - Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(_) if path.is_dir() => return Ok(()), - Err(e) => return Err(e), - } - match path.parent() { - Some(p) => self.create_dir_all(p)?, - None => { - return Err(io::const_error!( - io::ErrorKind::Uncategorized, - "failed to create whole tree", - )); + let ancestors = path.ancestors(); + let mut uncreated_dirs = 0; + + for ancestor in ancestors { + // for relative paths like "foo/bar", the parent of + // "foo" will be "" which there's no need to invoke + // a mkdir syscall on + if ancestor == Path::new("") || ancestor.parent() == None { + break; + } + + match self.inner.mkdir(ancestor) { + Ok(()) => break, + Err(e) if e.kind() == io::ErrorKind::NotFound => uncreated_dirs += 1, + // we check if the err is AlreadyExists for two reasons + // - in case the path exists as a *file* + // - and to avoid calls to .is_dir() in case of other errs + // (i.e. PermissionDenied) + Err(e) if e.kind() == io::ErrorKind::AlreadyExists && ancestor.is_dir() => break, + Err(e) => return Err(e), } } - match self.inner.mkdir(path) { - Ok(()) => Ok(()), - Err(_) if path.is_dir() => Ok(()), - Err(e) => Err(e), + + // collect only the uncreated directories w/o letting the vec resize + let mut uncreated_dirs_vec = Vec::with_capacity(uncreated_dirs); + uncreated_dirs_vec.extend(ancestors.take(uncreated_dirs)); + + for uncreated_dir in uncreated_dirs_vec.iter().rev() { + if let Err(e) = self.inner.mkdir(uncreated_dir) { + if e.kind() != io::ErrorKind::AlreadyExists || !uncreated_dir.is_dir() { + return Err(e); + } + } } + + Ok(()) } } diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index fcf21d9e97318..c416419bd0082 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -336,8 +336,8 @@ impl File { crate::io::default_read_buf(|buf| self.read(buf), cursor) } - pub fn write(&self, _buf: &[u8]) -> io::Result { - unsupported() + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { @@ -705,6 +705,25 @@ mod uefi_fs { } } + pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + let file_ptr = self.protocol.as_ptr(); + let mut buf_size = buf.len(); + + let r = unsafe { + ((*file_ptr).write)( + file_ptr, + &mut buf_size, + buf.as_ptr().cast::().cast_mut(), + ) + }; + + if buf_size == 0 && r.is_error() { + Err(io::Error::from_raw_os_error(r.as_usize())) + } else { + Ok(buf_size) + } + } + pub(crate) fn file_info(&self) -> io::Result> { let file_ptr = self.protocol.as_ptr(); let mut info_id = file::INFO_ID; diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml index 2739bb5923009..a6785bb20555d 100644 --- a/library/std_detect/Cargo.toml +++ b/library/std_detect/Cargo.toml @@ -7,11 +7,6 @@ authors = [ "Gonzalo Brito Gadeschi ", ] description = "`std::detect` - Rust's standard library run-time CPU feature detection." -homepage = "https://github.com/rust-lang/stdarch" -repository = "https://github.com/rust-lang/stdarch" -readme = "README.md" -keywords = ["std", "run-time", "feature", "detection"] -categories = ["hardware-support"] license = "MIT OR Apache-2.0" edition = "2024" @@ -25,10 +20,7 @@ core = { version = "1.0.0", package = 'rustc-std-workspace-core' } alloc = { version = "1.0.0", package = 'rustc-std-workspace-alloc' } [target.'cfg(not(windows))'.dependencies] -libc = { version = "0.2.0", optional = true, default-features = false } +libc = { version = "0.2.0", default-features = false } [features] -default = [] -std_detect_file_io = [ "libc" ] -std_detect_dlsym_getauxval = [ "libc" ] -std_detect_env_override = [ "libc" ] +std_detect_env_override = [] diff --git a/library/std_detect/README.md b/library/std_detect/README.md index 177848dec1044..895f3426d0495 100644 --- a/library/std_detect/README.md +++ b/library/std_detect/README.md @@ -21,32 +21,6 @@ run-time feature detection support than the one offered by Rust's standard library. We intend to make `std_detect` more flexible and configurable in this regard to better serve the needs of `#[no_std]` targets. -# Features - -* `std_detect_dlsym_getauxval` (enabled by default, requires `libc`): Enable to -use `libc::dlsym` to query whether [`getauxval`] is linked into the binary. When -this is not the case, this feature allows other fallback methods to perform -run-time feature detection. When this feature is disabled, `std_detect` assumes -that [`getauxval`] is linked to the binary. If that is not the case the behavior -is undefined. - - Note: This feature is ignored on `*-linux-{gnu,musl,ohos}*` and `*-android*` targets - because we can safely assume `getauxval` is linked to the binary. - * `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) - have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). - * `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) - use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) - * `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) - * `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) - have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). - -* `std_detect_file_io` (enabled by default, requires `std`): Enable to perform run-time feature -detection using file APIs (e.g. `/proc/self/auxv`, etc.) if other more performant -methods fail. This feature requires `libstd` as a dependency, preventing the -crate from working on applications in which `std` is not available. - -[`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html - # Platform support * All `x86`/`x86_64` targets are supported on all platforms by querying the diff --git a/library/std_detect/src/detect/mod.rs b/library/std_detect/src/detect/mod.rs index ae6fb2ab37279..c888dd34d9db5 100644 --- a/library/std_detect/src/detect/mod.rs +++ b/library/std_detect/src/detect/mod.rs @@ -47,21 +47,21 @@ cfg_select! { #[path = "os/x86.rs"] mod os; } - all(any(target_os = "linux", target_os = "android"), feature = "libc") => { + any(target_os = "linux", target_os = "android") => { #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[path = "os/riscv.rs"] mod riscv; #[path = "os/linux/mod.rs"] mod os; } - all(target_os = "freebsd", feature = "libc") => { + target_os = "freebsd" => { #[cfg(target_arch = "aarch64")] #[path = "os/aarch64.rs"] mod aarch64; #[path = "os/freebsd/mod.rs"] mod os; } - all(target_os = "openbsd", feature = "libc") => { + target_os = "openbsd" => { #[allow(dead_code)] // we don't use code that calls the mrs instruction. #[cfg(target_arch = "aarch64")] #[path = "os/aarch64.rs"] @@ -73,7 +73,7 @@ cfg_select! { #[path = "os/windows/aarch64.rs"] mod os; } - all(target_vendor = "apple", target_arch = "aarch64", feature = "libc") => { + all(target_vendor = "apple", target_arch = "aarch64") => { #[path = "os/darwin/aarch64.rs"] mod os; } diff --git a/library/std_detect/src/detect/os/linux/aarch64/tests.rs b/library/std_detect/src/detect/os/linux/aarch64/tests.rs index a3562f2fd9362..4d7c9a419d386 100644 --- a/library/std_detect/src/detect/os/linux/aarch64/tests.rs +++ b/library/std_detect/src/detect/os/linux/aarch64/tests.rs @@ -1,77 +1,70 @@ +use super::auxvec::auxv_from_file; use super::*; +// The baseline hwcaps used in the (artificial) auxv test files. +fn baseline_hwcaps() -> AtHwcap { + AtHwcap { + fp: true, + asimd: true, + aes: true, + pmull: true, + sha1: true, + sha2: true, + crc32: true, + atomics: true, + fphp: true, + asimdhp: true, + asimdrdm: true, + lrcpc: true, + dcpop: true, + asimddp: true, + ssbs: true, + ..AtHwcap::default() + } +} -#[cfg(feature = "std_detect_file_io")] -mod auxv_from_file { - use super::auxvec::auxv_from_file; - use super::*; - // The baseline hwcaps used in the (artificial) auxv test files. - fn baseline_hwcaps() -> AtHwcap { +#[test] +fn linux_empty_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); +} +#[test] +fn linux_no_hwcap2_aarch64() { + let file = + concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); +} +#[test] +fn linux_hwcap2_aarch64() { + let file = + concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!( + AtHwcap::from(v), AtHwcap { - fp: true, - asimd: true, - aes: true, - pmull: true, - sha1: true, - sha2: true, - crc32: true, - atomics: true, - fphp: true, - asimdhp: true, - asimdrdm: true, - lrcpc: true, - dcpop: true, - asimddp: true, - ssbs: true, - ..AtHwcap::default() + // Some other HWCAP bits. + paca: true, + pacg: true, + // HWCAP2-only bits. + dcpodp: true, + frint: true, + rng: true, + bti: true, + mte: true, + ..baseline_hwcaps() } - } - - #[test] - fn linux_empty_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_no_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_hwcap2_aarch64() { - let file = - concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!( - AtHwcap::from(v), - AtHwcap { - // Some other HWCAP bits. - paca: true, - pacg: true, - // HWCAP2-only bits. - dcpodp: true, - frint: true, - rng: true, - bti: true, - mte: true, - ..baseline_hwcaps() - } - ); - } + ); } diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs index 75e01bdc4499d..c0bbc7d4efa88 100644 --- a/library/std_detect/src/detect/os/linux/auxvec.rs +++ b/library/std_detect/src/detect/os/linux/auxvec.rs @@ -44,20 +44,16 @@ pub(crate) struct AuxVec { /// /// There is no perfect way of reading the auxiliary vector. /// -/// - If the `std_detect_dlsym_getauxval` cargo feature is enabled, this will use -/// `getauxval` if its linked to the binary, and otherwise proceed to a fallback implementation. -/// When `std_detect_dlsym_getauxval` is disabled, this will assume that `getauxval` is -/// linked to the binary - if that is not the case the behavior is undefined. -/// - Otherwise, if the `std_detect_file_io` cargo feature is enabled, it will +/// - If [`getauxval`] is linked to the binary we use it, and otherwise it will /// try to read `/proc/self/auxv`. /// - If that fails, this function returns an error. /// /// Note that run-time feature detection is not invoked for features that can /// be detected at compile-time. /// -/// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on -/// `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval` -/// is linked to the binary. +/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos}*` and +/// `*-android*` targets rather than `dlsym` it because we can safely assume +/// `getauxval` is linked to the binary. /// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) /// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). /// - `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) @@ -71,6 +67,7 @@ pub(crate) struct AuxVec { /// /// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h /// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ +/// [`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html pub(crate) fn auxv() -> Result { // Try to call a getauxval function. if let Ok(hwcap) = getauxval(AT_HWCAP) { @@ -115,16 +112,9 @@ pub(crate) fn auxv() -> Result { let _ = hwcap; } - #[cfg(feature = "std_detect_file_io")] - { - // If calling getauxval fails, try to read the auxiliary vector from - // its file: - auxv_from_file("/proc/self/auxv").map_err(|_| ()) - } - #[cfg(not(feature = "std_detect_file_io"))] - { - Err(()) - } + // If calling getauxval fails, try to read the auxiliary vector from + // its file: + auxv_from_file("/proc/self/auxv").map_err(|_| ()) } /// Tries to read the `key` from the auxiliary vector by calling the @@ -132,14 +122,16 @@ pub(crate) fn auxv() -> Result { fn getauxval(key: usize) -> Result { type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong; cfg_select! { - all( - feature = "std_detect_dlsym_getauxval", - not(all( + any( + all( target_os = "linux", any(target_env = "gnu", target_env = "musl", target_env = "ohos"), - )), - not(target_os = "android"), + ), + target_os = "android", ) => { + let ffi_getauxval: F = libc::getauxval; + } + _ => { let ffi_getauxval: F = unsafe { let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr()); if ptr.is_null() { @@ -148,23 +140,18 @@ fn getauxval(key: usize) -> Result { core::mem::transmute(ptr) }; } - _ => { - let ffi_getauxval: F = libc::getauxval; - } } Ok(unsafe { ffi_getauxval(key as libc::c_ulong) as usize }) } /// Tries to read the auxiliary vector from the `file`. If this fails, this /// function returns `Err`. -#[cfg(feature = "std_detect_file_io")] pub(super) fn auxv_from_file(file: &str) -> Result { let file = super::read_file(file)?; auxv_from_file_bytes(&file) } /// Read auxiliary vector from a slice of bytes. -#[cfg(feature = "std_detect_file_io")] pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result { // See . // @@ -181,7 +168,6 @@ pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result Result { // Targets with only AT_HWCAP: #[cfg(any( diff --git a/library/std_detect/src/detect/os/linux/auxvec/tests.rs b/library/std_detect/src/detect/os/linux/auxvec/tests.rs index 631a3e5e9ef17..88f0d6d493376 100644 --- a/library/std_detect/src/detect/os/linux/auxvec/tests.rs +++ b/library/std_detect/src/detect/os/linux/auxvec/tests.rs @@ -41,7 +41,6 @@ fn auxv_dump() { } } -#[cfg(feature = "std_detect_file_io")] cfg_select! { target_arch = "arm" => { // The tests below can be executed under qemu, where we do not have access to the test @@ -86,7 +85,6 @@ cfg_select! { } #[test] -#[cfg(feature = "std_detect_file_io")] fn auxv_dump_procfs() { if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") { println!("{:?}", auxvec); @@ -103,7 +101,6 @@ fn auxv_dump_procfs() { target_arch = "s390x", ))] #[test] -#[cfg(feature = "std_detect_file_io")] fn auxv_crate_procfs() { if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") { assert_eq!(auxv().unwrap(), procfs_auxv); diff --git a/library/std_detect/src/detect/os/linux/mod.rs b/library/std_detect/src/detect/os/linux/mod.rs index 5273c16c0893c..aec94f963f5c1 100644 --- a/library/std_detect/src/detect/os/linux/mod.rs +++ b/library/std_detect/src/detect/os/linux/mod.rs @@ -1,11 +1,9 @@ //! Run-time feature detection on Linux -//! -#[cfg(feature = "std_detect_file_io")] + use alloc::vec::Vec; mod auxvec; -#[cfg(feature = "std_detect_file_io")] fn read_file(orig_path: &str) -> Result, alloc::string::String> { use alloc::format; diff --git a/library/std_detect/src/lib.rs b/library/std_detect/src/lib.rs index 73e2f5dd96442..5e1d21bbfd17d 100644 --- a/library/std_detect/src/lib.rs +++ b/library/std_detect/src/lib.rs @@ -27,8 +27,7 @@ extern crate std; // rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare> -#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))] -#[cfg(feature = "std_detect_file_io")] +#[allow(unused_extern_crates)] extern crate alloc; #[doc(hidden)] diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index eec8c461b6db4..a188680829166 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -20,7 +20,7 @@ test = { path = "../test", public = true } # Forward features to the `std` crate as necessary [features] -default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] +default = ["panic-unwind"] backtrace = ["std/backtrace"] backtrace-trace-only = ["std/backtrace-trace-only"] compiler-builtins-c = ["std/compiler-builtins-c"] @@ -32,7 +32,5 @@ system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] panic-unwind = ["std/panic-unwind"] profiler = ["dep:profiler_builtins"] -std_detect_file_io = ["std/std_detect_file_io"] -std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] windows_raw_dylib = ["std/windows_raw_dylib"] llvm_enzyme = ["std/llvm_enzyme"] diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs index 5b2ff41ef0529..73dc08dc2b576 100644 --- a/tests/codegen-llvm/direct-access-external-data.rs +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -1,21 +1,48 @@ -//@ only-loongarch64-unknown-linux-gnu +//@ ignore-powerpc64 (handles dso_local differently) +//@ ignore-apple (handles dso_local differently) -//@ revisions: DEFAULT DIRECT INDIRECT +//@ revisions: DEFAULT PIE DIRECT INDIRECT //@ [DEFAULT] compile-flags: -C relocation-model=static -//@ [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes +//@ [PIE] compile-flags: -C relocation-model=pie +//@ [DIRECT] compile-flags: -C relocation-model=pie -Z direct-access-external-data=yes //@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no #![crate_type = "rlib"] +#![feature(linkage)] -// DEFAULT: @VAR = external {{.*}} global i32 -// DIRECT: @VAR = external dso_local {{.*}} global i32 -// INDIRECT: @VAR = external {{.*}} global i32 +unsafe extern "C" { + // CHECK: @VAR = external + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i32 + safe static VAR: i32; -extern "C" { - static VAR: i32; + // When "linkage" is used, we generate an indirection global. + // Check dso_local is still applied to the actual global. + // CHECK: @EXTERNAL = external + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "external"] + safe static EXTERNAL: *const u32; + + // CHECK: @WEAK = extern_weak + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "extern_weak"] + safe static WEAK: *const u32; } #[no_mangle] -pub fn get() -> i32 { - unsafe { VAR } +pub fn refer() { + core::hint::black_box(VAR); + core::hint::black_box(EXTERNAL); + core::hint::black_box(WEAK); } diff --git a/tests/ui/const-generics/mgca/type_const-array-return.rs b/tests/ui/const-generics/mgca/type_const-array-return.rs new file mode 100644 index 0000000000000..5375e4fded6d7 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-array-return.rs @@ -0,0 +1,26 @@ +//@ check-pass +// This test should compile without an ICE. +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +pub struct A; + +pub trait Array { + #[type_const] + const LEN: usize; + fn arr() -> [u8; Self::LEN]; +} + +impl Array for A { + #[type_const] + const LEN: usize = 4; + + #[allow(unused_braces)] + fn arr() -> [u8; const { Self::LEN }] { + return [0u8; const { Self::LEN }]; + } +} + +fn main() { + let _ = A::arr(); +} diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs new file mode 100644 index 0000000000000..b2c7340980091 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs @@ -0,0 +1,12 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +struct A; + +impl A { + #[type_const] + const B = 4; + //~^ ERROR: missing type for `const` item +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr new file mode 100644 index 0000000000000..b44e47cd7e611 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr @@ -0,0 +1,13 @@ +error: missing type for `const` item + --> $DIR/type_const-inherent-const-omitted-type.rs:8:12 + | +LL | const B = 4; + | ^ + | +help: provide a type for the item + | +LL | const B: = 4; + | ++++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs new file mode 100644 index 0000000000000..ab613859aa5c6 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs @@ -0,0 +1,22 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +trait BadTr { + const NUM: usize; +} + +struct GoodS; + +impl BadTr for GoodS { + #[type_const] + const NUM: = 84; + //~^ ERROR: missing type for `const` item + +} + +fn accept_bad_tr>(_x: &T) {} +//~^ ERROR use of trait associated const without `#[type_const]` + +fn main() { + accept_bad_tr::<84, _>(&GoodS); +} diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr new file mode 100644 index 0000000000000..16f312454ed28 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr @@ -0,0 +1,16 @@ +error: missing type for `const` item + --> $DIR/type_const-only-in-impl-omitted-type.rs:12:15 + | +LL | const NUM: = 84; + | ^ help: provide a type for the associated constant: `usize` + +error: use of trait associated const without `#[type_const]` + --> $DIR/type_const-only-in-impl-omitted-type.rs:17:43 + | +LL | fn accept_bad_tr>(_x: &T) {} + | ^^^^^^^^^^^ + | + = note: the declaration in the trait must be marked with `#[type_const]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/type_const-recursive.rs b/tests/ui/const-generics/mgca/type_const-recursive.rs new file mode 100644 index 0000000000000..15e49f747ed6b --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-recursive.rs @@ -0,0 +1,8 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +#[type_const] +const A: u8 = A; +//~^ ERROR: overflow normalizing the unevaluated constant `A` [E0275] + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-recursive.stderr b/tests/ui/const-generics/mgca/type_const-recursive.stderr new file mode 100644 index 0000000000000..947319ec7eda2 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-recursive.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow normalizing the unevaluated constant `A` + --> $DIR/type_const-recursive.rs:5:1 + | +LL | const A: u8 = A; + | ^^^^^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/const-generics/mgca/type_const-use.rs b/tests/ui/const-generics/mgca/type_const-use.rs new file mode 100644 index 0000000000000..04362cd285384 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-use.rs @@ -0,0 +1,13 @@ +//@ check-pass +// This test should compile without an ICE. +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +#[type_const] +const CONST: usize = 1; + +fn uses_const() { + CONST; +} + +fn main() {} diff --git a/tests/ui/eii/auxiliary/codegen1.rs b/tests/ui/eii/auxiliary/other_crate_privacy1.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen1.rs rename to tests/ui/eii/auxiliary/other_crate_privacy1.rs diff --git a/tests/ui/eii/auxiliary/codegen3.rs b/tests/ui/eii/auxiliary/other_crate_privacy2.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen3.rs rename to tests/ui/eii/auxiliary/other_crate_privacy2.rs diff --git a/tests/ui/eii/multiple_decls.rs b/tests/ui/eii/duplicate/multiple_decls.rs similarity index 100% rename from tests/ui/eii/multiple_decls.rs rename to tests/ui/eii/duplicate/multiple_decls.rs diff --git a/tests/ui/eii/multiple_decls.stderr b/tests/ui/eii/duplicate/multiple_decls.stderr similarity index 100% rename from tests/ui/eii/multiple_decls.stderr rename to tests/ui/eii/duplicate/multiple_decls.stderr diff --git a/tests/ui/eii/multiple_impls.rs b/tests/ui/eii/duplicate/multiple_impls.rs similarity index 100% rename from tests/ui/eii/multiple_impls.rs rename to tests/ui/eii/duplicate/multiple_impls.rs diff --git a/tests/ui/eii/multiple_impls.run.stdout b/tests/ui/eii/duplicate/multiple_impls.run.stdout similarity index 100% rename from tests/ui/eii/multiple_impls.run.stdout rename to tests/ui/eii/duplicate/multiple_impls.run.stdout diff --git a/tests/ui/eii/auxiliary/codegen2.rs b/tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen2.rs rename to tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/linking/codegen_cross_crate.rs similarity index 82% rename from tests/ui/eii/codegen_cross_crate.rs rename to tests/ui/eii/linking/codegen_cross_crate.rs index a1fa617491bd7..4016712e7504a 100644 --- a/tests/ui/eii/codegen_cross_crate.rs +++ b/tests/ui/eii/linking/codegen_cross_crate.rs @@ -1,6 +1,6 @@ //@ run-pass //@ check-run-results -//@ aux-build: codegen2.rs +//@ aux-build: codegen_cross_crate_other_crate.rs //@ compile-flags: -O //@ ignore-backends: gcc // FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 @@ -8,7 +8,7 @@ // Tests whether calling EIIs works with the declaration in another crate. #![feature(extern_item_impls)] -extern crate codegen2 as codegen; +extern crate codegen_cross_crate_other_crate as codegen; #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/codegen_cross_crate.run.stdout b/tests/ui/eii/linking/codegen_cross_crate.run.stdout similarity index 100% rename from tests/ui/eii/codegen_cross_crate.run.stdout rename to tests/ui/eii/linking/codegen_cross_crate.run.stdout diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/linking/codegen_single_crate.rs similarity index 100% rename from tests/ui/eii/codegen_single_crate.rs rename to tests/ui/eii/linking/codegen_single_crate.rs diff --git a/tests/ui/eii/codegen_single_crate.run.stdout b/tests/ui/eii/linking/codegen_single_crate.run.stdout similarity index 100% rename from tests/ui/eii/codegen_single_crate.run.stdout rename to tests/ui/eii/linking/codegen_single_crate.run.stdout diff --git a/tests/ui/eii/same-symbol.rs b/tests/ui/eii/linking/same-symbol.rs similarity index 100% rename from tests/ui/eii/same-symbol.rs rename to tests/ui/eii/linking/same-symbol.rs diff --git a/tests/ui/eii/same-symbol.run.stdout b/tests/ui/eii/linking/same-symbol.run.stdout similarity index 100% rename from tests/ui/eii/same-symbol.run.stdout rename to tests/ui/eii/linking/same-symbol.run.stdout diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index b5bbf68bfdaf6..72aec83d2cee0 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -1,13 +1,13 @@ //@ run-pass //@ check-run-results -//@ aux-build: codegen1.rs +//@ aux-build: other_crate_privacy1.rs //@ ignore-backends: gcc -// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether re-exports work. #![feature(extern_item_impls)] -extern crate codegen1 as codegen; +extern crate other_crate_privacy1 as codegen; #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index a0bc26ef629b7..e3f1f8c863da0 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -1,8 +1,8 @@ -//@ aux-build:codegen3.rs +//@ aux-build:other_crate_privacy2.rs // Tests whether name resolution respects privacy properly. #![feature(extern_item_impls)] -extern crate codegen3 as codegen; +extern crate other_crate_privacy2 as codegen; // has a span but in the other crate //~? ERROR `#[eii2]` required, but not found diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index 903285d4d1e37..9f4fd6a071c9c 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -11,24 +11,24 @@ LL | codegen::decl1(42); | ^^^^^ private function | note: the function `decl1` is defined here - --> $DIR/auxiliary/codegen3.rs:7:1 + --> $DIR/auxiliary/other_crate_privacy2.rs:7:1 | LL | fn decl1(x: u64); | ^^^^^^^^^^^^^^^^^ error: `#[eii2]` required, but not found - --> $DIR/auxiliary/codegen3.rs:9:7 + --> $DIR/auxiliary/other_crate_privacy2.rs:9:7 | LL | #[eii(eii2)] - | ^^^^ expected because `#[eii2]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii2]` was declared here in crate `other_crate_privacy2` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies error: `#[eii3]` required, but not found - --> $DIR/auxiliary/codegen3.rs:13:11 + --> $DIR/auxiliary/other_crate_privacy2.rs:13:11 | LL | #[eii(eii3)] - | ^^^^ expected because `#[eii3]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii3]` was declared here in crate `other_crate_privacy2` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs similarity index 100% rename from tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs rename to tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs diff --git a/tests/ui/eii/cross_crate.rs b/tests/ui/eii/type_checking/cross_crate_type_ok.rs similarity index 100% rename from tests/ui/eii/cross_crate.rs rename to tests/ui/eii/type_checking/cross_crate_type_ok.rs diff --git a/tests/ui/eii/cross_crate_wrong_ty.rs b/tests/ui/eii/type_checking/cross_crate_wrong_ty.rs similarity index 100% rename from tests/ui/eii/cross_crate_wrong_ty.rs rename to tests/ui/eii/type_checking/cross_crate_wrong_ty.rs diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr similarity index 100% rename from tests/ui/eii/cross_crate_wrong_ty.stderr rename to tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr