diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 42eb8673f30c0..350fa04ab3bdc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2517,6 +2517,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, } } + ExprKind::Array(elements) => { + let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| { + let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind { + let def_id = self.local_def_id(anon_const.id); + assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id)); + self.lower_anon_const_to_const_arg(anon_const) + } else { + self.lower_expr_to_const_arg_direct(element) + }; + &*self.arena.alloc(const_arg) + })); + let array_expr = self.arena.alloc(hir::ConstArgArrayExpr { + span: self.lower_span(expr.span), + elems: lowered_elems, + }); + + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Array(array_expr), + span, + } + } ExprKind::Underscore => ConstArg { hir_id: self.lower_node_id(expr.id), kind: hir::ConstArgKind::Infer(()), @@ -2532,6 +2554,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | ExprKind::Struct(..) | ExprKind::Call(..) | ExprKind::Tup(..) + | ExprKind::Array(..) ) { return self.lower_expr_to_const_arg_direct(expr); diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 01c503357fc79..5604fbd25edcd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -9,7 +9,7 @@ impl SingleAttributeParser for CrateNameParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(n) = args else { @@ -33,7 +33,7 @@ impl SingleAttributeParser for RecursionLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -56,7 +56,7 @@ impl SingleAttributeParser for MoveSizeLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -79,7 +79,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -102,7 +102,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -123,7 +123,7 @@ pub(crate) struct NoCoreParser; impl NoArgsAttributeParser for NoCoreParser { const PATH: &[Symbol] = &[sym::no_core]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore; } @@ -132,7 +132,7 @@ pub(crate) struct NoStdParser; impl NoArgsAttributeParser for NoStdParser { const PATH: &[Symbol] = &[sym::no_std]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd; } @@ -141,7 +141,7 @@ pub(crate) struct RustcCoherenceIsCoreParser; impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore; } @@ -151,7 +151,7 @@ impl SingleAttributeParser for WindowsSubsystemParser { const PATH: &[Symbol] = &[sym::windows_subsystem]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b85bb6c6c89d4..527e3f567cf3d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; -use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId}; +use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; use rustc_errors::{Diag, Diagnostic, Level}; use rustc_feature::{AttrSuggestionStyle, AttributeTemplate}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; +use rustc_hir::{AttrPath, HirId}; use rustc_session::Session; use rustc_session::lint::{Lint, LintId}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; @@ -303,8 +303,6 @@ pub trait Stage: Sized + 'static + Sealed { ) -> ErrorGuaranteed; fn should_emit(&self) -> ShouldEmit; - - fn id_is_crate_root(id: Self::Id) -> bool; } // allow because it's a sealed trait @@ -326,10 +324,6 @@ impl Stage for Early { fn should_emit(&self) -> ShouldEmit { self.emit_errors } - - fn id_is_crate_root(id: Self::Id) -> bool { - id == CRATE_NODE_ID - } } // allow because it's a sealed trait @@ -351,10 +345,6 @@ impl Stage for Late { fn should_emit(&self) -> ShouldEmit { ShouldEmit::ErrorsAndLints } - - fn id_is_crate_root(id: Self::Id) -> bool { - id == CRATE_HIR_ID - } } /// used when parsing attributes for miscellaneous things *before* ast lowering diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 88fa3e436292d..52c2d10f47977 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -15,11 +15,6 @@ use crate::session_diagnostics::InvalidTarget; pub(crate) enum AllowedTargets { AllowList(&'static [Policy]), AllowListWarnRest(&'static [Policy]), - /// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`. - /// For crate-level attributes we emit a specific set of lints to warn - /// people about accidentally not using them on the crate. - /// Only use this for attributes that are *exclusively* valid at the crate level. - CrateLevel, } pub(crate) enum AllowedResult { @@ -53,7 +48,6 @@ impl AllowedTargets { AllowedResult::Warn } } - AllowedTargets::CrateLevel => AllowedResult::Allowed, } } @@ -61,7 +55,6 @@ impl AllowedTargets { match self { AllowedTargets::AllowList(list) => list, AllowedTargets::AllowListWarnRest(list) => list, - AllowedTargets::CrateLevel => ALL_TARGETS, } .iter() .filter_map(|target| match target { @@ -95,7 +88,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target: Target, cx: &mut AcceptContext<'_, 'sess, S>, ) { - Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx); + if allowed_targets.allowed_targets() == &[Target::Crate] { + Self::check_crate_level(target, cx); + return; + } match allowed_targets.is_allowed(target) { AllowedResult::Allowed => {} @@ -149,18 +145,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } } - pub(crate) fn check_type( - crate_level: bool, - target: Target, - cx: &mut AcceptContext<'_, 'sess, S>, - ) { - let is_crate_root = S::id_is_crate_root(cx.target_id); - - if is_crate_root { - return; - } - - if !crate_level { + pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) { + // For crate-level attributes we emit a specific set of lints to warn + // people about accidentally not using them on the crate. + if target == Target::Crate { return; } diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 2d67608609e39..734737199ba5f 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -108,7 +108,7 @@ fn eii_( let mut return_items = Vec::new(); if func.body.is_some() { - return_items.push(Box::new(generate_default_impl( + return_items.push(generate_default_impl( ecx, &func, impl_unsafe, @@ -116,24 +116,24 @@ fn eii_( eii_attr_span, item_span, foreign_item_name, - ))) + )) } - return_items.push(Box::new(generate_foreign_item( + return_items.push(generate_foreign_item( ecx, eii_attr_span, item_span, func, vis, &attrs_from_decl, - ))); - return_items.push(Box::new(generate_attribute_macro_to_implement( + )); + return_items.push(generate_attribute_macro_to_implement( ecx, eii_attr_span, macro_name, foreign_item_name, impl_unsafe, - ))); + )); return_items.into_iter().map(wrap_item).collect() } @@ -193,7 +193,7 @@ fn generate_default_impl( eii_attr_span: Span, item_span: Span, foreign_item_name: Ident, -) -> ast::Item { +) -> Box { // FIXME: re-add some original attrs let attrs = ThinVec::new(); @@ -210,124 +210,72 @@ fn generate_default_impl( span: eii_attr_span, is_default: true, known_eii_macro_resolution: Some(ast::EiiExternTarget { - extern_item_path: ast::Path { - span: foreign_item_name.span, - segments: thin_vec![ - ast::PathSegment { - ident: Ident::from_str_and_span("super", foreign_item_name.span,), - id: DUMMY_NODE_ID, - args: None - }, - ast::PathSegment { ident: foreign_item_name, id: DUMMY_NODE_ID, args: None }, - ], - tokens: None, - }, + extern_item_path: ecx.path( + foreign_item_name.span, + // prefix super to escape the `dflt` module generated below + vec![Ident::from_str_and_span("super", foreign_item_name.span), foreign_item_name], + ), impl_unsafe, }), }); - ast::Item { - attrs: ThinVec::new(), - id: ast::DUMMY_NODE_ID, - span: eii_attr_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - kind: ast::ItemKind::Const(Box::new(ast::ConstItem { - ident: Ident { name: kw::Underscore, span: eii_attr_span }, - defaultness: ast::Defaultness::Final, - generics: ast::Generics::default(), - ty: Box::new(ast::Ty { - id: DUMMY_NODE_ID, - kind: ast::TyKind::Tup(ThinVec::new()), - span: eii_attr_span, - tokens: None, - }), - rhs: Some(ast::ConstItemRhs::Body(Box::new(ast::Expr { - id: DUMMY_NODE_ID, - kind: ast::ExprKind::Block( - Box::new(ast::Block { - stmts: thin_vec![ast::Stmt { - id: DUMMY_NODE_ID, - kind: ast::StmtKind::Item(Box::new(ast::Item { - attrs: ThinVec::new(), - id: DUMMY_NODE_ID, - span: item_span, - vis: ast::Visibility { - span: item_span, - kind: ast::VisibilityKind::Inherited, - tokens: None - }, - kind: ItemKind::Mod( - ast::Safety::Default, - Ident::from_str_and_span("dflt", item_span), - ast::ModKind::Loaded( - thin_vec![ - Box::new(ast::Item { - attrs: thin_vec![ecx.attr_nested_word( - sym::allow, - sym::unused_imports, - item_span - ),], - id: DUMMY_NODE_ID, - span: item_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None - }, - kind: ItemKind::Use(ast::UseTree { - prefix: ast::Path::from_ident( - Ident::from_str_and_span( - "super", item_span, - ) - ), - kind: ast::UseTreeKind::Glob, - span: item_span, - }), - tokens: None, - }), - Box::new(ast::Item { - attrs, - id: DUMMY_NODE_ID, - span: item_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None - }, - kind: ItemKind::Fn(Box::new(default_func)), - tokens: None, - }), - ], - ast::Inline::Yes, - ast::ModSpans { - inner_span: item_span, - inject_use_span: item_span, - } - ) - ), - tokens: None, - })), - span: eii_attr_span, - }], - id: DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: eii_attr_span, - tokens: None, - }), - None, + let item_mod = |span: Span, name: Ident, items: ThinVec>| { + ecx.item( + item_span, + ThinVec::new(), + ItemKind::Mod( + ast::Safety::Default, + name, + ast::ModKind::Loaded( + items, + ast::Inline::Yes, + ast::ModSpans { inner_span: span, inject_use_span: span }, ), - span: eii_attr_span, - attrs: ThinVec::new(), - tokens: None, - }))), - define_opaque: None, - })), - tokens: None, - } + ), + ) + }; + + let anon_mod = |span: Span, stmts: ThinVec| { + let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new())); + let underscore = Ident::new(kw::Underscore, item_span); + ecx.item_const( + span, + underscore, + unit, + ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))), + ) + }; + + // const _: () = { + // mod dflt { + // use super::*; + // + // } + // } + anon_mod( + item_span, + thin_vec![ecx.stmt_item( + item_span, + item_mod( + item_span, + Ident::from_str_and_span("dflt", item_span), + thin_vec![ + ecx.item( + item_span, + thin_vec![ecx.attr_nested_word(sym::allow, sym::unused_imports, item_span)], + ItemKind::Use(ast::UseTree { + prefix: ast::Path::from_ident(Ident::from_str_and_span( + "super", item_span, + )), + kind: ast::UseTreeKind::Glob, + span: item_span, + }) + ), + ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func))) + ] + ) + ),], + ) } /// Generates a foreign item, like @@ -342,7 +290,7 @@ fn generate_foreign_item( mut func: ast::Fn, vis: Visibility, attrs_from_decl: &[Attribute], -) -> ast::Item { +) -> Box { let mut foreign_item_attrs = ThinVec::new(); foreign_item_attrs.extend_from_slice(attrs_from_decl); @@ -374,16 +322,10 @@ fn generate_foreign_item( func.sig.header.safety = ast::Safety::Safe(func.sig.span); } - ast::Item { - attrs: ast::AttrVec::default(), - id: ast::DUMMY_NODE_ID, - span: eii_attr_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - kind: ast::ItemKind::ForeignMod(ast::ForeignMod { + ecx.item( + eii_attr_span, + ThinVec::new(), + ast::ItemKind::ForeignMod(ast::ForeignMod { extern_span: eii_attr_span, safety: ast::Safety::Unsafe(eii_attr_span), abi, @@ -396,8 +338,7 @@ fn generate_foreign_item( tokens: None, })]), }), - tokens: None, - } + ) } /// Generate a stub macro (a bit like in core) that will roughly look like: @@ -416,13 +357,14 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, -) -> ast::Item { +) -> Box { let mut macro_attrs = ThinVec::new(); // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); - ast::Item { + // cant use ecx methods here to construct item since we need it to be public + Box::new(ast::Item { attrs: macro_attrs, id: ast::DUMMY_NODE_ID, span, @@ -461,7 +403,7 @@ fn generate_attribute_macro_to_implement( }, ), tokens: None, - } + }) } pub(crate) fn eii_extern_target( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9b08f4e9869cf..63f820dc29184 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -379,19 +379,19 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { { false } - // Unsupported - (Arch::Arm64EC, _) => false, + // Unsupported (fixed in llvm22) + (Arch::Arm64EC, _) if major < 22 => false, // Selection failure (fixed in llvm21) (Arch::S390x, _) if major < 21 => false, // MinGW ABI bugs (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false, // Infinite recursion - (Arch::CSky, _) => false, + (Arch::CSky, _) if major < 22 => false, // (fixed in llvm22) (Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21) (Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21) - (Arch::PowerPC | Arch::PowerPC64, _) => false, - (Arch::Sparc | Arch::Sparc64, _) => false, - (Arch::Wasm32 | Arch::Wasm64, _) => false, + (Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22) + (Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22) + (Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22) // `f16` support only requires that symbols converting to and from `f32` are available. We // provide these in `compiler-builtins`, so `f16` should be available on all platforms that // do not have other ABI issues or LLVM crashes. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2fb6daf6469b7..055df9c2a0852 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -513,6 +513,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> { Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]), /// Tuple constructor variant TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]), + /// Array literal argument + Array(&'hir ConstArgArrayExpr<'hir>), /// Error const Error(ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes @@ -529,6 +531,12 @@ pub struct ConstArgExprField<'hir> { pub expr: &'hir ConstArg<'hir>, } +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub struct ConstArgArrayExpr<'hir> { + pub span: Span, + pub elems: &'hir [&'hir ConstArg<'hir>], +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct InferArg { #[stable_hasher(ignore)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e5e6fc7b1d8de..d1b75325af268 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1101,6 +1101,12 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( } V::Result::output() } + ConstArgKind::Array(array_expr) => { + for arg in array_expr.elems { + try_visit!(visitor.visit_const_arg_unambig(*arg)); + } + V::Result::output() + } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1dd9bff425759..6f44a728242d7 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2389,6 +2389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::TupleCall(qpath, args) => { self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span) } + hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, feed), hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), @@ -2402,6 +2403,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + fn lower_const_arg_array( + &self, + array_expr: &'tcx hir::ConstArgArrayExpr<'tcx>, + feed: FeedConstTy<'tcx>, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + let FeedConstTy::WithTy(ty) = feed else { + return Const::new_error_with_message(tcx, array_expr.span, "unsupported const array"); + }; + + let ty::Array(elem_ty, _) = ty.kind() else { + return Const::new_error_with_message( + tcx, + array_expr.span, + "const array must have an array type", + ); + }; + + let elems = array_expr + .elems + .iter() + .map(|elem| self.lower_const_arg(elem, FeedConstTy::WithTy(*elem_ty))) + .collect::>(); + + let valtree = ty::ValTree::from_branches(tcx, elems); + + ty::Const::new_value(tcx, valtree, ty) + } + fn lower_const_arg_tuple_call( &self, hir_id: HirId, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 37fa18c00887e..e0e9fe7758535 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1153,6 +1153,7 @@ impl<'a> State<'a> { } ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields), ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), + ConstArgKind::Array(..) => self.word("/* ARRAY EXPR */"), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_) => self.word("/*ERROR*/"), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index eedb88783ec0e..a62826cd7cec0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1441,6 +1441,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Skip encoding defs for these as they should not have had a `DefId` created hir::ConstArgKind::Error(..) | hir::ConstArgKind::Struct(..) + | hir::ConstArgKind::Array(..) | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Path(..) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b392b7747b554..ea5640ecc1fa9 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -419,7 +419,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Avoid overwriting `const_arg_context` as we may want to treat const blocks // as being anon consts if we are inside a const argument. - ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) => { + ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) | ExprKind::Array(..) => { return visit::walk_expr(self, expr); } // FIXME(mgca): we may want to handle block labels in some manner diff --git a/library/alloctests/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs index 778065fd96575..c2bf43caf131e 100644 --- a/library/alloctests/benches/btree/map.rs +++ b/library/alloctests/benches/btree/map.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use std::ops::RangeBounds; use rand::Rng; +use rand::distr::{Distribution, Uniform}; use rand::seq::SliceRandom; use test::{Bencher, black_box}; @@ -106,7 +107,8 @@ macro_rules! map_find_rand_bench { // setup let mut rng = crate::bench_rng(); - let mut keys: Vec<_> = (0..n).map(|_| rng.random::() % n).collect(); + let mut keys: Vec<_> = + Uniform::new(0, n).unwrap().sample_iter(&mut rng).take(n as usize).collect(); for &k in &keys { map.insert(k, k); diff --git a/library/alloctests/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs index 0f1ec664d3d4f..1ed645cf99dca 100644 --- a/library/alloctests/tests/sort/patterns.rs +++ b/library/alloctests/tests/sort/patterns.rs @@ -27,21 +27,20 @@ where { // :.:.:.:: - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); // Abstracting over ranges in Rust :( let dist = Uniform::try_from(range).unwrap(); - (0..len).map(|_| dist.sample(&mut rng)).collect() + rng.sample_iter(dist).take(len).collect() } pub fn random_zipf(len: usize, exponent: f64) -> Vec { // https://en.wikipedia.org/wiki/Zipf's_law - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - // Abstracting over ranges in Rust :( let dist = ZipfDistribution::new(len, exponent).unwrap(); - (0..len).map(|_| dist.sample(&mut rng) as i32).collect() + rng.sample_iter(dist).map(|val| val as i32).take(len).collect() } pub fn random_sorted(len: usize, sorted_percent: f64) -> Vec { @@ -68,7 +67,7 @@ pub fn all_equal(len: usize) -> Vec { // ...... // :::::: - (0..len).map(|_| 66).collect::>() + vec![66; len] } pub fn ascending(len: usize) -> Vec { @@ -206,6 +205,6 @@ fn rand_root_seed() -> u64 { } fn random_vec(len: usize) -> Vec { - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - (0..len).map(|_| rng.random::()).collect() + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + rng.random_iter().take(len).collect() } diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index ee40d2b74c647..b9bdb827209b3 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -337,7 +337,6 @@ impl Peekable { /// /// Parse the leading decimal number from an iterator of characters. /// ``` - /// #![feature(peekable_next_if_map)] /// let mut iter = "125 GOTO 10".chars().peekable(); /// let mut line_num = 0_u32; /// while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) { @@ -349,7 +348,6 @@ impl Peekable { /// /// Matching custom types. /// ``` - /// #![feature(peekable_next_if_map)] /// /// #[derive(Debug, PartialEq, Eq)] /// enum Node { @@ -408,7 +406,7 @@ impl Peekable { ///# ], ///# ) /// ``` - #[unstable(feature = "peekable_next_if_map", issue = "143702")] + #[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")] pub fn next_if_map(&mut self, f: impl FnOnce(I::Item) -> Result) -> Option { let unpeek = if let Some(item) = self.next() { match f(item) { @@ -437,7 +435,6 @@ impl Peekable { /// /// Parse the leading decimal number from an iterator of characters. /// ``` - /// #![feature(peekable_next_if_map)] /// let mut iter = "125 GOTO 10".chars().peekable(); /// let mut line_num = 0_u32; /// while let Some(digit) = iter.next_if_map_mut(|c| c.to_digit(10)) { @@ -446,7 +443,7 @@ impl Peekable { /// assert_eq!(line_num, 125); /// assert_eq!(iter.collect::(), " GOTO 10"); /// ``` - #[unstable(feature = "peekable_next_if_map", issue = "143702")] + #[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")] pub fn next_if_map_mut(&mut self, f: impl FnOnce(&mut I::Item) -> Option) -> Option { let unpeek = if let Some(mut item) = self.next() { match f(&mut item) { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 094a074b7027f..419f66089b10c 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1906,9 +1906,12 @@ pub trait Iterator { /// Transforms an iterator into a collection. /// - /// `collect()` can take anything iterable, and turn it into a relevant - /// collection. This is one of the more powerful methods in the standard - /// library, used in a variety of contexts. + /// `collect()` takes ownership of an iterator and produces whichever + /// collection type you request. The iterator itself carries no knowledge of + /// the eventual container; the target collection is chosen entirely by the + /// type you ask `collect()` to return. This makes `collect()` one of the + /// more powerful methods in the standard library, and it shows up in a wide + /// variety of contexts. /// /// The most basic pattern in which `collect()` is used is to turn one /// collection into another. You take a collection, call [`iter`] on it, diff --git a/library/coretests/benches/num/int_bits/mod.rs b/library/coretests/benches/num/int_bits/mod.rs index 43531b0b5de99..c6ec51f248baa 100644 --- a/library/coretests/benches/num/int_bits/mod.rs +++ b/library/coretests/benches/num/int_bits/mod.rs @@ -4,11 +4,12 @@ macro_rules! bench_template { ($op:path, $name:ident, $mask:expr) => { #[bench] fn $name(bench: &mut ::test::Bencher) { - use ::rand::Rng; + use ::rand::distr::{Distribution, Uniform}; let mut rng = crate::bench_rng(); let mut dst = vec![0; ITERATIONS]; - let src1: Vec = (0..ITERATIONS).map(|_| rng.random_range(0..=U::MAX)).collect(); - let mut src2: Vec = (0..ITERATIONS).map(|_| rng.random_range(0..=U::MAX)).collect(); + let distr = &Uniform::try_from(0..=U::MAX).unwrap(); + let src1: Vec = distr.sample_iter(&mut rng).take(ITERATIONS).collect(); + let mut src2: Vec = distr.sample_iter(&mut rng).take(ITERATIONS).collect(); // Fix the loop invariant mask src2[0] = U::MAX / 3; let dst = dst.first_chunk_mut().unwrap(); diff --git a/library/coretests/benches/num/int_sqrt/mod.rs b/library/coretests/benches/num/int_sqrt/mod.rs index 05cb3c5383b27..56172f71dd88c 100644 --- a/library/coretests/benches/num/int_sqrt/mod.rs +++ b/library/coretests/benches/num/int_sqrt/mod.rs @@ -1,3 +1,5 @@ +use std::iter; + use rand::Rng; use test::{Bencher, black_box}; @@ -20,7 +22,9 @@ macro_rules! int_sqrt_bench { let mut rng = crate::bench_rng(); /* Exponentially distributed random numbers from the whole range of the type. */ let numbers: Vec<$t> = - (0..256).map(|_| rng.random::<$t>() >> rng.random_range(0..<$t>::BITS)).collect(); + iter::repeat_with(|| rng.random::<$t>() >> rng.random_range(0..<$t>::BITS)) + .take(256) + .collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); @@ -32,9 +36,10 @@ macro_rules! int_sqrt_bench { fn $random_small(bench: &mut Bencher) { let mut rng = crate::bench_rng(); /* Exponentially distributed random numbers from the range 0..256. */ - let numbers: Vec<$t> = (0..256) - .map(|_| (rng.random::() >> rng.random_range(0..u8::BITS)) as $t) - .collect(); + let numbers: Vec<$t> = + iter::repeat_with(|| (rng.random::() >> rng.random_range(0..u8::BITS)) as $t) + .take(256) + .collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); @@ -44,9 +49,9 @@ macro_rules! int_sqrt_bench { #[bench] fn $random_uniform(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); + let rng = crate::bench_rng(); /* Exponentially distributed random numbers from the whole range of the type. */ - let numbers: Vec<$t> = (0..256).map(|_| rng.random::<$t>()).collect(); + let numbers: Vec<$t> = rng.random_iter().take(256).collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b28e7338859c4..6a8b6d9ba154f 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -90,7 +90,6 @@ #![feature(one_sided_range)] #![feature(option_reduce)] #![feature(pattern)] -#![feature(peekable_next_if_map)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 7c7ef7b2f7018..e4a30b80e3df4 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -37,7 +37,8 @@ fn connect_error() { e.kind() == ErrorKind::ConnectionRefused || e.kind() == ErrorKind::InvalidInput || e.kind() == ErrorKind::AddrInUse - || e.kind() == ErrorKind::AddrNotAvailable, + || e.kind() == ErrorKind::AddrNotAvailable + || e.kind() == ErrorKind::NetworkUnreachable, "bad error: {} {:?}", e, e.kind() diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 6d4090ee31cfc..708ebaec362e4 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -92,9 +92,138 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::io::{self, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, Write}; #[stable(feature = "rust1", since = "1.0.0")] pub use crate::os::fd::*; +#[allow(unused_imports)] // not used on all targets +use crate::sys::cvt; // Tests for this module #[cfg(test)] mod tests; + +#[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] +pub trait StdioExt: crate::sealed::Sealed { + /// Redirects the stdio file descriptor to point to the file description underpinning `fd`. + /// + /// Rust std::io write buffers (if any) are flushed, but other runtimes + /// (e.g. C stdio) or libraries that acquire a clone of the file descriptor + /// will not be aware of this change. + /// + /// # Platform-specific behavior + /// + /// This is [currently] implemented using + /// + /// - `fd_renumber` on wasip1 + /// - `dup2` on most unixes + /// + /// [currently]: crate::io#platform-specific-behavior + /// + /// ``` + /// #![feature(stdio_swap)] + /// use std::io::{self, Read, Write}; + /// use std::os::unix::io::StdioExt; + /// + /// fn main() -> io::Result<()> { + /// let (reader, mut writer) = io::pipe()?; + /// let mut stdin = io::stdin(); + /// stdin.set_fd(reader)?; + /// writer.write_all(b"Hello, world!")?; + /// let mut buffer = vec![0; 13]; + /// assert_eq!(stdin.read(&mut buffer)?, 13); + /// assert_eq!(&buffer, b"Hello, world!"); + /// Ok(()) + /// } + /// ``` + fn set_fd>(&mut self, fd: T) -> io::Result<()>; + + /// Redirects the stdio file descriptor and returns a new `OwnedFd` + /// backed by the previous file description. + /// + /// See [`set_fd()`] for details. + /// + /// [`set_fd()`]: StdioExt::set_fd + fn replace_fd>(&mut self, replace_with: T) -> io::Result; + + /// Redirects the stdio file descriptor to the null device (`/dev/null`) + /// and returns a new `OwnedFd` backed by the previous file description. + /// + /// Programs that communicate structured data via stdio can use this early in `main()` to + /// extract the fds, treat them as other IO types (`File`, `UnixStream`, etc), + /// apply custom buffering or avoid interference from stdio use later in the program. + /// + /// See [`set_fd()`] for additional details. + /// + /// [`set_fd()`]: StdioExt::set_fd + fn take_fd(&mut self) -> io::Result; +} + +macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $writer:literal) { + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_ty { + fn set_fd>(&mut self, fd: T) -> io::Result<()> { + self.lock().set_fd(fd) + } + + fn take_fd(&mut self) -> io::Result { + self.lock().take_fd() + } + + fn replace_fd>(&mut self, replace_with: T) -> io::Result { + self.lock().replace_fd(replace_with) + } + } + + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_lock_ty { + fn set_fd>(&mut self, fd: T) -> io::Result<()> { + #[cfg($writer)] + self.flush()?; + replace_stdio_fd(self.as_fd(), fd.into()) + } + + fn take_fd(&mut self) -> io::Result { + let null = null_fd()?; + let cloned = self.as_fd().try_clone_to_owned()?; + self.set_fd(null)?; + Ok(cloned) + } + + fn replace_fd>(&mut self, replace_with: T) -> io::Result { + let cloned = self.as_fd().try_clone_to_owned()?; + self.set_fd(replace_with)?; + Ok(cloned) + } + } +} + +io_ext_impl!(Stdout, StdoutLock<'_>, true); +io_ext_impl!(Stdin, StdinLock<'_>, false); +io_ext_impl!(Stderr, StderrLock<'_>, true); + +fn null_fd() -> io::Result { + let null_dev = crate::fs::OpenOptions::new().read(true).write(true).open("/dev/null")?; + Ok(null_dev.into()) +} + +/// Replaces the underlying file descriptor with the one from `other`. +/// Does not set CLOEXEC. +fn replace_stdio_fd(this: BorrowedFd<'_>, other: OwnedFd) -> io::Result<()> { + cfg_select! { + all(target_os = "wasi", target_env = "p1") => { + cvt(unsafe { libc::__wasilibc_fd_renumber(other.as_raw_fd(), this.as_raw_fd()) }).map(|_| ()) + } + not(any( + target_arch = "wasm32", + target_os = "hermit", + target_os = "trusty", + target_os = "motor" + )) => { + cvt(unsafe {libc::dup2(other.as_raw_fd(), this.as_raw_fd())}).map(|_| ()) + } + _ => { + let _ = (this, other); + Err(io::Error::UNSUPPORTED_PLATFORM) + } + } +} diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index fcf21d9e97318..e596260d9dca7 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -285,11 +285,11 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - unsupported() + self.datasync() } pub fn datasync(&self) -> io::Result<()> { - unsupported() + self.0.flush() } pub fn lock(&self) -> io::Result<()> { @@ -348,12 +348,29 @@ impl File { false } + // Write::flush is only meant for buffered writers. So should be noop for unbuffered files. pub fn flush(&self) -> io::Result<()> { - unsupported() + Ok(()) } - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - unsupported() + pub fn seek(&self, pos: SeekFrom) -> io::Result { + const NEG_OFF_ERR: io::Error = + io::const_error!(io::ErrorKind::InvalidInput, "cannot seek to negative offset."); + + let off = match pos { + SeekFrom::Start(p) => p, + SeekFrom::End(p) => { + // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. + if p == 0 { + 0xFFFFFFFFFFFFFFFF + } else { + self.file_attr()?.size().checked_add_signed(p).ok_or(NEG_OFF_ERR)? + } + } + SeekFrom::Current(p) => self.tell()?.checked_add_signed(p).ok_or(NEG_OFF_ERR)?, + }; + + self.0.set_position(off).map(|_| off) } pub fn size(&self) -> Option> { @@ -755,6 +772,12 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(pos) } } + pub(crate) fn set_position(&self, pos: u64) -> io::Result<()> { + let file_ptr = self.protocol.as_ptr(); + let r = unsafe { ((*file_ptr).set_position)(file_ptr, pos) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + pub(crate) fn delete(self) -> io::Result<()> { let file_ptr = self.protocol.as_ptr(); let r = unsafe { ((*file_ptr).delete)(file_ptr) }; @@ -765,6 +788,12 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } + pub(crate) fn flush(&self) -> io::Result<()> { + let file_ptr = self.protocol.as_ptr(); + let r = unsafe { ((*file_ptr).flush)(file_ptr) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + pub(crate) fn path(&self) -> &Path { &self.path } diff --git a/src/bootstrap/download-ci-gcc-stamp b/src/bootstrap/download-ci-gcc-stamp index bbe26afc95269..ec8d0fa3135d1 100644 --- a/src/bootstrap/download-ci-gcc-stamp +++ b/src/bootstrap/download-ci-gcc-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-gcc` configuration download a new version of GCC from CI, even if the GCC submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/138051 +Last change is for: https://github.com/rust-lang/rust/pull/150873 diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 43efdcd7db173..074404b4cdf3e 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -396,7 +396,7 @@ impl Config { "; self.download_file(&format!("{base}/{gcc_sha}/{filename}"), &tarball, help_on_error); } - self.unpack(&tarball, root_dir, "gcc"); + self.unpack(&tarball, root_dir, "gcc-dev"); } } diff --git a/src/ci/run.sh b/src/ci/run.sh index 425ad38a66557..b486f0525f40d 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -187,9 +187,8 @@ else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp" fi - # Download GCC from CI on test builders (temporarily disabled because the CI gcc component - # was renamed). - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=false" + # Download GCC from CI on test builders + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=true" # download-rustc seems to be broken on CI after the stage0 redesign # Disable it until these issues are debugged and resolved diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 817eda4c52ecc..597a85f397695 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -330,6 +330,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind // FIXME(mgca): proper printing :3 ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() } } + hir::ConstArgKind::Array(..) => { + ConstantKind::Path { path: "/* ARRAY EXPR */".to_string().into() } + } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, hir::ConstArgKind::Literal(..) => { @@ -1818,6 +1821,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T | hir::ConstArgKind::Path(..) | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Tup(..) + | hir::ConstArgKind::Array(..) | hir::ConstArgKind::Literal(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 4c57683806e6a..5bbed35e2068b 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -84,7 +84,7 @@ const TEST_REPOS: &[Test] = &[ Test { name: "diesel", repo: "https://github.com/diesel-rs/diesel", - sha: "91493fe47175076f330ce5fc518f0196c0476f56", + sha: "3db7c17c5b069656ed22750e84d6498c8ab5b81d", lock: None, packages: &[], // Test the embedded sqlite variant of diesel diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index acea701b2e830..8243077cab897 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -321,6 +321,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), + ConstArgKind::Array(..) => chain!(self, "let ConstArgKind::Array(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 538f1fd2628c9..e2ada37d53b39 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1144,6 +1144,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx | ConstArgKind::Tup(..) | ConstArgKind::Literal(..) | ConstArgKind::TupleCall(..) + | ConstArgKind::Array(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0bb641568879c..c7bb3a064a093 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -687,6 +687,11 @@ impl HirEqInterExpr<'_, '_, '_> { .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) }, (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => kind_l == kind_r, + (ConstArgKind::Array(l_arr), ConstArgKind::Array(r_arr)) => { + l_arr.elems.len() == r_arr.elems.len() + && l_arr.elems.iter().zip(r_arr.elems.iter()) + .all(|(l_elem, r_elem)| self.eq_const_arg(l_elem, r_elem)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) @@ -696,6 +701,7 @@ impl HirEqInterExpr<'_, '_, '_> { | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Literal(..) + | ConstArgKind::Array(..) | ConstArgKind::Error(..), _, ) => false, @@ -1575,6 +1581,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, + ConstArgKind::Array(array_expr) => { + for elem in array_expr.elems { + self.hash_const_arg(elem); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, ConstArgKind::Literal(lit) => lit.hash(&mut self.s), } diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index f86933029341e..694a5922b7990 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -249,6 +249,15 @@ impl FileDescription for io::Stdin { finish.call(ecx, result) } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -279,6 +288,15 @@ impl FileDescription for io::Stdout { finish.call(ecx, result) } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -289,6 +307,15 @@ impl FileDescription for io::Stderr { "stderr" } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn write<'tcx>( self: FileDescriptionRef, _communicate_allowed: bool, @@ -436,6 +463,15 @@ impl FileDescription for NullOutput { // We just don't write anything, but report to the user that we did. finish.call(ecx, Ok(len)) } + + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } } /// Internal type of a file-descriptor - this is what [`FdTable`] expects diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs deleted file mode 100644 index 7911133f548ff..0000000000000 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ignore-target: windows # No libc IO on Windows -//@compile-flags: -Zmiri-disable-isolation - -// FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) - -fn main() { - unsafe { - libc::close(1); //~ ERROR: cannot close stdout - } -} diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr deleted file mode 100644 index 84973ac020ded..0000000000000 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: unsupported operation: cannot close stdout - --> tests/fail-dep/libc/fs/close_stdout.rs:LL:CC - | -LL | libc::close(1); - | ^^^^^^^^^^^^^^ unsupported operation occurred here - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 99685d6d976b6..8c860b5db7baf 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -48,6 +48,7 @@ fn main() { test_nofollow_not_symlink(); #[cfg(target_os = "macos")] test_ioctl(); + test_close_stdout(); } fn test_file_open_unix_allow_two_args() { @@ -579,3 +580,11 @@ fn test_ioctl() { assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); } } + +fn test_close_stdout() { + // This is std library UB, but that's not relevant since we're + // only interacting with libc here. + unsafe { + libc::close(1); + } +} diff --git a/tests/assembly-llvm/rust-abi-arg-attr.rs b/tests/assembly-llvm/rust-abi-arg-attr.rs index 4f3673ccfc3b9..2d13feb021ba5 100644 --- a/tests/assembly-llvm/rust-abi-arg-attr.rs +++ b/tests/assembly-llvm/rust-abi-arg-attr.rs @@ -1,3 +1,4 @@ +//@ add-minicore //@ assembly-output: emit-asm //@ revisions: riscv64 riscv64-zbb loongarch64 //@ compile-flags: -C opt-level=3 @@ -14,45 +15,8 @@ #![no_std] #![no_core] // FIXME: Migrate these code after PR #130693 is landed. - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -#[lang = "copy"] -trait Copy {} - -impl Copy for i8 {} -impl Copy for u32 {} -impl Copy for i32 {} - -#[lang = "neg"] -trait Neg { - type Output; - - fn neg(self) -> Self::Output; -} - -impl Neg for i8 { - type Output = i8; - - fn neg(self) -> Self::Output { - -self - } -} - -#[lang = "Ordering"] -#[repr(i8)] -enum Ordering { - Less = -1, - Equal = 0, - Greater = 1, -} +extern crate minicore; +use minicore::*; #[rustc_intrinsic] fn three_way_compare(lhs: T, rhs: T) -> Ordering; diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 122a3a226015a..95b217c130317 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -210,6 +210,14 @@ impl Neg for isize { } } +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> i8 { + loop {} + } +} + #[lang = "sync"] pub trait Sync {} impl_marker_trait!( @@ -280,6 +288,16 @@ pub enum c_void { __variant2, } +#[lang = "Ordering"] +#[repr(i8)] +pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +impl Copy for Ordering {} + #[lang = "const_param_ty"] #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy_ {} diff --git a/tests/ui/const-generics/mgca/array-expr-complex.rs b/tests/ui/const-generics/mgca/array-expr-complex.rs new file mode 100644 index 0000000000000..3e8320bc94de2 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-complex.rs @@ -0,0 +1,16 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] + +fn takes_array() {} + +fn generic_caller() { + // not supported yet + takes_array::<{ [1, 2, 1 + 2] }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + takes_array::<{ [X; 3] }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + takes_array::<{ [0; Y] }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-complex.stderr b/tests/ui/const-generics/mgca/array-expr-complex.stderr new file mode 100644 index 0000000000000..beac1aa232f2f --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-complex.stderr @@ -0,0 +1,20 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr-complex.rs:8:28 + | +LL | takes_array::<{ [1, 2, 1 + 2] }>(); + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr-complex.rs:10:19 + | +LL | takes_array::<{ [X; 3] }>(); + | ^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr-complex.rs:12:19 + | +LL | takes_array::<{ [0; Y] }>(); + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/const-generics/mgca/array-expr-empty.rs b/tests/ui/const-generics/mgca/array-expr-empty.rs new file mode 100644 index 0000000000000..d37c6f2fcfe35 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-empty.rs @@ -0,0 +1,9 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +fn takes_empty_array() {} +//~^ ERROR: expected type, found `]` + +fn main() { + takes_empty_array::<{ [] }>(); +} diff --git a/tests/ui/const-generics/mgca/array-expr-empty.stderr b/tests/ui/const-generics/mgca/array-expr-empty.stderr new file mode 100644 index 0000000000000..91340e621acbb --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-empty.stderr @@ -0,0 +1,8 @@ +error: expected type, found `]` + --> $DIR/array-expr-empty.rs:4:32 + | +LL | fn takes_empty_array() {} + | ^ expected type + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/array-expr-simple.rs b/tests/ui/const-generics/mgca/array-expr-simple.rs new file mode 100644 index 0000000000000..44feeccb4f9f2 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-simple.rs @@ -0,0 +1,25 @@ +//@ run-pass +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] +#![allow(dead_code)] + +fn takes_array_u32() {} +fn takes_array_bool() {} +fn takes_nested_array() {} +fn takes_empty_array() {} + +fn generic_caller() { + takes_array_u32::<{ [X, Y, X] }>(); + takes_array_u32::<{ [X, Y, const { 1 }] }>(); + takes_array_u32::<{ [X, Y, const { 1 + 1 }] }>(); + takes_array_u32::<{ [2_002, 2u32, 1_u32] }>(); + + takes_array_bool::<{ [true, false] }>(); + + takes_nested_array::<{ [[X, Y], [3, 4]] }>(); + takes_nested_array::<{ [[1u32, 2_u32], [const { 3 }, 4]] }>(); + + takes_empty_array::<{ [] }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs b/tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs new file mode 100644 index 0000000000000..47ecbfa6b7e15 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs @@ -0,0 +1,18 @@ +//@ run-pass +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] +#![allow(dead_code)] + +fn takes_array() {} + +trait Trait { + #[type_const] + const ASSOC: u32; +} + +fn generic_caller() { + takes_array::<{ [T::ASSOC, N, T::ASSOC] }>(); + takes_array::<{ [1_u32, T::ASSOC, 2] }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-macro.rs b/tests/ui/const-generics/mgca/array-expr-with-macro.rs new file mode 100644 index 0000000000000..aef5acc1c8030 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-macro.rs @@ -0,0 +1,18 @@ +//@ run-pass +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] +#![allow(dead_code)] + +macro_rules! make_array { + ($n:expr, $m:expr, $p:expr) => { + [N, $m, $p] + }; +} + +fn takes_array() {} + +fn generic_caller() { + takes_array::<{ make_array!(N, 2, 3) }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-struct.rs b/tests/ui/const-generics/mgca/array-expr-with-struct.rs new file mode 100644 index 0000000000000..883af57e918e3 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-struct.rs @@ -0,0 +1,20 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::marker::ConstParamTy; + +#[derive(PartialEq, Eq, ConstParamTy)] +struct Container { + values: [u32; 3], +} + +fn takes_container() {} + +fn generic_caller() { + takes_container::<{ Container { values: [N, M, 1] } }>(); + takes_container::<{ Container { values: [1, 2, 3] } }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-tuple.rs b/tests/ui/const-generics/mgca/array-expr-with-tuple.rs new file mode 100644 index 0000000000000..004663dcefaba --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-tuple.rs @@ -0,0 +1,13 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +fn takes_tuple() {} + +fn generic_caller() { + takes_tuple::<{ ([N, M], 5, [M, N]) }>(); + takes_tuple::<{ ([1, 2], 3, [4, 5]) }>(); +} + +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 9b71bf55f2182..89118fdb5948f 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1365,11 +1365,11 @@ message = "The rustc-dev-guide subtree was changed. If this PR *only* touches th cc = ["@BoxyUwU", "@jieyouxu", "@kobzol", "@tshepang"] [mentions."compiler/rustc_passes/src/check_attr.rs"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."compiler/rustc_attr_parsing"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."compiler/rustc_hir/src/attrs"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."src/tools/enzyme"] cc = ["@ZuseZ4"]