diff --git a/RELEASES.md b/RELEASES.md index c396cd8069d6d..c1cf337ea8d2a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,134 @@ +Version 1.95 (2026-04-16) +========================== + + + +Language +-------- +- [Stabilize `if let` guards on match arms](https://github.com/rust-lang/rust/pull/141295) +- [`irrefutable_let_patterns` lint no longer lints on let chains](https://github.com/rust-lang/rust/pull/146832) +- [Support importing path-segment keywords with renaming](https://github.com/rust-lang/rust/pull/146972) +- [Stabilize inline assembly for PowerPC and PowerPC64](https://github.com/rust-lang/rust/pull/147996) +- [const-eval: be more consistent in the behavior of padding during typed copies](https://github.com/rust-lang/rust/pull/148967) +- [Const blocks are no longer evaluated to determine if expressions involving fallible operations can implicitly be constant-promoted.](https://github.com/rust-lang/rust/pull/150557). Expressions whose ability to implicitly be promoted would depend on the result of a const block are no longer implicitly promoted. +- [Make operational semantics of pattern matching independent of crate and module](https://github.com/rust-lang/rust/pull/150681) + + + + +Compiler +-------- +- [Stabilize `--remap-path-scope` for controlling the scoping of how paths get remapped in the resulting binary](https://github.com/rust-lang/rust/pull/147611) + + + + +Platform Support +---------------- +- [Promote `powerpc64-unknown-linux-musl` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/149962) +- [Promote `aarch64-apple-tvos` to Tier 2](https://github.com/rust-lang/rust/pull/152021) +- [Promote `aarch64-apple-tvos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021) +- [Promote `aarch64-apple-watchos` to Tier 2](https://github.com/rust-lang/rust/pull/152021) +- [Promote `aarch64-apple-watchos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021) +- [Promote `aarch64-apple-visionos` to Tier 2](https://github.com/rust-lang/rust/pull/152021) +- [Promote `aarch64-apple-visionos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021) + + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html + + + +Libraries +--------- +- [`thread::scope`: document how join interacts with TLS destructors](https://github.com/rust-lang/rust/pull/149482) +- [Speed up `str::contains` on aarch64 targets with `neon` target feature enabled by default](https://github.com/rust-lang/rust/pull/152176) + + + + +Stabilized APIs +--------------- + +- [`MaybeUninit<[T; N]>: From<[MaybeUninit; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3CMaybeUninit%3C%5BT;+N%5D%3E%3E-for-%5BMaybeUninit%3CT%3E;+N%5D) +- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E) +- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E) +- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit; N]>`](https://doc.rust-lang.org/beta/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E) +- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E) +- [`[MaybeUninit; N]: From>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E) +- [`Cell<[T; N]>: AsRef<[Cell; N]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E;+N%5D%3E-for-Cell%3C%5BT;+N%5D%3E) +- [`Cell<[T; N]>: AsRef<[Cell]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT;+N%5D%3E) +- [`Cell<[T]>: AsRef<[Cell]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT%5D%3E) +- [`bool: TryFrom<{integer}>`](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-TryFrom%3Cu128%3E-for-bool) +- [`AtomicPtr::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.update) +- [`AtomicPtr::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.try_update) +- [`AtomicBool::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.update) +- [`AtomicBool::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.try_update) +- [`AtomicIn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.update) +- [`AtomicIn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.try_update) +- [`AtomicUn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.update) +- [`AtomicUn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.try_update) +- [`cfg_select!`](https://doc.rust-lang.org/stable/std/macro.cfg_select.html) +- [`mod core::range`](https://doc.rust-lang.org/stable/core/range/index.html) +- [`core::range::RangeInclusive`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusive.html) +- [`core::range::RangeInclusiveIter`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusiveIter.html) +- [`core::hint::cold_path`](https://doc.rust-lang.org/stable/core/hint/fn.cold_path.html) +- [`<*const T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked) +- [`<*mut T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked-1) +- [`<*mut T>::as_mut_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_unchecked) + + +These previously stable APIs are now stable in const contexts: + +- [`fmt::from_fn`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html) +- [`ControlFlow::is_break`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_break) +- [`ControlFlow::is_continue`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_continue) + + + + +Cargo +----- +- [docs(report): enhance man pages for `cargo report *`](https://github.com/rust-lang/cargo/pull/16430/) + +Rustdoc +----- +- [In search results, rank unstable items lower](https://github.com/rust-lang/rust/pull/149460) +- [Add new "hide deprecated items" setting in rustdoc](https://github.com/rust-lang/rust/pull/151091) + + +Compatibility Notes +------------------- +- [Array coercions may now result in less inference constraints than before](https://github.com/rust-lang/rust/pull/140283) +- Importing `$crate` without renaming, i.e. `use $crate::{self};`, is now no longer permitted due to stricter error checking for `self` imports. +- [const-eval: be more consistent in the behavior of padding during typed copies.](https://github.com/rust-lang/rust/pull/148967) + In very rare cases, this may cause compilation errors due to bytes from parts of a pointer ending up in the padding bytes of a `const` or `static`. +- [A future-incompatibility warning lint `ambiguous_glob_imported_traits` is now reported when using an ambiguously glob imported trait](https://github.com/rust-lang/rust/pull/149058) +- [Check lifetime bounds of types mentioning only type parameters](https://github.com/rust-lang/rust/pull/149389) +- [Report more visibility-related ambiguous import errors](https://github.com/rust-lang/rust/pull/149596) +- [Deprecate `Eq::assert_receiver_is_total_eq` and emit future compatibility warnings on manual impls](https://github.com/rust-lang/rust/pull/149978) +- [powerpc64: Use the ELF ABI version set in target spec instead of guessing](https://github.com/rust-lang/rust/pull/150468) (fixes the ELF ABI used by the OpenBSD target) +- Matching on a `#[non_exhaustive]` enum [now reads the discriminant, even if the enum has only one variant](https://github.com/rust-lang/rust/pull/150681). This can cause closures to capture values that they previously wouldn't. +- `mut ref` and `mut ref mut` patterns, part of the unstable [Match Ergonomics 2024 RFC](https://github.com/rust-lang/rust/issues/123076), were accidentally allowed on stable within struct pattern field shorthand. These patterns are now correctly feature-gated as unstable in this position. +- [Add future-compatibility warning for derive helper attributes which conflict with built-in attributes](https://github.com/rust-lang/rust/pull/151152) +- [JSON target specs](https://doc.rust-lang.org/rustc/targets/custom.html) have been destabilized and now require `-Z unstable-options` to use. Previously, they could not be used without the standard library, which has no stable build mechanism. In preparation for the `build-std` project adding that support, JSON target specs are being proactively gated to ensure they remain unstable even if `build-std` is stabilized. Cargo now includes the `-Z json-target-spec` CLI flag to automatically pass `-Z unstable-options` to the compiler when needed. See [#150151](https://github.com/rust-lang/rust/pull/150151), [#151534](https://github.com/rust-lang/rust/pull/150151), and [rust-lang/cargo#16557](https://github.com/rust-lang/cargo/pull/16557). +- [The arguments of `#[feature]` attributes on invalid targets are now checked](https://github.com/rust-lang/rust/issues/153764) + + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Update to LLVM 22](https://github.com/rust-lang/rust/pull/150722) + + Version 1.94.1 (2026-03-26) =========================== diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index ae4989fcbc6c9..ad32fe7e488c1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3918,6 +3918,13 @@ pub struct StaticItem { pub mutability: Mutability, pub expr: Option>, pub define_opaque: Option>, + + /// This static is an implementation of an externally implementable item (EII). + /// This means, there was an EII declared somewhere and this static is the + /// implementation that should be used for the declaration. + /// + /// For statics, there may be at most one `EiiImpl`, but this is a `ThinVec` to make usages of this field nicer. + pub eii_impls: ThinVec, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3939cb1901d44..080e9cb9235f9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -213,8 +213,14 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { i: &ItemKind, ) -> Vec { match i { - ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(), - ItemKind::Fn(box Fn { eii_impls, .. }) => { + ItemKind::Fn(box Fn { eii_impls, .. }) + | ItemKind::Static(box StaticItem { eii_impls, .. }) + if eii_impls.is_empty() => + { + Vec::new() + } + ItemKind::Fn(box Fn { eii_impls, .. }) + | ItemKind::Static(box StaticItem { eii_impls, .. }) => { vec![hir::Attribute::Parsed(AttributeKind::EiiImpls( eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(), ))] @@ -226,7 +232,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { ItemKind::ExternCrate(..) | ItemKind::Use(..) - | ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::ConstBlock(..) | ItemKind::Mod(..) @@ -302,6 +307,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { mutability: m, expr: e, define_opaque, + eii_impls: _, }) => { let ident = self.lower_ident(*ident); let ty = self @@ -826,6 +832,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { expr: _, safety, define_opaque, + eii_impls: _, }) => { let ty = self .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 3e9c596148343..201fa63bfa33c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -43,6 +43,7 @@ impl<'a> State<'a> { expr, safety, define_opaque, + eii_impls, }) => self.print_item_const( *ident, Some(*mutability), @@ -53,6 +54,7 @@ impl<'a> State<'a> { *safety, ast::Defaultness::Implicit, define_opaque.as_deref(), + eii_impls, ), ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, @@ -93,8 +95,12 @@ impl<'a> State<'a> { safety: ast::Safety, defaultness: ast::Defaultness, define_opaque: Option<&[(ast::NodeId, ast::Path)]>, + eii_impls: &[EiiImpl], ) { self.print_define_opaques(define_opaque); + for eii_impl in eii_impls { + self.print_eii_impl(eii_impl); + } let (cb, ib) = self.head(""); self.print_visibility(vis); self.print_safety(safety); @@ -191,6 +197,7 @@ impl<'a> State<'a> { mutability: mutbl, expr: body, define_opaque, + eii_impls, }) => { self.print_safety(*safety); self.print_item_const( @@ -203,6 +210,7 @@ impl<'a> State<'a> { ast::Safety::Default, ast::Defaultness::Implicit, define_opaque.as_deref(), + eii_impls, ); } ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => { @@ -234,6 +242,7 @@ impl<'a> State<'a> { ast::Safety::Default, *defaultness, define_opaque.as_deref(), + &[], ); } ast::ItemKind::Fn(func) => { @@ -602,6 +611,7 @@ impl<'a> State<'a> { ast::Safety::Default, *defaultness, define_opaque.as_deref(), + &[], ); } ast::AssocItemKind::Type(box ast::TyAlias { @@ -703,18 +713,8 @@ impl<'a> State<'a> { self.print_define_opaques(define_opaque.as_deref()); - for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls { - self.word("#["); - if let Safety::Unsafe(..) = impl_safety { - self.word("unsafe"); - self.popen(); - } - self.print_path(eii_macro_path, false, 0); - if let Safety::Unsafe(..) = impl_safety { - self.pclose(); - } - self.word("]"); - self.hardbreak(); + for eii_impl in eii_impls { + self.print_eii_impl(eii_impl); } let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); @@ -741,6 +741,20 @@ impl<'a> State<'a> { } } + fn print_eii_impl(&mut self, eii: &ast::EiiImpl) { + self.word("#["); + if let Safety::Unsafe(..) = eii.impl_safety { + self.word("unsafe"); + self.popen(); + } + self.print_path(&eii.eii_macro_path, false, 0); + if let Safety::Unsafe(..) = eii.impl_safety { + self.pclose(); + } + self.word("]"); + self.hardbreak(); + } + fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) { if let Some(define_opaque) = define_opaque { self.word("#[define_opaque("); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index f0cb348540da1..73b2727fdab0a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -709,7 +709,8 @@ pub(crate) struct RustcEiiForeignItemParser; impl NoArgsAttributeParser for RustcEiiForeignItemParser { const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index def4069f6b477..23db854252a37 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -17,6 +17,7 @@ impl AttributeParser for OnConstParser { template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]), |this, cx, args| { if !cx.features().diagnostic_on_const() { + // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs return; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index 006b3b66658e0..a79b7d6afbcdc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -24,6 +24,7 @@ impl OnMoveParser { mode: Mode, ) { if !cx.features().diagnostic_on_move() { + // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs return; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index bd5eb4cbf82c7..dcfba68a4cf8b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -18,6 +18,7 @@ impl OnUnknownParser { mode: Mode, ) { if !cx.features().diagnostic_on_unknown() { + // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs return; } let span = cx.attr_span; diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 7b651ed848288..fd0ef8500c6c3 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,7 +1,8 @@ use rustc_ast::token::{Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::{ - Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast, + Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Mutability, Path, StmtKind, + Visibility, ast, }; use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -10,8 +11,9 @@ use thin_vec::{ThinVec, thin_vec}; use crate::errors::{ EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, - EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction, - EiiSharedMacroInStatementPosition, + EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition, + EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault, + EiiStaticMultipleImplementations, EiiStaticMutable, }; /// ```rust @@ -73,44 +75,72 @@ fn eii_( }); return vec![orig_item]; } else { - ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { + ecx.dcx().emit_err(EiiSharedMacroTarget { span: eii_attr_span, name: path_to_string(&meta_item.path), }); return vec![orig_item]; }; - let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } = - item.as_ref() - else { - ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { - span: eii_attr_span, - name: path_to_string(&meta_item.path), - }); - return vec![Annotatable::Item(item)]; + let ast::Item { attrs, id: _, span: _, vis, kind, tokens: _ } = item.as_ref(); + let (item_span, foreign_item_name) = match kind { + ItemKind::Fn(func) => (func.sig.span, func.ident), + ItemKind::Static(stat) => { + // Statics with a default are not supported yet + if let Some(stat_body) = &stat.expr { + ecx.dcx().emit_err(EiiStaticDefault { + span: stat_body.span, + name: path_to_string(&meta_item.path), + }); + return vec![]; + } + // Statics must have an explicit name for the eii + if meta_item.is_word() { + ecx.dcx().emit_err(EiiStaticArgumentRequired { + span: eii_attr_span, + name: path_to_string(&meta_item.path), + }); + return vec![]; + } + + // Mut statics are currently not supported + if stat.mutability == Mutability::Mut { + ecx.dcx().emit_err(EiiStaticMutable { + span: eii_attr_span, + name: path_to_string(&meta_item.path), + }); + } + + (item.span, stat.ident) + } + _ => { + ecx.dcx().emit_err(EiiSharedMacroTarget { + span: eii_attr_span, + name: path_to_string(&meta_item.path), + }); + return vec![Annotatable::Item(item)]; + } }; + // only clone what we need let attrs = attrs.clone(); - let func = (**func).clone(); let vis = vis.clone(); let attrs_from_decl = filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path); - let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else { + let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else { // we don't need to wrap in Annotatable::Stmt conditionally since // EII can't be used on items in statement position return vec![Annotatable::Item(item)]; }; - // span of the declaring item without attributes - let item_span = func.sig.span; - let foreign_item_name = func.ident; - let mut module_items = Vec::new(); - if func.body.is_some() { - module_items.push(generate_default_impl( + if let ItemKind::Fn(func) = kind + && func.body.is_some() + { + module_items.push(generate_default_func_impl( ecx, &func, impl_unsafe, @@ -125,7 +155,7 @@ fn eii_( ecx, eii_attr_span, item_span, - func, + kind, vis, &attrs_from_decl, )); @@ -148,11 +178,11 @@ fn eii_( /// declaration of the EII. fn name_for_impl_macro( ecx: &mut ExtCtxt<'_>, - func: &ast::Fn, + item_ident: Ident, meta_item: &MetaItem, ) -> Result { if meta_item.is_word() { - Ok(func.ident) + Ok(item_ident) } else if let Some([first]) = meta_item.meta_item_list() && let Some(m) = first.meta_item() && m.path.segments.len() == 1 @@ -190,7 +220,7 @@ fn filter_attrs_for_multiple_eii_attr( .collect() } -fn generate_default_impl( +fn generate_default_func_impl( ecx: &mut ExtCtxt<'_>, func: &ast::Fn, impl_unsafe: bool, @@ -257,7 +287,7 @@ fn generate_foreign_item( ecx: &mut ExtCtxt<'_>, eii_attr_span: Span, item_span: Span, - mut func: ast::Fn, + item_kind: &ItemKind, vis: Visibility, attrs_from_decl: &[Attribute], ) -> Box { @@ -268,30 +298,21 @@ fn generate_foreign_item( // This attribute makes sure that we later know that this foreign item's symbol should not be. foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span)); - let abi = match func.sig.header.ext { - // extern "X" fn => extern "X" {} - ast::Extern::Explicit(lit, _) => Some(lit), - // extern fn => extern {} - ast::Extern::Implicit(_) => None, - // fn => extern "Rust" {} - ast::Extern::None => Some(ast::StrLit { - symbol: sym::Rust, - suffix: None, - symbol_unescaped: sym::Rust, - style: ast::StrStyle::Cooked, - span: eii_attr_span, - }), + // We set the abi to the default "rust" abi, which can be overridden by `generate_foreign_func`, + // if a specific abi was specified on the EII function + let mut abi = Some(ast::StrLit { + symbol: sym::Rust, + suffix: None, + symbol_unescaped: sym::Rust, + style: ast::StrStyle::Cooked, + span: eii_attr_span, + }); + let foreign_kind = match item_kind { + ItemKind::Fn(func) => generate_foreign_func(func.clone(), &mut abi), + ItemKind::Static(stat) => generate_foreign_static(stat.clone()), + _ => unreachable!("Target was checked earlier"), }; - // ABI has been moved to the extern {} block, so we remove it from the fn item. - func.sig.header.ext = ast::Extern::None; - func.body = None; - - // And mark safe functions explicitly as `safe fn`. - if func.sig.header.safety == ast::Safety::Default { - func.sig.header.safety = ast::Safety::Safe(func.sig.span); - } - ecx.item( eii_attr_span, ThinVec::new(), @@ -304,13 +325,46 @@ fn generate_foreign_item( id: ast::DUMMY_NODE_ID, span: item_span, vis, - kind: ast::ForeignItemKind::Fn(Box::new(func.clone())), + kind: foreign_kind, tokens: None, })]), }), ) } +fn generate_foreign_func( + mut func: Box, + abi: &mut Option, +) -> ast::ForeignItemKind { + match func.sig.header.ext { + // extern "X" fn => extern "X" {} + ast::Extern::Explicit(lit, _) => *abi = Some(lit), + // extern fn => extern {} + ast::Extern::Implicit(_) => *abi = None, + // no abi was specified, so we keep the default + ast::Extern::None => {} + }; + + // ABI has been moved to the extern {} block, so we remove it from the fn item. + func.sig.header.ext = ast::Extern::None; + func.body = None; + + // And mark safe functions explicitly as `safe fn`. + if func.sig.header.safety == ast::Safety::Default { + func.sig.header.safety = ast::Safety::Safe(func.sig.span); + } + + ast::ForeignItemKind::Fn(func) +} + +fn generate_foreign_static(mut stat: Box) -> ast::ForeignItemKind { + if stat.safety == ast::Safety::Default { + stat.safety = ast::Safety::Safe(stat.ident.span); + } + + ast::ForeignItemKind::Static(stat) +} + /// Generate a stub macro (a bit like in core) that will roughly look like: /// /// ```rust, ignore, example @@ -453,19 +507,25 @@ pub(crate) fn eii_shared_macro( { item } else { - ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { - span, - name: path_to_string(&meta_item.path), - }); + ecx.dcx().emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) }); return vec![item]; }; - let ItemKind::Fn(f) = &mut i.kind else { - ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { - span, - name: path_to_string(&meta_item.path), - }); - return vec![item]; + let eii_impls = match &mut i.kind { + ItemKind::Fn(func) => &mut func.eii_impls, + ItemKind::Static(stat) => { + if !stat.eii_impls.is_empty() { + // Reject multiple implementations on one static item + // because it might be unintuitive for libraries defining statics the defined statics may alias + ecx.dcx().emit_err(EiiStaticMultipleImplementations { span }); + } + &mut stat.eii_impls + } + _ => { + ecx.dcx() + .emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) }); + return vec![item]; + } }; let is_default = if meta_item.is_word() { @@ -483,7 +543,7 @@ pub(crate) fn eii_shared_macro( return vec![item]; }; - f.eii_impls.push(EiiImpl { + eii_impls.push(EiiImpl { node_id: DUMMY_NODE_ID, inner_span: meta_item.path.span, eii_macro_path: meta_item.path.clone(), diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index b5ac84337465a..ad641beb87d98 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1117,8 +1117,42 @@ pub(crate) struct EiiExternTargetExpectedUnsafe { } #[derive(Diagnostic)] -#[diag("`#[{$name}]` is only valid on functions")] -pub(crate) struct EiiSharedMacroExpectedFunction { +#[diag("`#[{$name}]` is only valid on functions and statics")] +pub(crate) struct EiiSharedMacroTarget { + #[primary_span] + pub span: Span, + pub name: String, +} + +#[derive(Diagnostic)] +#[diag("static cannot implement multiple EIIs")] +#[note( + "this is not allowed because multiple externally implementable statics that alias may be unintuitive" +)] +pub(crate) struct EiiStaticMultipleImplementations { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("`#[{$name}]` cannot be used on statics with a value")] +pub(crate) struct EiiStaticDefault { + #[primary_span] + pub span: Span, + pub name: String, +} + +#[derive(Diagnostic)] +#[diag("`#[{$name}]` requires the name as an explicit argument when used on a static")] +pub(crate) struct EiiStaticArgumentRequired { + #[primary_span] + pub span: Span, + pub name: String, +} + +#[derive(Diagnostic)] +#[diag("`#[{$name}]` cannot be used on mutable statics")] +pub(crate) struct EiiStaticMutable { #[primary_span] pub span: Span, pub name: String, diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index caec20db4c2db..8921395ab76ce 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -211,3 +211,32 @@ pub(crate) struct FixedX18InvalidArch<'a> { "enabling both `-Zpacked-stack` and the `backchain` target feature is incompatible with the default s390x ABI. Switch to s390x-unknown-none-softfloat if you need both attributes" )] pub(crate) struct PackedStackBackchainNeedsSoftfloat; + +#[derive(Diagnostic)] +#[diag( + "intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`" +)] +pub(crate) struct IntrinsicSignatureMismatch<'a> { + pub name: &'a str, + pub llvm_fn_ty: &'a str, + pub rust_fn_ty: &'a str, + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("unknown LLVM intrinsic `{$name}`")] +pub(crate) struct UnknownIntrinsic<'a> { + pub name: &'a str, + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("intrinsic `{$name}` cannot be used with target arch `{$target_arch}`")] +pub(crate) struct IntrinsicWrongArch<'a> { + pub name: &'a str, + pub target_arch: &'a str, + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 3e600914d6f42..d46672bdffb7f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; use std::ffi::c_uint; -use std::{assert_matches, ptr}; +use std::{assert_matches, iter, ptr}; use rustc_abi::{ Align, BackendRepr, ExternAbi, Float, HasDataLayout, NumScalableVectors, Primitive, Size, @@ -21,10 +21,11 @@ use rustc_middle::ty::offload_meta::OffloadMetadata; use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; +use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; use rustc_target::callconv::PassMode; -use rustc_target::spec::Os; +use rustc_target::spec::{Arch, Os}; use tracing::debug; use crate::abi::FnAbiLlvmExt; @@ -36,7 +37,8 @@ use crate::builder::gpu_offload::{ use crate::context::CodegenCx; use crate::declare::declare_raw_fn; use crate::errors::{ - AutoDiffWithoutEnable, AutoDiffWithoutLto, OffloadWithoutEnable, OffloadWithoutFatLTO, + AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch, + OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, }; use crate::llvm::{self, Type, Value}; use crate::type_of::LayoutLlvmExt; @@ -818,7 +820,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { &mut self, instance: ty::Instance<'tcx>, args: &[OperandRef<'tcx, Self::Value>], - is_cleanup: bool, + _is_cleanup: bool, ) -> Self::Value { let tcx = self.tcx(); @@ -847,42 +849,29 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { llargument_tys.push(arg_layout.immediate_llvm_type(self)); } - let fn_ty = self.type_func(&llargument_tys, llreturn_ty); - let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) { llfn } else { let sym = tcx.symbol_name(instance).name; - // FIXME use get_intrinsic let llfn = if let Some(llfn) = self.get_declared_value(sym) { llfn } else { - // Function addresses in Rust are never significant, allowing functions to - // be merged. - let llfn = declare_raw_fn( - self, - sym, - llvm::CCallConv, - llvm::UnnamedAddr::Global, - llvm::Visibility::Default, - fn_ty, - ); - - llfn + intrinsic_fn(self, sym, llreturn_ty, llargument_tys, instance) }; self.intrinsic_instances.borrow_mut().insert(instance, llfn); llfn }; + let fn_ty = self.get_type_of_global(fn_ptr); let mut llargs = vec![]; for arg in args { match arg.val { OperandValue::ZeroSized => {} - OperandValue::Immediate(_) => llargs.push(arg.immediate()), + OperandValue::Immediate(a) => llargs.push(a), OperandValue::Pair(a, b) => { llargs.push(a); llargs.push(b); @@ -908,24 +897,38 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } debug!("call intrinsic {:?} with args ({:?})", instance, llargs); - let args = self.check_call("call", fn_ty, fn_ptr, &llargs); + + for (dest_ty, arg) in iter::zip(self.func_params_types(fn_ty), &mut llargs) { + let src_ty = self.val_ty(arg); + assert!( + can_autocast(self, src_ty, dest_ty), + "Cannot match `{dest_ty:?}` (expected) with {src_ty:?} (found) in `{fn_ptr:?}" + ); + + *arg = autocast(self, arg, src_ty, dest_ty); + } + let llret = unsafe { llvm::LLVMBuildCallWithOperandBundles( self.llbuilder, fn_ty, fn_ptr, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, + llargs.as_ptr(), + llargs.len() as c_uint, ptr::dangling(), 0, c"".as_ptr(), ) }; - if is_cleanup { - self.apply_attrs_to_cleanup_callsite(llret); - } - llret + let src_ty = self.val_ty(llret); + let dest_ty = llreturn_ty; + assert!( + can_autocast(self, dest_ty, src_ty), + "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`" + ); + + autocast(self, llret, src_ty, dest_ty) } fn abort(&mut self) { @@ -976,6 +979,239 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } +fn llvm_arch_for(rust_arch: &Arch) -> Option<&'static str> { + Some(match rust_arch { + Arch::AArch64 | Arch::Arm64EC => "aarch64", + Arch::AmdGpu => "amdgcn", + Arch::Arm => "arm", + Arch::Bpf => "bpf", + Arch::Hexagon => "hexagon", + Arch::LoongArch32 | Arch::LoongArch64 => "loongarch", + Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => "mips", + Arch::Nvptx64 => "nvvm", + Arch::PowerPC | Arch::PowerPC64 => "ppc", + Arch::RiscV32 | Arch::RiscV64 => "riscv", + Arch::S390x => "s390", + Arch::SpirV => "spv", + Arch::Wasm32 | Arch::Wasm64 => "wasm", + Arch::X86 | Arch::X86_64 => "x86", + _ => return None, // fallback for unknown archs + }) +} + +fn can_autocast<'ll>(cx: &CodegenCx<'ll, '_>, rust_ty: &'ll Type, llvm_ty: &'ll Type) -> bool { + if rust_ty == llvm_ty { + return true; + } + + match cx.type_kind(llvm_ty) { + // Some LLVM intrinsics return **non-packed** structs, but they can't be mimicked from Rust + // due to auto field-alignment in non-packed structs (packed structs are represented in LLVM + // as, well, packed structs, so they won't match with those either) + TypeKind::Struct if cx.type_kind(rust_ty) == TypeKind::Struct => { + let rust_element_tys = cx.struct_element_types(rust_ty); + let llvm_element_tys = cx.struct_element_types(llvm_ty); + + if rust_element_tys.len() != llvm_element_tys.len() { + return false; + } + + iter::zip(rust_element_tys, llvm_element_tys).all( + |(rust_element_ty, llvm_element_ty)| { + can_autocast(cx, rust_element_ty, llvm_element_ty) + }, + ) + } + TypeKind::Vector => { + let llvm_element_ty = cx.element_type(llvm_ty); + let element_count = cx.vector_length(llvm_ty) as u64; + + if llvm_element_ty == cx.type_bf16() { + rust_ty == cx.type_vector(cx.type_i16(), element_count) + } else if llvm_element_ty == cx.type_i1() { + let int_width = element_count.next_power_of_two().max(8); + rust_ty == cx.type_ix(int_width) + } else { + false + } + } + TypeKind::BFloat => rust_ty == cx.type_i16(), + _ => false, + } +} + +fn autocast<'ll>( + bx: &mut Builder<'_, 'll, '_>, + val: &'ll Value, + src_ty: &'ll Type, + dest_ty: &'ll Type, +) -> &'ll Value { + if src_ty == dest_ty { + return val; + } + match (bx.type_kind(src_ty), bx.type_kind(dest_ty)) { + // re-pack structs + (TypeKind::Struct, TypeKind::Struct) => { + let mut ret = bx.const_poison(dest_ty); + for (idx, (src_element_ty, dest_element_ty)) in + iter::zip(bx.struct_element_types(src_ty), bx.struct_element_types(dest_ty)) + .enumerate() + { + let elt = bx.extract_value(val, idx as u64); + let casted_elt = autocast(bx, elt, src_element_ty, dest_element_ty); + ret = bx.insert_value(ret, casted_elt, idx as u64); + } + ret + } + // cast from the i1xN vector type to the primitive type + (TypeKind::Vector, TypeKind::Integer) if bx.element_type(src_ty) == bx.type_i1() => { + let vector_length = bx.vector_length(src_ty) as u64; + let int_width = vector_length.next_power_of_two().max(8); + + let val = if vector_length == int_width { + val + } else { + // zero-extends vector + let shuffle_indices = match vector_length { + 0 => unreachable!("zero length vectors are not allowed"), + 1 => vec![0, 1, 1, 1, 1, 1, 1, 1], + 2 => vec![0, 1, 2, 2, 2, 2, 2, 2], + 3 => vec![0, 1, 2, 3, 3, 3, 3, 3], + 4.. => (0..int_width as i32).collect(), + }; + let shuffle_mask = + shuffle_indices.into_iter().map(|i| bx.const_i32(i)).collect::>(); + bx.shuffle_vector(val, bx.const_null(src_ty), bx.const_vector(&shuffle_mask)) + }; + bx.bitcast(val, dest_ty) + } + // cast from the primitive type to the i1xN vector type + (TypeKind::Integer, TypeKind::Vector) if bx.element_type(dest_ty) == bx.type_i1() => { + let vector_length = bx.vector_length(dest_ty) as u64; + let int_width = vector_length.next_power_of_two().max(8); + + let intermediate_ty = bx.type_vector(bx.type_i1(), int_width); + let intermediate = bx.bitcast(val, intermediate_ty); + + if vector_length == int_width { + intermediate + } else { + let shuffle_mask: Vec<_> = + (0..vector_length).map(|i| bx.const_i32(i as i32)).collect(); + bx.shuffle_vector( + intermediate, + bx.const_poison(intermediate_ty), + bx.const_vector(&shuffle_mask), + ) + } + } + _ => bx.bitcast(val, dest_ty), // for `bf16(xN)` <-> `u16(xN)` + } +} + +fn intrinsic_fn<'ll, 'tcx>( + bx: &Builder<'_, 'll, 'tcx>, + name: &str, + rust_return_ty: &'ll Type, + rust_argument_tys: Vec<&'ll Type>, + instance: ty::Instance<'tcx>, +) -> &'ll Value { + let tcx = bx.tcx; + + let rust_fn_ty = bx.type_func(&rust_argument_tys, rust_return_ty); + + let intrinsic = llvm::Intrinsic::lookup(name.as_bytes()); + + if let Some(intrinsic) = intrinsic + && intrinsic.is_target_specific() + { + let (llvm_arch, _) = name[5..].split_once('.').unwrap(); + let rust_arch = &tcx.sess.target.arch; + + if let Some(correct_llvm_arch) = llvm_arch_for(rust_arch) + && llvm_arch != correct_llvm_arch + { + tcx.dcx().emit_fatal(IntrinsicWrongArch { + name, + target_arch: rust_arch.desc(), + span: tcx.def_span(instance.def_id()), + }); + } + } + + if let Some(intrinsic) = intrinsic + && !intrinsic.is_overloaded() + { + // FIXME: also do this for overloaded intrinsics + let llfn = intrinsic.get_declaration(bx.llmod, &[]); + let llvm_fn_ty = bx.get_type_of_global(llfn); + + let llvm_return_ty = bx.get_return_type(llvm_fn_ty); + let llvm_argument_tys = bx.func_params_types(llvm_fn_ty); + let llvm_is_variadic = bx.func_is_variadic(llvm_fn_ty); + + let is_correct_signature = !llvm_is_variadic + && rust_argument_tys.len() == llvm_argument_tys.len() + && iter::once((rust_return_ty, llvm_return_ty)) + .chain(iter::zip(rust_argument_tys, llvm_argument_tys)) + .all(|(rust_ty, llvm_ty)| can_autocast(bx, rust_ty, llvm_ty)); + + if !is_correct_signature { + tcx.dcx().emit_fatal(IntrinsicSignatureMismatch { + name, + llvm_fn_ty: &format!("{llvm_fn_ty:?}"), + rust_fn_ty: &format!("{rust_fn_ty:?}"), + span: tcx.def_span(instance.def_id()), + }); + } + + return llfn; + } + + // Function addresses in Rust are never significant, allowing functions to be merged. + let llfn = declare_raw_fn( + bx, + name, + llvm::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Default, + rust_fn_ty, + ); + + if intrinsic.is_none() { + let mut new_llfn = None; + let can_upgrade = unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn) }; + + if !can_upgrade { + // This is either plain wrong, or this can be caused by incompatible LLVM versions + tcx.dcx().emit_fatal(UnknownIntrinsic { name, span: tcx.def_span(instance.def_id()) }); + } else if let Some(def_id) = instance.def_id().as_local() { + // we can emit diagnostics only for local crates + let hir_id = tcx.local_def_id_to_hir_id(def_id); + + // not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences + let msg = if let Some(new_llfn) = new_llfn { + format!( + "using deprecated intrinsic `{name}`, `{}` can be used instead", + str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap() + ) + } else { + format!("using deprecated intrinsic `{name}`") + }; + + tcx.emit_node_lint( + DEPRECATED_LLVM_INTRINSIC, + hir_id, + rustc_errors::DiagDecorator(|d| { + d.primary_message(msg).span(tcx.hir_span(hir_id)); + }), + ); + } + } + + llfn +} + fn catch_unwind_intrinsic<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 67fbc0f53adc9..195e050a9b651 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -73,7 +73,6 @@ unsafe extern "C" { pub(crate) fn LLVMDumpModule(M: &Module); pub(crate) fn LLVMDumpValue(V: &Value); pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint; - pub(crate) fn LLVMGetReturnType(T: &Type) -> &Type; pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value); pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>; } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index bc24f1692fcf2..525d1dbe9d0d3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -921,6 +921,9 @@ unsafe extern "C" { pub(crate) fn LLVMDoubleTypeInContext(C: &Context) -> &Type; pub(crate) fn LLVMFP128TypeInContext(C: &Context) -> &Type; + // Operations on non-IEEE real types + pub(crate) fn LLVMBFloatTypeInContext(C: &Context) -> &Type; + // Operations on function types pub(crate) fn LLVMFunctionType<'a>( ReturnType: &'a Type, @@ -930,6 +933,8 @@ unsafe extern "C" { ) -> &'a Type; pub(crate) fn LLVMCountParamTypes(FunctionTy: &Type) -> c_uint; pub(crate) fn LLVMGetParamTypes<'a>(FunctionTy: &'a Type, Dest: *mut &'a Type); + pub(crate) fn LLVMGetReturnType(FunctionTy: &Type) -> &Type; + pub(crate) fn LLVMIsFunctionVarArg(FunctionTy: &Type) -> Bool; // Operations on struct types pub(crate) fn LLVMStructTypeInContext<'a>( @@ -1084,12 +1089,18 @@ unsafe extern "C" { // Operations about llvm intrinsics pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint; + pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero) -> Bool; pub(crate) fn LLVMGetIntrinsicDeclaration<'a>( Mod: &'a Module, ID: NonZero, ParamTypes: *const &'a Type, ParamCount: size_t, ) -> &'a Value; + pub(crate) fn LLVMRustUpgradeIntrinsicFunction<'a>( + Fn: &'a Value, + NewFn: &mut Option<&'a Value>, + ) -> bool; + pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero) -> bool; // Operations on parameters pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; @@ -1605,6 +1616,9 @@ unsafe extern "C" { Packed: Bool, ); + pub(crate) fn LLVMCountStructElementTypes(StructTy: &Type) -> c_uint; + pub(crate) fn LLVMGetStructElementTypes<'a>(StructTy: &'a Type, Dest: *mut &'a Type); + pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 2871326b28b5a..2ec19b1795b5a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -323,6 +323,14 @@ impl Intrinsic { NonZero::new(id).map(|id| Self { id }) } + pub(crate) fn is_overloaded(self) -> bool { + unsafe { LLVMIntrinsicIsOverloaded(self.id).is_true() } + } + + pub(crate) fn is_target_specific(self) -> bool { + unsafe { LLVMRustIsTargetIntrinsic(self.id) } + } + pub(crate) fn get_declaration<'ll>( self, llmod: &'ll Module, diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 0783282bc6e56..2c0a6ff01018c 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -135,7 +135,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { let ty = self.get_type_of_global(aliasee); for (alias, linkage, visibility) in aliases { - let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias)); + let instance = Instance::mono(self.tcx, *alias); + let symbol_name = self.tcx.symbol_name(instance); tracing::debug!("STATIC ALIAS: {alias:?} {linkage:?} {visibility:?}"); let lldecl = llvm::add_alias( @@ -145,6 +146,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { aliasee, &CString::new(symbol_name.name).unwrap(), ); + // Add the alias name to the set of cached items, so there is no duplicate + // instance added to it during the normal `external static` codegen + let prev_entry = self.instances.borrow_mut().insert(instance, lldecl); + + // If there already was a previous entry, then `add_static_aliases` was called multiple times for the same `alias` + // which would result in incorrect codegen + assert!(prev_entry.is_none(), "An instance was already present for {instance:?}"); llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility)); llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage)); diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 2026b06d104df..796f3d9ef60ba 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -77,6 +77,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { unsafe { llvm::LLVMAddFunction(self.llmod(), name.as_ptr(), ty) } } + pub(crate) fn get_return_type(&self, ty: &'ll Type) -> &'ll Type { + unsafe { llvm::LLVMGetReturnType(ty) } + } + pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { unsafe { let n_args = llvm::LLVMCountParamTypes(ty) as usize; @@ -86,6 +90,20 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { args } } + + pub(crate) fn func_is_variadic(&self, ty: &'ll Type) -> bool { + unsafe { llvm::LLVMIsFunctionVarArg(ty).is_true() } + } + + pub(crate) fn struct_element_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { + unsafe { + let n_args = llvm::LLVMCountStructElementTypes(ty) as usize; + let mut args = Vec::with_capacity(n_args); + llvm::LLVMGetStructElementTypes(ty, args.as_mut_ptr()); + args.set_len(n_args); + args + } + } } impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { pub(crate) fn type_bool(&self) -> &'ll Type { @@ -165,6 +183,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { ) } } + + pub(crate) fn type_bf16(&self) -> &'ll Type { + unsafe { llvm::LLVMBFloatTypeInContext(self.llcx()) } + } } impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2cb96c4ec0f59..f9e4a6a352bac 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -302,6 +302,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let to_backend_ty = bx.cx().immediate_backend_type(cast); OperandValue::Immediate(bx.bitcast(imm, to_backend_ty)) } + ( + OperandValue::Immediate(imm), + abi::BackendRepr::SimdScalableVector { element: from_scalar, .. }, + abi::BackendRepr::SimdScalableVector { element: to_scalar, .. }, + ) if vector_can_bitcast(from_scalar) && vector_can_bitcast(to_scalar) => { + let to_backend_ty = bx.cx().immediate_backend_type(cast); + OperandValue::Immediate(bx.bitcast(imm, to_backend_ty)) + } ( OperandValue::Pair(imm_a, imm_b), abi::BackendRepr::ScalarPair(in_a, in_b), diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 05e6b78132aeb..01886a97f55a2 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -715,6 +715,7 @@ impl<'a> ExtCtxt<'a> { mutability, expr: Some(expr), define_opaque: None, + eii_impls: Default::default(), } .into(), ), diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 29213058d1d5e..956e68773b796 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -15,7 +15,7 @@ use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -26,7 +26,10 @@ use super::potentially_plural_count; use crate::check::compare_impl_item::{ CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions, }; -use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; +use crate::errors::{ + EiiDefkindMismatch, EiiDefkindMismatchStaticMutability, EiiDefkindMismatchStaticSafety, + EiiWithGenerics, LifetimesOrBoundsMismatchOnEii, +}; /// Checks whether the signature of some `external_impl`, matches /// the signature of `declaration`, which it is supposed to be compatible @@ -38,14 +41,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { - // Error recovery can resolve the EII target to another value item with the same name, - // such as a tuple-struct constructor. Skip the comparison in that case and rely on the - // earlier name-resolution error instead of ICEing while building EII diagnostics. - // See . - if !is_foreign_function(tcx, foreign_item) { - return Ok(()); - } - + check_eii_target(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?; check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?; let external_impl_span = tcx.def_span(external_impl); @@ -152,6 +148,118 @@ pub(crate) fn compare_eii_function_types<'tcx>( Ok(()) } +pub(crate) fn compare_eii_statics<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + external_impl_ty: Ty<'tcx>, + foreign_item: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + check_eii_target(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?; + + let external_impl_span = tcx.def_span(external_impl); + let cause = ObligationCause::new( + external_impl_span, + external_impl, + ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item }, + ); + + let param_env = ParamEnv::empty(); + + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); + + let declaration_ty = tcx.type_of(foreign_item).instantiate_identity(); + debug!(?declaration_ty); + + // FIXME: Copied over from compare impl items, same issue: + // We'd want to keep more accurate spans than "the method signature" when + // processing the comparison between the trait and impl fn, but we sadly lose them + // and point at the whole signature when a trait bound or specific input or output + // type would be more appropriate. In other places we have a `Vec` + // corresponding to their `Vec`, but we don't have that here. + // Fixing this would improve the output of test `issue-83765.rs`. + let result = ocx.sup(&cause, param_env, declaration_ty, external_impl_ty); + + if let Err(terr) = result { + debug!(?external_impl_ty, ?declaration_ty, ?terr, "sub_types failed"); + + let mut diag = struct_span_code_err!( + tcx.dcx(), + cause.span, + E0806, + "static `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`", + tcx.item_name(external_impl) + ); + diag.span_note(eii_attr_span, "expected this because of this attribute"); + + return Err(diag.emit()); + } + + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.evaluate_obligations_error_on_ambiguity(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(reported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let errors = infcx.resolve_regions(external_impl, param_env, []); + if !errors.is_empty() { + return Err(infcx + .tainted_by_errors() + .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors))); + } + + Ok(()) +} + +fn check_eii_target( + tcx: TyCtxt<'_>, + external_impl: LocalDefId, + foreign_item: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + // Error recovery can resolve the EII target to another value item with the same name, + // such as a tuple-struct constructor. Skip the comparison in that case and rely on the + // earlier name-resolution error instead of ICEing while building EII diagnostics. + // See . + if !tcx.is_foreign_item(foreign_item) { + return Err(tcx.dcx().delayed_bug("EII is a foreign item")); + } + let expected_kind = tcx.def_kind(foreign_item); + let actual_kind = tcx.def_kind(external_impl); + + match expected_kind { + // Correct target + _ if expected_kind == actual_kind => Ok(()), + DefKind::Static { mutability: m1, safety: s1, .. } + if let DefKind::Static { mutability: m2, safety: s2, .. } = actual_kind => + { + Err(if s1 != s2 { + tcx.dcx().emit_err(EiiDefkindMismatchStaticSafety { span: eii_attr_span, eii_name }) + } else if m1 != m2 { + tcx.dcx() + .emit_err(EiiDefkindMismatchStaticMutability { span: eii_attr_span, eii_name }) + } else { + unreachable!() + }) + } + // Not checked by attr target checking + DefKind::Fn | DefKind::Static { .. } => Err(tcx.dcx().emit_err(EiiDefkindMismatch { + span: eii_attr_span, + eii_name, + expected_kind: expected_kind.descr(foreign_item), + })), + // Checked by attr target checking + _ => Err(tcx.dcx().delayed_bug("Attribute should not be allowed by target checking")), + } +} + /// Checks a bunch of different properties of the impl/trait methods for /// compatibility, such as asyncness, number of argument, self receiver kind, /// and number of early- and late-bound generics. @@ -451,7 +559,3 @@ fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&' let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); tcx.hir_fn_sig_by_hir_id(hir_id) } - -fn is_foreign_function(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - tcx.is_foreign_item(def_id) && matches!(tcx.def_kind(def_id), DefKind::Fn) -} diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 424a75bd4dcb3..d5f17a5cbb75b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -41,7 +41,7 @@ use rustc_trait_selection::traits::{ }; use tracing::{debug, instrument}; -use super::compare_eii::compare_eii_function_types; +use super::compare_eii::{compare_eii_function_types, compare_eii_statics}; use crate::autoderef::Autoderef; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; use crate::errors; @@ -1208,7 +1208,7 @@ fn check_item_fn( decl: &hir::FnDecl<'_>, ) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, def_id, |wfcx| { - check_eiis(tcx, def_id); + check_eiis_fn(tcx, def_id); let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, sig, decl, def_id); @@ -1216,7 +1216,7 @@ fn check_item_fn( }) } -fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { +fn check_eiis_fn(tcx: TyCtxt<'_>, def_id: LocalDefId) { // does the function have an EiiImpl attribute? that contains the defid of a *macro* // that was used to mark the implementation. This is a two step process. for EiiImpl { resolution, span, .. } in @@ -1243,6 +1243,33 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } +fn check_eiis_static<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, ty: Ty<'tcx>) { + // does the function have an EiiImpl attribute? that contains the defid of a *macro* + // that was used to mark the implementation. This is a two step process. + for EiiImpl { resolution, span, .. } in + find_attr!(tcx, def_id, EiiImpls(impls) => impls).into_iter().flatten() + { + let (foreign_item, name) = match resolution { + EiiImplResolution::Macro(def_id) => { + // we expect this macro to have the `EiiMacroFor` attribute, that points to a function + // signature that we'd like to compare the function we're currently checking with + if let Some(foreign_item) = + find_attr!(tcx, *def_id, EiiDeclaration(EiiDecl {foreign_item: t, ..}) => *t) + { + (foreign_item, tcx.item_name(*def_id)) + } else { + tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); + continue; + } + } + EiiImplResolution::Known(decl) => (decl.foreign_item, decl.name.name), + EiiImplResolution::Error(_eg) => continue, + }; + + let _ = compare_eii_statics(tcx, def_id, ty, foreign_item, name, *span); + } +} + #[instrument(level = "debug", skip(tcx))] pub(crate) fn check_static_item<'tcx>( tcx: TyCtxt<'tcx>, @@ -1251,6 +1278,10 @@ pub(crate) fn check_static_item<'tcx>( should_check_for_sync: bool, ) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, item_id, |wfcx| { + if should_check_for_sync { + check_eiis_static(tcx, item_id, ty); + } + let span = tcx.ty_span(item_id); let loc = Some(WellFormedLoc::Ty(item_id)); let item_ty = wfcx.deeply_normalize(span, loc, ty); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1abafd4547ce6..f353ace0b3886 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1933,3 +1933,28 @@ pub(crate) struct ImplUnpinForPinProjectedType { pub adt_span: Span, pub adt_name: Symbol, } + +#[derive(Diagnostic)] +#[diag("`#[{$eii_name}]` must be used on a {$expected_kind}")] +pub(crate) struct EiiDefkindMismatch { + #[primary_span] + pub span: Span, + pub eii_name: Symbol, + pub expected_kind: &'static str, +} + +#[derive(Diagnostic)] +#[diag("mutability does not match with the definition of`#[{$eii_name}]`")] +pub(crate) struct EiiDefkindMismatchStaticMutability { + #[primary_span] + pub span: Span, + pub eii_name: Symbol, +} + +#[derive(Diagnostic)] +#[diag("safety does not match with the definition of`#[{$eii_name}]`")] +pub(crate) struct EiiDefkindMismatchStaticSafety { + #[primary_span] + pub span: Span, + pub eii_name: Symbol, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 55e6d233f4755..e21cadcf3ffe6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3557,6 +3557,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Register the impl's predicates. One of these predicates // must be unsatisfied, or else we wouldn't have gotten here // in the first place. + let unnormalized_predicates = + self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args); ocx.register_obligations(traits::predicates_for_generics( |idx, span| { cause.clone().derived_cause( @@ -3574,8 +3576,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ) }, + |pred| ocx.normalize(&cause, self.param_env, pred), self.param_env, - self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args), + unnormalized_predicates, )); // Normalize the output type, which we can use later on as the diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d3dcb65e71ee2..f57a22f21235e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -423,20 +423,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Instantiates and normalizes the bounds for a given item - pub(crate) fn instantiate_bounds( - &self, - span: Span, - def_id: DefId, - args: GenericArgsRef<'tcx>, - ) -> ty::InstantiatedPredicates<'tcx> { - let bounds = self.tcx.predicates_of(def_id); - let result = bounds.instantiate(self.tcx, args); - let result = self.normalize(span, result); - debug!("instantiate_bounds(bounds={:?}, args={:?}) = {:?}", bounds, args, result); - result - } - pub(crate) fn normalize(&self, span: Span, value: T) -> T where T: TypeFoldable>, @@ -1426,10 +1412,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let param_env = self.param_env; - let bounds = self.instantiate_bounds(span, def_id, args); + let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args); for obligation in traits::predicates_for_generics( |idx, predicate_span| self.cause(span, code(idx, predicate_span)), + |pred| self.normalize(span, pred), param_env, bounds, ) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 857713e3295c9..419fc8e82be6b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -339,9 +339,9 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { // Check whether the impl imposes obligations we have to worry about. let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_bounds); let impl_obligations = traits::predicates_for_generics( |_, _| ObligationCause::dummy(), + |pred| ocx.normalize(&ObligationCause::dummy(), self.param_env, pred), self.param_env, impl_bounds, ); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 6f8335f0cc82e..3423f6b42bb26 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -144,8 +144,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ); self.unify_receivers(self_ty, method_sig_rcvr, pick); - let (method_sig, method_predicates) = - self.normalize(self.span, (method_sig, method_predicates)); + let method_sig = self.normalize(self.span, method_sig); // Make sure nobody calls `drop()` explicitly. self.check_for_illegal_method_calls(pick); @@ -626,6 +625,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ); self.cause(self.span, code) }, + |pred| self.normalize(self.call_expr.span, pred), self.param_env, method_predicates, ) { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 083e29bff04f7..eef7f9ba495ac 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -442,17 +442,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // any late-bound regions appearing in its bounds. let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args); - let InferOk { value: bounds, obligations: o } = - self.at(&obligation.cause, self.param_env).normalize(bounds); - obligations.extend(o); - assert!(!bounds.has_escaping_bound_vars()); - let predicates_cause = obligation.cause.clone(); + let mut normalization_obligations = PredicateObligations::new(); obligations.extend(traits::predicates_for_generics( move |_, _| predicates_cause.clone(), + |pred| { + let InferOk { value: pred, obligations: o } = + self.at(&obligation.cause, self.param_env).normalize(pred); + normalization_obligations.extend(o); + assert!(!pred.has_escaping_bound_vars()); + pred + }, self.param_env, bounds, )); + obligations.extend(normalization_obligations); // Also add an obligation for the method type being well-formed. debug!( diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c7442373353eb..6cfa6e8d75175 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1989,7 +1989,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let impl_def_id = probe.item.container_id(self.tcx); let impl_bounds = self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args); - let impl_bounds = ocx.normalize(cause, self.param_env, impl_bounds); // Convert the bounds into obligations. ocx.register_obligations(traits::predicates_for_generics( |idx, span| { @@ -2001,6 +2000,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); self.cause(self.span, code) }, + |pred| ocx.normalize(cause, self.param_env, pred), self.param_env, impl_bounds, )); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 4aff294aeac61..8af8f40d69f56 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -37,6 +37,7 @@ declare_lint_pass! { DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, DEPRECATED, DEPRECATED_IN_FUTURE, + DEPRECATED_LLVM_INTRINSIC, DEPRECATED_SAFE_2024, DEPRECATED_WHERE_CLAUSE_LOCATION, DUPLICATE_FEATURES, @@ -5597,3 +5598,48 @@ declare_lint! { report_in_deps: false, }; } + +declare_lint! { + /// The `deprecated_llvm_intrinsic` lint detects usage of deprecated LLVM intrinsics. + /// + /// ### Example + /// + /// ```rust,ignore (requires x86) + /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + /// #![feature(link_llvm_intrinsics, abi_unadjusted)] + /// #![deny(deprecated_llvm_intrinsic)] + /// + /// unsafe extern "unadjusted" { + /// #[link_name = "llvm.x86.addcarryx.u32"] + /// fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8; + /// } + /// + /// #[inline(never)] + /// #[target_feature(enable = "adx")] + /// pub fn bar(a: u8, b: u32, c: u32, d: &mut u32) -> u8 { + /// unsafe { foo(a, b, c, d) } + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: Using deprecated intrinsic `llvm.x86.addcarryx.u32` + /// --> example.rs:7:5 + /// | + /// 7 | fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8; + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// ``` + /// + /// ### Explanation + /// + /// LLVM periodically updates its list of intrinsics. Deprecated intrinsics are unlikely + /// to be removed, but they may optimize less well than their new versions, so it's + /// best to use the new version. Also, some deprecated intrinsics might have buggy + /// behavior + pub DEPRECATED_LLVM_INTRINSIC, + Allow, + "detects uses of deprecated LLVM intrinsics", + @feature_gate = link_llvm_intrinsics; +} diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f7fccf6296bd1..c310e580af559 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -9,6 +9,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticHandler.h" @@ -1815,6 +1816,19 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) { GV.setSanitizerMetadata(MD); } +extern "C" bool LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn, + LLVMValueRef *NewFn) { + Function *F = unwrap(Fn); + Function *NewF = nullptr; + bool CanUpgrade = UpgradeIntrinsicFunction(F, NewF, false); + *NewFn = wrap(NewF); + return CanUpgrade; +} + +extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) { + return Intrinsic::isTargetIntrinsic(ID); +} + // Statically assert that the fixed metadata kind IDs declared in // `metadata_kind.rs` match the ones actually used by LLVM. #define FIXED_MD_KIND(VARIANT, VALUE) \ diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 1017ccffb0b2a..dd36cbf1b8f6f 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -60,7 +60,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{ErrorGuaranteed, catch_fatal_errors}; use rustc_hir as hir; use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem}; use rustc_hir::def::{DefKind, DocLinkResMap}; @@ -1202,7 +1202,7 @@ rustc_queries! { /// Return the live symbols in the crate for dead code check. /// /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone). - query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx Result<( + query live_symbols_and_ignored_derived_traits(_: ()) -> Result<&'tcx ( LocalDefIdSet, LocalDefIdMap>, ), ErrorGuaranteed> { @@ -1292,7 +1292,7 @@ rustc_queries! { /// Return the set of (transitive) callees that may result in a recursive call to `key`, /// if we were able to walk all callees. - query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx Option> { + query mir_callgraph_cyclic(key: LocalDefId) -> Option<&'tcx UnordSet> { arena_cache desc { "computing (transitive) callees of `{}` that may recurse", diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs index 7c7ad12622604..4ab2fbe914965 100644 --- a/compiler/rustc_middle/src/query/arena_cached.rs +++ b/compiler/rustc_middle/src/query/arena_cached.rs @@ -1,6 +1,7 @@ use std::mem; use rustc_arena::TypedArena; +use rustc_span::ErrorGuaranteed; use crate::ty::TyCtxt; @@ -51,6 +52,21 @@ impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> { } } +impl<'tcx, T> ArenaCached<'tcx> for Result<&'tcx T, ErrorGuaranteed> { + type Provided = Result; + /// The provide value is `Result`, but we only store `T` in the arena. + type Allocated = T; + + fn alloc_in_arena( + tcx: TyCtxt<'tcx>, + typed_arena: &'tcx TypedArena, + value: Result, + ) -> Self { + // Don't store Err(ErrorGuaranteed) in the arena, and wrap the allocated reference in Ok. + try { do_alloc(tcx, typed_arena, value?) } + } +} + /// Allocates a value in either its dedicated arena, or in the common dropless /// arena, depending on whether it needs to be dropped. fn do_alloc<'tcx, T>(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena, value: T) -> &'tcx T { diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 87fea2fc6aa94..fe3054dc18e65 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -166,6 +166,8 @@ pub struct QuerySystem<'tcx> { pub extern_providers: ExternProviders, pub jobs: AtomicU64, + + pub cycle_handler_nesting: Lock, } #[derive(Copy, Clone)] @@ -446,6 +448,11 @@ macro_rules! define_callbacks { } } + /// Calls `self.description` or returns a fallback if there was a fatal error + pub fn catch_description(&self, tcx: TyCtxt<'tcx>) -> String { + catch_fatal_errors(|| self.description(tcx)).unwrap_or_else(|_| format!("", self.query_name())) + } + /// Returns the default span for this query if `span` is a dummy span. pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span { if !span.is_dummy() { @@ -463,6 +470,11 @@ macro_rules! define_callbacks { )* } } + + /// Calls `self.default_span` or returns `DUMMY_SP` if there was a fatal error + pub fn catch_default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span { + catch_fatal_errors(|| self.default_span(tcx, span)).unwrap_or(DUMMY_SP) + } } /// Holds a `QueryVTable` for each query. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bc971d7a43705..a78e5096b2e5e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -689,7 +689,7 @@ impl<'tcx> TermKind<'tcx> { /// `[[], [U:Bar]]`. Now if there were some particular reference /// like `Foo`, then the `InstantiatedPredicates` would be `[[], /// [usize:Bar]]`. -#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug)] pub struct InstantiatedPredicates<'tcx> { pub predicates: Vec>, pub spans: Vec, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ab3683f598208..df85aa7d041a5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1235,6 +1235,7 @@ impl<'a> Parser<'a> { mutability: _, expr, define_opaque, + eii_impls: _, }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { @@ -1503,6 +1504,7 @@ impl<'a> Parser<'a> { }, safety: Safety::Default, define_opaque: None, + eii_impls: ThinVec::default(), })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1636,7 +1638,15 @@ impl<'a> Parser<'a> { self.expect_semi()?; - let item = StaticItem { ident, ty, safety, mutability, expr, define_opaque: None }; + let item = StaticItem { + ident, + ty, + safety, + mutability, + expr, + define_opaque: None, + eii_impls: ThinVec::default(), + }; Ok(ItemKind::Static(Box::new(item))) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 54d34ef26a021..45478df40e8bf 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -551,9 +551,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) { for EiiImpl { span, inner_span, resolution, impl_marked_unsafe, is_default: _ } in impls { match target { - Target::Fn => {} + Target::Fn | Target::Static => {} _ => { - self.dcx().emit_err(errors::EiiImplNotFunction { span: *span }); + self.dcx().emit_err(errors::EiiImplTarget { span: *span }); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5de43f24b2dc6..9d4f7a3cbbea2 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1175,8 +1175,8 @@ pub(crate) struct ReprAlignShouldBeAlignStatic { } #[derive(Diagnostic)] -#[diag("`eii_macro_for` is only valid on functions")] -pub(crate) struct EiiImplNotFunction { +#[diag("`eii_macro_for` is only valid on functions and statics")] +pub(crate) struct EiiImplTarget { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_query_impl/src/error.rs b/compiler/rustc_query_impl/src/error.rs index 44d53f87aae29..54c2d96078c67 100644 --- a/compiler/rustc_query_impl/src/error.rs +++ b/compiler/rustc_query_impl/src/error.rs @@ -79,3 +79,28 @@ pub(crate) struct Cycle { )] pub note_span: (), } + +#[derive(Subdiagnostic)] +#[note("...when {$stack_bottom}")] +pub(crate) struct NestedCycleBottom { + pub stack_bottom: String, +} + +#[derive(Diagnostic)] +#[diag("internal compiler error: query cycle when printing cycle detected")] +pub(crate) struct NestedCycle { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub stack_bottom: NestedCycleBottom, + #[subdiagnostic] + pub cycle_stack: Vec, + #[subdiagnostic] + pub stack_count: StackCount, + #[subdiagnostic] + pub cycle_usage: Option, + #[note( + "see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information" + )] + pub note_span: (), +} diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 45be65b02964e..a07f7055554c6 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -4,7 +4,7 @@ use std::mem::ManuallyDrop; use rustc_data_structures::hash_table::{Entry, HashTable}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::{DynSend, DynSync}; -use rustc_data_structures::{outline, sharded, sync}; +use rustc_data_structures::{defer, outline, sharded, sync}; use rustc_errors::FatalError; use rustc_middle::dep_graph::{DepGraphData, DepNodeKey, SerializedDepNodeIndex}; use rustc_middle::query::{ @@ -17,6 +17,7 @@ use rustc_span::{DUMMY_SP, Span}; use tracing::warn; use crate::dep_graph::{DepNode, DepNodeIndex}; +use crate::handle_cycle_error; use crate::job::{QueryJobInfo, QueryJobMap, create_cycle_error, find_cycle_in_stack}; use crate::plumbing::{current_query_job, loadable_from_disk, next_job_id, start_query}; use crate::query_impl::for_each_query_vtable; @@ -114,8 +115,29 @@ fn handle_cycle<'tcx, C: QueryCache>( key: C::Key, cycle: Cycle<'tcx>, ) -> C::Value { - let error = create_cycle_error(tcx, &cycle); - (query.handle_cycle_error_fn)(tcx, key, cycle, error) + let nested; + { + let mut nesting = tcx.query_system.cycle_handler_nesting.lock(); + nested = match *nesting { + 0 => false, + 1 => true, + _ => { + // Don't print further nested errors to avoid cases of infinite recursion + tcx.dcx().delayed_bug("doubly nested cycle error").raise_fatal() + } + }; + *nesting += 1; + } + let _guard = defer(|| *tcx.query_system.cycle_handler_nesting.lock() -= 1); + + let error = create_cycle_error(tcx, &cycle, nested); + + if nested { + // Avoid custom handlers and only use the robust `create_cycle_error` for nested cycle errors + handle_cycle_error::default(error) + } else { + (query.handle_cycle_error_fn)(tcx, key, cycle, error) + } } /// Guard object representing the responsibility to execute a query job and diff --git a/compiler/rustc_query_impl/src/handle_cycle_error.rs b/compiler/rustc_query_impl/src/handle_cycle_error.rs index 07565254969c8..e02e4a92d0a2c 100644 --- a/compiler/rustc_query_impl/src/handle_cycle_error.rs +++ b/compiler/rustc_query_impl/src/handle_cycle_error.rs @@ -210,7 +210,7 @@ pub(crate) fn layout_of<'tcx>( ControlFlow::Continue(()) } }, - || create_cycle_error(tcx, &cycle), + || create_cycle_error(tcx, &cycle, false), ); diag.emit().raise_fatal() diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs index 2486c0abfde80..bf0493b29fd1e 100644 --- a/compiler/rustc_query_impl/src/job.rs +++ b/compiler/rustc_query_impl/src/job.rs @@ -413,15 +413,16 @@ pub fn print_query_stack<'tcx>( pub(crate) fn create_cycle_error<'tcx>( tcx: TyCtxt<'tcx>, Cycle { usage, frames }: &Cycle<'tcx>, + nested: bool, ) -> Diag<'tcx> { assert!(!frames.is_empty()); - let span = frames[0].tagged_key.default_span(tcx, frames[1 % frames.len()].span); + let span = frames[0].tagged_key.catch_default_span(tcx, frames[1 % frames.len()].span); let mut cycle_stack = Vec::new(); use crate::error::StackCount; - let stack_bottom = frames[0].tagged_key.description(tcx); + let stack_bottom = frames[0].tagged_key.catch_description(tcx); let stack_count = if frames.len() == 1 { StackCount::Single { stack_bottom: stack_bottom.clone() } } else { @@ -430,14 +431,14 @@ pub(crate) fn create_cycle_error<'tcx>( for i in 1..frames.len() { let frame = &frames[i]; - let span = frame.tagged_key.default_span(tcx, frames[(i + 1) % frames.len()].span); + let span = frame.tagged_key.catch_default_span(tcx, frames[(i + 1) % frames.len()].span); cycle_stack - .push(crate::error::CycleStack { span, desc: frame.tagged_key.description(tcx) }); + .push(crate::error::CycleStack { span, desc: frame.tagged_key.catch_description(tcx) }); } let cycle_usage = usage.as_ref().map(|usage| crate::error::CycleUsage { - span: usage.tagged_key.default_span(tcx, usage.span), - usage: usage.tagged_key.description(tcx), + span: usage.tagged_key.catch_default_span(tcx, usage.span), + usage: usage.tagged_key.catch_description(tcx), }); let is_all_def_kind = |def_kind| { @@ -454,23 +455,36 @@ pub(crate) fn create_cycle_error<'tcx>( }) }; - let alias = if is_all_def_kind(DefKind::TyAlias) { - Some(crate::error::Alias::Ty) - } else if is_all_def_kind(DefKind::TraitAlias) { - Some(crate::error::Alias::Trait) + let alias = if !nested { + if is_all_def_kind(DefKind::TyAlias) { + Some(crate::error::Alias::Ty) + } else if is_all_def_kind(DefKind::TraitAlias) { + Some(crate::error::Alias::Trait) + } else { + None + } } else { None }; - let cycle_diag = crate::error::Cycle { - span, - cycle_stack, - stack_bottom, - alias, - cycle_usage, - stack_count, - note_span: (), - }; - - tcx.sess.dcx().create_err(cycle_diag) + if nested { + tcx.sess.dcx().create_err(crate::error::NestedCycle { + span, + cycle_stack, + stack_bottom: crate::error::NestedCycleBottom { stack_bottom }, + cycle_usage, + stack_count, + note_span: (), + }) + } else { + tcx.sess.dcx().create_err(crate::error::Cycle { + span, + cycle_stack, + stack_bottom, + alias, + cycle_usage, + stack_count, + note_span: (), + }) + } } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d13ecaa2dee5c..d5133aa04dccc 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -8,7 +8,7 @@ #![feature(try_blocks)] // tidy-alphabetical-end -use rustc_data_structures::sync::AtomicU64; +use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_middle::dep_graph; use rustc_middle::queries::{ExternProviders, Providers}; use rustc_middle::query::on_disk_cache::OnDiskCache; @@ -56,6 +56,7 @@ pub fn query_system<'tcx>( local_providers, extern_providers, jobs: AtomicU64::new(1), + cycle_handler_nesting: Lock::new(0), } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 427a75c6bff4d..78dcb0620e5b1 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -274,6 +274,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { expr: _, safety, define_opaque: _, + eii_impls: _, }) => { let safety = match safety { ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9e0f04e82b472..4d855037ca170 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2983,7 +2983,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let binding_key = BindingKey::new(IdentKey::new(ident), MacroNS); - let binding = self.resolution(crate_module, binding_key)?.binding()?; + let binding = self.resolution(crate_module, binding_key)?.best_decl()?; let Res::Def(DefKind::Macro(kinds), _) = binding.res() else { return None; }; diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 55518276a4f0f..cd7790f27b5f5 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -114,7 +114,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { let module = self.r.expect_module(module_id.to_def_id()); for (_, name_resolution) in self.r.resolutions(module).borrow().iter() { - let Some(mut decl) = name_resolution.borrow().binding() else { + let Some(mut decl) = name_resolution.borrow().best_decl() else { continue; }; // Set the given effective visibility level to `Level::Direct` and diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index bcc754fd984da..8c7bf61949a29 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1521,20 +1521,24 @@ pub(crate) struct RedundantImportVisibility { #[diag("unknown diagnostic attribute")] pub(crate) struct UnknownDiagnosticAttribute { #[subdiagnostic] - pub typo: Option, + pub help: Option, } #[derive(Subdiagnostic)] -#[suggestion( - "an attribute with a similar name exists", - style = "verbose", - code = "{typo_name}", - applicability = "machine-applicable" -)] -pub(crate) struct UnknownDiagnosticAttributeTypoSugg { - #[primary_span] - pub span: Span, - pub typo_name: Symbol, +pub(crate) enum UnknownDiagnosticAttributeHelp { + #[suggestion( + "an attribute with a similar name exists", + style = "verbose", + code = "{typo_name}", + applicability = "machine-applicable" + )] + Typo { + #[primary_span] + span: Span, + typo_name: Symbol, + }, + #[help("add `#![feature({$feature})]` to the crate attributes to enable")] + UseFeature { feature: Symbol }, } // FIXME: Make this properly translatable. diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e24e65d55c00f..a94f3ea435e2c 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -289,15 +289,22 @@ impl<'ra> NameResolution<'ra> { NameResolution { single_imports: FxIndexSet::default(), orig_ident_span, .. } } - /// Returns the binding for the name if it is known or None if it not known. - pub(crate) fn binding(&self) -> Option> { - self.best_decl().and_then(|binding| { - if !binding.is_glob_import() || self.single_imports.is_empty() { - Some(binding) - } else { - None - } - }) + /// Returns the best declaration if it is not going to change, and `None` if the best + /// declaration may still change to something else. + /// FIXME: this function considers `single_imports`, but not `unexpanded_invocations`, so + /// the returned declaration may actually change after expanding macros in the same module, + /// because of this fact we have glob overwriting (`select_glob_decl`). Consider using + /// `unexpanded_invocations` here and avoiding glob overwriting entirely, if it doesn't cause + /// code breakage in practice. + /// FIXME: relationship between this function and similar `DeclData::determined` is unclear. + pub(crate) fn determined_decl(&self) -> Option> { + if self.non_glob_decl.is_some() { + self.non_glob_decl + } else if self.glob_decl.is_some() && self.single_imports.is_empty() { + self.glob_decl + } else { + None + } } pub(crate) fn best_decl(&self) -> Option> { @@ -482,41 +489,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { orig_ident_span, warn_ambiguity, |this, resolution| { - if let Some(old_decl) = resolution.best_decl() { - assert_ne!(decl, old_decl); - assert!(!decl.warn_ambiguity.get()); - if res == Res::Err && old_decl.res() != Res::Err { - // Do not override real declarations with `Res::Err`s from error recovery. - return Ok(()); - } - match (old_decl.is_glob_import(), decl.is_glob_import()) { - (true, true) => { - resolution.glob_decl = - Some(this.select_glob_decl(old_decl, decl, warn_ambiguity)); - } - (old_glob @ true, false) | (old_glob @ false, true) => { - let (glob_decl, non_glob_decl) = - if old_glob { (old_decl, decl) } else { (decl, old_decl) }; - resolution.non_glob_decl = Some(non_glob_decl); - if let Some(old_glob_decl) = resolution.glob_decl - && old_glob_decl != glob_decl - { - resolution.glob_decl = - Some(this.select_glob_decl(old_glob_decl, glob_decl, false)); - } else { - resolution.glob_decl = Some(glob_decl); - } - } - (false, false) => { - return Err(old_decl); - } - } + assert!(!decl.warn_ambiguity.get()); + if decl.is_glob_import() { + resolution.glob_decl = Some(match resolution.glob_decl { + Some(old_decl) => this.select_glob_decl( + old_decl, + decl, + warn_ambiguity && resolution.non_glob_decl.is_none(), + ), + None => decl, + }) } else { - if decl.is_glob_import() { - resolution.glob_decl = Some(decl); - } else { - resolution.non_glob_decl = Some(decl); - } + resolution.non_glob_decl = Some(match resolution.non_glob_decl { + Some(old_decl) => return Err(old_decl), + None => decl, + }) } Ok(()) @@ -543,11 +530,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let resolution = &mut *self .resolution_or_default(module, key, orig_ident_span) .borrow_mut_unchecked(); - let old_decl = resolution.binding(); + let old_decl = resolution.determined_decl(); let t = f(self, resolution); - if let Some(binding) = resolution.binding() + if let Some(binding) = resolution.determined_decl() && old_decl != Some(binding) { (binding, t, warn_ambiguity || old_decl.is_some()) @@ -573,13 +560,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; if self.is_accessible_from(binding.vis(), scope) { let import_decl = self.new_import_decl(binding, *import); - let _ = self.try_plant_decl_into_local_module( + self.try_plant_decl_into_local_module( ident, orig_ident_span, key.ns, import_decl, warn_ambiguity, - ); + ) + .expect("planting a glob cannot fail"); } } @@ -598,6 +586,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.per_ns(|this, ns| { let module = import.parent_scope.module; let ident = IdentKey::new(target); + // This can fail, dummies are inserted only in non-occupied slots. let _ = this.try_plant_decl_into_local_module( ident, target.span, @@ -1676,7 +1665,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .iter() .filter_map(|(key, resolution)| { let resolution = resolution.borrow(); - resolution.binding().map(|binding| (*key, binding, resolution.orig_ident_span)) + resolution.determined_decl().map(|decl| (*key, decl, resolution.orig_ident_span)) }) .collect::>(); for (mut key, binding, orig_ident_span) in bindings { @@ -1692,15 +1681,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let import_decl = self.new_import_decl(binding, import); let warn_ambiguity = self .resolution(import.parent_scope.module, key) - .and_then(|r| r.binding()) + .and_then(|r| r.determined_decl()) .is_some_and(|binding| binding.warn_ambiguity_recursive()); - let _ = self.try_plant_decl_into_local_module( + self.try_plant_decl_into_local_module( key.ident, orig_ident_span, key.ns, import_decl, warn_ambiguity, - ); + ) + .expect("planting a glob cannot fail"); } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2c287045be7a9..56e26b1ac6cbe 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -530,9 +530,8 @@ impl PathSource<'_, '_, '_> { }, _ => "value", }, - PathSource::ReturnTypeNotation - | PathSource::Delegation - | PathSource::ExternItemImpl => "function", + PathSource::ReturnTypeNotation | PathSource::Delegation => "function", + PathSource::ExternItemImpl => "function or static", PathSource::PreciseCapturingArg(..) => "type or const parameter", PathSource::Macro => "macro", PathSource::Module => "module", @@ -625,7 +624,13 @@ impl PathSource<'_, '_, '_> { }, PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)), PathSource::ExternItemImpl => { - matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..), _)) + matches!( + res, + Res::Def( + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Static { .. }, + _ + ) + ) } PathSource::PreciseCapturingArg(ValueNS) => { matches!(res, Res::Def(DefKind::ConstParam, _)) @@ -1095,21 +1100,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc debug!("(resolving function) entering function"); if let FnKind::Fn(_, _, f) = fn_kind { - for EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. } in &f.eii_impls - { - // See docs on the `known_eii_macro_resolution` field: - // if we already know the resolution statically, don't bother resolving it. - if let Some(target) = known_eii_macro_resolution { - self.smart_resolve_path( - *node_id, - &None, - &target.foreign_item, - PathSource::ExternItemImpl, - ); - } else { - self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); - } - } + self.resolve_eii(&f.eii_impls); } // Create a value rib for the function. @@ -2905,7 +2896,14 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.module = orig_module; } - ItemKind::Static(box ast::StaticItem { ident, ty, expr, define_opaque, .. }) => { + ItemKind::Static(box ast::StaticItem { + ident, + ty, + expr, + define_opaque, + eii_impls, + .. + }) => { self.with_static_rib(def_kind, |this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); @@ -2917,6 +2915,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }); self.resolve_define_opaques(define_opaque); + self.resolve_eii(&eii_impls); } ItemKind::Const(box ast::ConstItem { @@ -5496,6 +5495,23 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } } + + fn resolve_eii(&mut self, eii_impls: &[EiiImpl]) { + for EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. } in eii_impls { + // See docs on the `known_eii_macro_resolution` field: + // if we already know the resolution statically, don't bother resolving it. + if let Some(target) = known_eii_macro_resolution { + self.smart_resolve_path( + *node_id, + &None, + &target.foreign_item, + PathSource::ExternItemImpl, + ); + } else { + self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); + } + } + } } /// Walks the whole crate in DFS order, visiting each item, counting the declared number of diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d75f2981a7724..7334131a1c01d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1101,9 +1101,11 @@ impl<'ra> DeclData<'ra> { !(certainly_before_other_or_simultaneously || certainly_before_invoc_or_simultaneously) } - // Its purpose is to postpone the determination of a single binding because - // we can't predict whether it will be overwritten by recently expanded macros. - // FIXME: How can we integrate it with the `update_resolution`? + /// Returns whether this declaration may be shadowed or overwritten by something else later. + /// FIXME: this function considers `unexpanded_invocations`, but not `single_imports`, so + /// the declaration may not be as "determined" as we think. + /// FIXME: relationship between this function and similar `NameResolution::determined_decl` + /// is unclear. fn determined(&self) -> bool { match &self.kind { DeclKind::Import { source_decl, import, .. } if import.is_glob() => { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 67a896bdd7557..13bda9c98c0a7 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -712,34 +712,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit(); } - let diagnostic_attributes: &[(Symbol, bool)] = &[ - (sym::on_unimplemented, true), - (sym::do_not_recommend, true), - (sym::on_move, true), - (sym::on_const, self.tcx.features().diagnostic_on_const()), - (sym::on_unknown, self.tcx.features().diagnostic_on_unknown()), + const DIAGNOSTIC_ATTRIBUTES: &[(Symbol, Option)] = &[ + (sym::on_unimplemented, None), + (sym::do_not_recommend, None), + (sym::on_move, Some(sym::diagnostic_on_move)), + (sym::on_const, Some(sym::diagnostic_on_const)), + (sym::on_unknown, Some(sym::diagnostic_on_unknown)), ]; if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) && let [namespace, attribute, ..] = &*path.segments && namespace.ident.name == sym::diagnostic - && !diagnostic_attributes - .iter() - .any(|(attr, stable)| *stable && attribute.ident.name == *attr) + && !DIAGNOSTIC_ATTRIBUTES.iter().any(|(attr, feature)| { + attribute.ident.name == *attr + && feature.is_none_or(|f| self.tcx.features().enabled(f)) + }) { + let name = attribute.ident.name; let span = attribute.span(); - let candidates = diagnostic_attributes - .iter() - .filter_map(|(sym, stable)| stable.then_some(*sym)) - .collect::>(); - let typo = find_best_match_for_name(&candidates, attribute.ident.name, Some(5)) - .map(|typo_name| errors::UnknownDiagnosticAttributeTypoSugg { span, typo_name }); + + let help = 'help: { + if self.tcx.sess.is_nightly_build() { + for (attr, feature) in DIAGNOSTIC_ATTRIBUTES { + if let Some(feature) = *feature + && *attr == name + { + break 'help Some(errors::UnknownDiagnosticAttributeHelp::UseFeature { + feature, + }); + } + } + } + + let candidates = DIAGNOSTIC_ATTRIBUTES + .iter() + .filter_map(|(attr, feature)| { + feature.is_none_or(|f| self.tcx.features().enabled(f)).then_some(*attr) + }) + .collect::>(); + + find_best_match_for_name(&candidates, name, None).map(|typo_name| { + errors::UnknownDiagnosticAttributeHelp::Typo { span, typo_name } + }) + }; self.tcx.sess.psess.buffer_lint( UNKNOWN_DIAGNOSTIC_ATTRIBUTES, span, node_id, - errors::UnknownDiagnosticAttribute { typo }, + errors::UnknownDiagnosticAttribute { help }, ); } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 94ce7631b3c88..89a6132b0dc7f 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -34,8 +34,8 @@ use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast, + self, Clause, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast, }; use rustc_span::Span; use rustc_span::def_id::DefId; @@ -177,9 +177,10 @@ pub enum TraitQueryMode { } /// Creates predicate obligations from the generic bounds. -#[instrument(level = "debug", skip(cause, param_env))] +#[instrument(level = "debug", skip(cause, param_env, normalize_predicate))] pub fn predicates_for_generics<'tcx>( cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, + mut normalize_predicate: impl FnMut(Clause<'tcx>) -> Clause<'tcx>, param_env: ty::ParamEnv<'tcx>, generic_bounds: ty::InstantiatedPredicates<'tcx>, ) -> impl Iterator> { @@ -187,7 +188,7 @@ pub fn predicates_for_generics<'tcx>( cause: cause(idx, span), recursion_depth: 0, param_env, - predicate: clause.as_predicate(), + predicate: normalize_predicate(clause).as_predicate(), }) } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index fa9d617604e50..d6dcb97562d04 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -185,12 +185,13 @@ fn fulfill_implication<'tcx>( // Now check that the source trait ref satisfies all the where clauses of the target impl. // This is not just for correctness; we also need this to constrain any params that may // only be referenced via projection predicates. - let predicates = ocx.normalize( - cause, + let predicates = infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args); + let obligations = predicates_for_generics( + |_, _| cause.clone(), + |pred| ocx.normalize(cause, param_env, pred), param_env, - infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args), + predicates, ); - let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates); ocx.register_obligations(obligations); let errors = ocx.evaluate_obligations_error_on_ambiguity(); @@ -315,12 +316,14 @@ pub(super) fn specializes( // Now check that the source trait ref satisfies all the where clauses of the target impl. // This is not just for correctness; we also need this to constrain any params that may // only be referenced via projection predicates. - let predicates = ocx.normalize( - cause, + let predicates = + infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args); + let obligations = predicates_for_generics( + |_, _| cause.clone(), + |pred| ocx.normalize(cause, param_env, pred), param_env, - infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args), + predicates, ); - let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates); ocx.register_obligations(obligations); let errors = ocx.evaluate_obligations_error_on_ambiguity(); diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index ae559e599f481..9d350166c681b 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -346,7 +346,8 @@ impl T> DerefMut for LazyCell { } #[stable(feature = "lazy_cell", since = "1.80.0")] -impl Default for LazyCell { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for LazyCell { /// Creates a new lazy value using `Default` as the initializing function. #[inline] fn default() -> LazyCell { diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 37562da3cd6b4..1b1489261f62f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -213,14 +213,13 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(int_lowest_highest_one)] - /// #[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".highest_one(), None);")] #[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".highest_one(), Some(0));")] #[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".highest_one(), Some(4));")] #[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".highest_one(), Some(4));")] /// ``` - #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -234,14 +233,13 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(int_lowest_highest_one)] - /// #[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".lowest_one(), None);")] #[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".lowest_one(), Some(0));")] #[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".lowest_one(), Some(4));")] #[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".lowest_one(), Some(0));")] /// ``` - #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index e2c552e78d6b6..9a330fe592230 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -711,8 +711,6 @@ macro_rules! nonzero_integer { /// # Examples /// /// ``` - /// #![feature(int_lowest_highest_one)] - /// /// # use core::num::NonZero; /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -722,7 +720,8 @@ macro_rules! nonzero_integer { /// # Some(()) /// # } /// ``` - #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -735,8 +734,6 @@ macro_rules! nonzero_integer { /// # Examples /// /// ``` - /// #![feature(int_lowest_highest_one)] - /// /// # use core::num::NonZero; /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -746,7 +743,8 @@ macro_rules! nonzero_integer { /// # Some(()) /// # } /// ``` - #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1948,8 +1946,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - /// #![feature(uint_bit_width)] - /// /// # use core::num::NonZero; /// # /// # fn main() { test().unwrap(); } @@ -1960,7 +1956,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Some(()) /// # } /// ``` - #[unstable(feature = "uint_bit_width", issue = "142326")] + #[stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index fd43ca742aefb..b925400e19227 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -232,14 +232,13 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(uint_bit_width)] - /// #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".bit_width(), 0);")] #[doc = concat!("assert_eq!(0b111_", stringify!($SelfT), ".bit_width(), 3);")] #[doc = concat!("assert_eq!(0b1110_", stringify!($SelfT), ".bit_width(), 4);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.bit_width(), ", stringify!($BITS), ");")] /// ``` - #[unstable(feature = "uint_bit_width", issue = "142326")] + #[stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -293,14 +292,13 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(int_lowest_highest_one)] - /// #[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".highest_one(), None);")] #[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".highest_one(), Some(0));")] #[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".highest_one(), Some(4));")] #[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".highest_one(), Some(4));")] /// ``` - #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -317,14 +315,13 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(int_lowest_highest_one)] - /// #[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".lowest_one(), None);")] #[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".lowest_one(), Some(0));")] #[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".lowest_one(), Some(4));")] #[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".lowest_one(), Some(0));")] /// ``` - #[unstable(feature = "int_lowest_highest_one", issue = "145203")] + #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 305861ea7b698..e46204c6246ab 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -293,6 +293,7 @@ impl const DerefMut for &mut T { /// unchanged. #[unstable(feature = "deref_pure_trait", issue = "87121")] #[lang = "deref_pure"] +#[rustc_dyn_incompatible_trait] pub unsafe trait DerefPure: PointeeSized {} #[unstable(feature = "deref_pure_trait", issue = "87121")] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index c709b6c432e52..019a2dfaa4476 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -66,7 +66,6 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(int_from_ascii)] -#![feature(int_lowest_highest_one)] #![feature(int_roundings)] #![feature(ip)] #![feature(is_ascii_octdigit)] @@ -120,7 +119,6 @@ #![feature(try_find)] #![feature(try_trait_v2)] #![feature(type_info)] -#![feature(uint_bit_width)] #![feature(uint_carryless_mul)] #![feature(uint_gather_scatter_bits)] #![feature(unicode_internals)] diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 9bdde0ae4a537..de1b9c391e8f2 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -375,7 +375,8 @@ impl T> DerefMut for LazyLock { } #[stable(feature = "lazy_cell", since = "1.80.0")] -impl Default for LazyLock { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for LazyLock { /// Creates a new lazy value using `Default` as the initializing function. #[inline] fn default() -> LazyLock { diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 2f3ef1741cdfc..81ef39581d74d 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -155,6 +155,7 @@ pub fn available_parallelism() -> io::Result> { target_os = "aix", target_vendor = "apple", target_os = "cygwin", + target_os = "wasi", ) => { #[allow(unused_assignments)] #[allow(unused_mut)] diff --git a/library/std/tests/sync/lazy_lock.rs b/library/std/tests/sync/lazy_lock.rs index 68aeea834b4fa..c549094dd1381 100644 --- a/library/std/tests/sync/lazy_lock.rs +++ b/library/std/tests/sync/lazy_lock.rs @@ -33,6 +33,15 @@ fn lazy_default() { assert_eq!(CALLED.load(SeqCst), 1); } +#[test] +fn const_lazy_default() { + // using Box as it cannot be initialized in const contexts + const X: LazyLock> = <_>::default(); + const Y: LazyCell> = <_>::default(); + assert_eq!(**X, 0); + assert_eq!(**Y, 0); +} + #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_lazy_new() { diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index 32a7efde2a257..92c4c2f511be3 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -1,3 +1,5 @@ +#![feature(const_default)] +#![feature(const_trait_impl)] #![feature(mapped_lock_guards)] #![feature(mpmc_channel)] #![feature(oneshot_channel)] diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index dc8eadd75148b..ef13ce44d3180 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -85,7 +85,6 @@ fn thread_local_hygeiene() { target_env = "sgx", target_os = "solid_asp3", target_os = "teeos", - target_os = "wasi" ), should_panic )] diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 28a7afd6c61a6..222b982073280 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -636,9 +636,9 @@ impl Step for Rustc { let page_src = file_entry.path(); let page_dst = man_dst.join(file_entry.file_name()); let src_text = t!(std::fs::read_to_string(&page_src)); - let new_text = src_text.replace("", &builder.version); + let version = builder.rust_info().version(builder.build, &builder.version); + let new_text = src_text.replace("", &version); t!(std::fs::write(&page_dst, &new_text)); - t!(fs::copy(&page_src, &page_dst)); } // Debugger scripts diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index c222aa2305647..991592ec522d0 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2334,6 +2334,10 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--verbose"); } + if builder.config.cmd.verbose_run_make_subprocess_output() { + cmd.arg("--verbose-run-make-subprocess-output"); + } + if builder.config.rustc_debug_assertions { cmd.arg("--with-rustc-debug-assertions"); } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 2f1e234d6ebc0..e1b8aa9810c3d 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -422,6 +422,10 @@ pub enum Subcommand { #[arg(long)] /// don't capture stdout/stderr of tests no_capture: bool, + #[arg(long, default_value_t = true, action = clap::ArgAction::Set, default_missing_value = "true", num_args = 0..=1, require_equals = true)] + /// whether to show verbose subprocess output for run-make tests; + /// set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture) + verbose_run_make_subprocess_output: bool, #[arg(long)] /// Use a different codegen backend when running tests. test_codegen_backend: Option, @@ -631,6 +635,15 @@ impl Subcommand { } } + pub fn verbose_run_make_subprocess_output(&self) -> bool { + match *self { + Subcommand::Test { verbose_run_make_subprocess_output, .. } => { + verbose_run_make_subprocess_output + } + _ => true, + } + } + pub fn rustfix_coverage(&self) -> bool { match *self { Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage, diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 3ae2373e1da21..331403f959b4c 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -621,4 +621,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "`x.py` stopped accepting partial argument names. Use full names to avoid errors.", }, + ChangeInfo { + change_id: 154587, + severity: ChangeSeverity::Info, + summary: "New `--verbose-run-make-subprocess-output` flag for `x.py test` (defaults to true). Set `--verbose-run-make-subprocess-output=false` to suppress verbose subprocess output for passing run-make tests when using `--no-capture`.", + }, ]; diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 83fcfecc1de7b..e19c7a8d4e44f 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -460,6 +460,15 @@ However, revisions or building auxiliary via directives are not currently suppor `rmake.rs` and `run-make-support` may *not* use any nightly/unstable features, as they must be compilable by a stage 0 rustc that may be a beta or even stable rustc. +By default, run-make tests print each subprocess command and its stdout/stderr. +When running with `--no-capture` on `panic=abort` test suites (such as `cg_clif`), +this can flood the terminal. Omit `--verbose-run-make-subprocess-output` to +suppress this output for passing tests — failing tests always print regardless: + +```bash +./x test tests/run-make --no-capture --verbose-run-make-subprocess-output=false +``` + #### Quickly check if `rmake.rs` tests can be compiled You can quickly check if `rmake.rs` tests can be compiled without having to diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 92af4f04dcba9..689a13452e1bc 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -420,6 +420,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l extra-checks -d 'comma-sepa complete -c x -n "__fish_x_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r +complete -c x -n "__fish_x_using_subcommand test" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}" complete -c x -n "__fish_x_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r complete -c x -n "__fish_x_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -473,6 +474,7 @@ complete -c x -n "__fish_x_using_subcommand t" -l extra-checks -d 'comma-separat complete -c x -n "__fish_x_using_subcommand t" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r complete -c x -n "__fish_x_using_subcommand t" -l pass -d 'force {check,build,run}-pass tests to this mode' -r complete -c x -n "__fish_x_using_subcommand t" -l run -d 'whether to execute run-* tests' -r +complete -c x -n "__fish_x_using_subcommand t" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}" complete -c x -n "__fish_x_using_subcommand t" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r complete -c x -n "__fish_x_using_subcommand t" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand t" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index d4bf45f738365..e99ef27c2abca 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -487,6 +487,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') + [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)') [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') @@ -547,6 +548,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') + [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)') [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 0dbbe1ea43efd..a852df8a7753e 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -420,6 +420,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l extra-checks -d 'comm complete -c x.py -n "__fish_x.py_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r +complete -c x.py -n "__fish_x.py_using_subcommand test" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}" complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -473,6 +474,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand t" -l extra-checks -d 'comma-s complete -c x.py -n "__fish_x.py_using_subcommand t" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r complete -c x.py -n "__fish_x.py_using_subcommand t" -l pass -d 'force {check,build,run}-pass tests to this mode' -r complete -c x.py -n "__fish_x.py_using_subcommand t" -l run -d 'whether to execute run-* tests' -r +complete -c x.py -n "__fish_x.py_using_subcommand t" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}" complete -c x.py -n "__fish_x.py_using_subcommand t" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r complete -c x.py -n "__fish_x.py_using_subcommand t" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand t" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index b4e3b8c580a49..665cb812f2df9 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -487,6 +487,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') + [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)') [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') @@ -547,6 +548,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') + [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)') [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 8a7aee2a091c7..5e6db9bcb5325 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -4638,7 +4638,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4668,6 +4668,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --verbose-run-make-subprocess-output) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; --test-codegen-backend) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4852,7 +4856,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4882,6 +4886,10 @@ _x.py() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --verbose-run-make-subprocess-output) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; --test-codegen-backend) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index e24da218a05d8..1f8701c297baa 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -488,6 +488,7 @@ _arguments "${_arguments_options[@]}" : \ '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \ '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ +'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \ '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ @@ -550,6 +551,7 @@ _arguments "${_arguments_options[@]}" : \ '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \ '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ +'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \ '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index a4b44b73f47af..6314fe1307dcb 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -4638,7 +4638,7 @@ _x() { return 0 ;; x__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4668,6 +4668,10 @@ _x() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --verbose-run-make-subprocess-output) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; --test-codegen-backend) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4852,7 +4856,7 @@ _x() { return 0 ;; x__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4882,6 +4886,10 @@ _x() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --verbose-run-make-subprocess-output) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; --test-codegen-backend) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 7f43781684b4b..12f441012e60f 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -488,6 +488,7 @@ _arguments "${_arguments_options[@]}" : \ '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \ '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ +'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \ '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ @@ -550,6 +551,7 @@ _arguments "${_arguments_options[@]}" : \ '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \ '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ +'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \ '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index cfff7da60a6a4..c96c0649753fd 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -339,6 +339,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { expr: le, safety: ls, define_opaque: _, + eii_impls: _, }), Static(box StaticItem { ident: ri, @@ -347,6 +348,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { expr: re, safety: rs, define_opaque: _, + eii_impls: _, }), ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()), ( @@ -540,6 +542,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { expr: le, safety: ls, define_opaque: _, + eii_impls: _, }), Static(box StaticItem { ident: ri, @@ -548,6 +551,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { expr: re, safety: rs, define_opaque: _, + eii_impls: _, }), ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs, ( diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index c167580d99d9a..f73d7c96f7e85 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -603,6 +603,10 @@ pub(crate) struct Config { /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump. pub(crate) verbose: bool, + /// Whether to enable verbose subprocess output for run-make tests. + /// Set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture). + pub verbose_run_make_subprocess_output: bool, + /// Where to find the remote test client process, if we're using it. /// /// Note: this is *only* used for target platform executables created by `run-make` test diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a23e3bb9a90e4..dcea79b18e6a8 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -134,6 +134,11 @@ fn parse_config(args: Vec) -> Config { ) .optflag("", "optimize-tests", "run tests with optimizations enabled") .optflag("", "verbose", "run tests verbosely, showing all output") + .optflag( + "", + "verbose-run-make-subprocess-output", + "show verbose subprocess output for successful run-make tests", + ) .optflag( "", "bless", @@ -471,6 +476,8 @@ fn parse_config(args: Vec) -> Config { adb_test_dir, adb_device_status, verbose: matches.opt_present("verbose"), + verbose_run_make_subprocess_output: matches + .opt_present("verbose-run-make-subprocess-output"), only_modified: matches.opt_present("only-modified"), remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from), compare_mode, diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index ac8846a263c0d..1044683ae6426 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -231,6 +231,13 @@ impl TestCx<'_> { } // Guard against externally-set env vars. + // Set env var to enable verbose output for successful commands. + // Only set when --verbose-run-make-subprocess-output is passed. + cmd.env_remove("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT"); + if self.config.verbose_run_make_subprocess_output { + cmd.env("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT", "1"); + } + cmd.env_remove("__RUSTC_DEBUG_ASSERTIONS_ENABLED"); if self.config.with_rustc_debug_assertions { // Used for `run_make_support::env::rustc_debug_assertions_enabled`. diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index c71fd714aa660..57ce0c5a6d5f7 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -109,6 +109,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { adb_test_dir: Default::default(), adb_device_status: Default::default(), verbose: Default::default(), + verbose_run_make_subprocess_output: Default::default(), remote_test_client: Default::default(), compare_mode: Default::default(), rustfix_coverage: Default::default(), diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs index f44b3861d11d3..93ec44d58d791 100644 --- a/src/tools/run-make-support/src/util.rs +++ b/src/tools/run-make-support/src/util.rs @@ -4,7 +4,7 @@ use crate::command::{Command, CompletedProcess}; use crate::env::env_var; use crate::path_helpers::cwd; -pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) { +fn print_command_output(cmd: &Command, output: &CompletedProcess) { cmd.inspect(|std_cmd| { eprintln!("{std_cmd:?}"); }); @@ -16,6 +16,15 @@ pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) { } } +pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) { + // Only prints when `--verbose-run-make-subprocess-output` is active (env var set), + // so that passing tests don't flood the terminal when using `--no-capture`. + if std::env::var_os("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT").is_none() { + return; + } + print_command_output(cmd, output); +} + /// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the /// executed command, failure location, output status and stdout/stderr, and abort the process with /// exit code `1`. @@ -29,7 +38,7 @@ pub(crate) fn handle_failed_output( } else { eprintln!("command failed at line {caller_line_number}"); } - verbose_print_command(cmd, &output); + print_command_output(cmd, &output); std::process::exit(1) } diff --git a/tests/codegen-llvm/inject-autocast.rs b/tests/codegen-llvm/inject-autocast.rs new file mode 100644 index 0000000000000..fec9d3f0b1955 --- /dev/null +++ b/tests/codegen-llvm/inject-autocast.rs @@ -0,0 +1,93 @@ +//@ compile-flags: -C opt-level=0 -C target-feature=+kl,+avx512vp2intersect,+avx512vl,+avxneconvert +//@ only-x86_64 + +#![feature(link_llvm_intrinsics, abi_unadjusted, simd_ffi, portable_simd)] +#![crate_type = "lib"] + +use std::simd::{f32x4, i16x8, i64x2}; + +#[repr(C, packed)] +pub struct Bar(u32, i64x2, i64x2, i64x2, i64x2, i64x2, i64x2); +// CHECK: %Bar = type <{ i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> }> + +// CHECK-LABEL: @struct_autocast +#[no_mangle] +pub unsafe fn struct_autocast(key_metadata: u32, key: i64x2) -> Bar { + extern "unadjusted" { + #[link_name = "llvm.x86.encodekey128"] + fn foo(key_metadata: u32, key: i64x2) -> Bar; + } + + // CHECK: [[A:%[0-9]+]] = call { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } @llvm.x86.encodekey128(i32 {{.*}}, <2 x i64> {{.*}}) + // CHECK: [[B:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 0 + // CHECK: [[C:%[0-9]+]] = insertvalue %Bar poison, i32 [[B]], 0 + // CHECK: [[D:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 1 + // CHECK: [[E:%[0-9]+]] = insertvalue %Bar [[C]], <2 x i64> [[D]], 1 + // CHECK: [[F:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 2 + // CHECK: [[G:%[0-9]+]] = insertvalue %Bar [[E]], <2 x i64> [[F]], 2 + // CHECK: [[H:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 3 + // CHECK: [[I:%[0-9]+]] = insertvalue %Bar [[G]], <2 x i64> [[H]], 3 + // CHECK: [[J:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 4 + // CHECK: [[K:%[0-9]+]] = insertvalue %Bar [[I]], <2 x i64> [[J]], 4 + // CHECK: [[L:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 5 + // CHECK: [[M:%[0-9]+]] = insertvalue %Bar [[K]], <2 x i64> [[L]], 5 + // CHECK: [[N:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 6 + // CHECK: insertvalue %Bar [[M]], <2 x i64> [[N]], 6 + foo(key_metadata, key) +} + +// CHECK-LABEL: @struct_with_i1_vector_autocast +#[no_mangle] +pub unsafe fn struct_with_i1_vector_autocast(a: i64x2, b: i64x2) -> (u8, u8) { + extern "unadjusted" { + #[link_name = "llvm.x86.avx512.vp2intersect.q.128"] + fn foo(a: i64x2, b: i64x2) -> (u8, u8); + } + + // CHECK: [[A:%[0-9]+]] = call { <2 x i1>, <2 x i1> } @llvm.x86.avx512.vp2intersect.q.128(<2 x i64> {{.*}}, <2 x i64> {{.*}}) + // CHECK: [[B:%[0-9]+]] = extractvalue { <2 x i1>, <2 x i1> } [[A]], 0 + // CHECK: [[C:%[0-9]+]] = shufflevector <2 x i1> [[B]], <2 x i1> zeroinitializer, <8 x i32> + // CHECK: [[D:%[0-9]+]] = bitcast <8 x i1> [[C]] to i8 + // CHECK: [[E:%[0-9]+]] = insertvalue { i8, i8 } poison, i8 [[D]], 0 + // CHECK: [[F:%[0-9]+]] = extractvalue { <2 x i1>, <2 x i1> } [[A]], 1 + // CHECK: [[G:%[0-9]+]] = shufflevector <2 x i1> [[F]], <2 x i1> zeroinitializer, <8 x i32> + // CHECK: [[H:%[0-9]+]] = bitcast <8 x i1> [[G]] to i8 + // CHECK: insertvalue { i8, i8 } [[E]], i8 [[H]], 1 + foo(a, b) +} + +// CHECK-LABEL: @i1_vector_autocast +#[no_mangle] +pub unsafe fn i1_vector_autocast(a: u8, b: u8) -> u8 { + extern "unadjusted" { + #[link_name = "llvm.x86.avx512.kadd.b"] + fn foo(a: u8, b: u8) -> u8; + } + + // CHECK: [[A:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1> + // CHECK: [[B:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1> + // CHECK: [[C:%[0-9]+]] = call <8 x i1> @llvm.x86.avx512.kadd.b(<8 x i1> [[A]], <8 x i1> [[B]]) + // CHECK: bitcast <8 x i1> [[C]] to i8 + foo(a, b) +} + +// CHECK-LABEL: @bf16_vector_autocast +#[no_mangle] +pub unsafe fn bf16_vector_autocast(a: f32x4) -> i16x8 { + extern "unadjusted" { + #[link_name = "llvm.x86.vcvtneps2bf16128"] + fn foo(a: f32x4) -> i16x8; + } + + // CHECK: [[A:%[0-9]+]] = call <8 x bfloat> @llvm.x86.vcvtneps2bf16128(<4 x float> {{.*}}) + // CHECK: bitcast <8 x bfloat> [[A]] to <8 x i16> + foo(a) +} + +// CHECK: declare { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } @llvm.x86.encodekey128(i32, <2 x i64>) + +// CHECK: declare { <2 x i1>, <2 x i1> } @llvm.x86.avx512.vp2intersect.q.128(<2 x i64>, <2 x i64>) + +// CHECK: declare <8 x i1> @llvm.x86.avx512.kadd.b(<8 x i1>, <8 x i1>) + +// CHECK: declare <8 x bfloat> @llvm.x86.vcvtneps2bf16128(<4 x float>) diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs index 238ab12c186ef..a4410c70ba38a 100644 --- a/tests/debuginfo/basic-stepping.rs +++ b/tests/debuginfo/basic-stepping.rs @@ -9,9 +9,20 @@ // Debugger tests need debuginfo //@ compile-flags: -g -// FIXME(#128945): SingleUseConsts shouldn't need to be disabled. -//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass -//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts +// Some optimization passes _improve_ compile times [1]. So we want to run some +// passes even with `-Copt-level=0`. That means that some of the lines below can +// be optimized away. To make regression testing more robust, we also want to +// run this test with such passes disabled. The solution is to use two +// revisions. One with default `-Copt-level=0` passes, and one "even less +// optimized", with enough optimization passes disabled to keep the maximum +// number of lines steppable. +// +// If `-Zmir-enable-passes=-...` ends up being annoying to maintain, we can try +// switching to `-Zmir-opt-level=0` instead. +// +// [1]: https://github.com/rust-lang/compiler-team/issues/319 +//@ revisions: opt-level-0 maximally-steppable +//@ [maximally-steppable] compile-flags: -Zmir-enable-passes=-SingleUseConsts // === GDB TESTS =================================================================================== @@ -20,12 +31,12 @@ //@ gdb-command: next //@ gdb-check: let d = c = 99; //@ gdb-command: next -//@ [no-SingleUseConsts-mir-pass] gdb-check: let e = "hi bob"; -//@ [no-SingleUseConsts-mir-pass] gdb-command: next -//@ [no-SingleUseConsts-mir-pass] gdb-check: let f = b"hi bob"; -//@ [no-SingleUseConsts-mir-pass] gdb-command: next -//@ [no-SingleUseConsts-mir-pass] gdb-check: let g = b'9'; -//@ [no-SingleUseConsts-mir-pass] gdb-command: next +//@ [maximally-steppable] gdb-check: let e = "hi bob"; +//@ [maximally-steppable] gdb-command: next +//@ [maximally-steppable] gdb-check: let f = b"hi bob"; +//@ [maximally-steppable] gdb-command: next +//@ [maximally-steppable] gdb-check: let g = b'9'; +//@ [maximally-steppable] gdb-command: next //@ gdb-check: let h = ["whatever"; 8]; //@ gdb-command: next //@ gdb-check: let i = [1,2,3,4]; @@ -61,15 +72,15 @@ //@ lldb-check: [...]let d = c = 99;[...] //@ lldb-command: next //@ lldb-command: frame select -//@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let e = "hi bob";[...] -//@ [no-SingleUseConsts-mir-pass] lldb-command: next -//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select -//@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let f = b"hi bob";[...] -//@ [no-SingleUseConsts-mir-pass] lldb-command: next -//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select -//@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let g = b'9';[...] -//@ [no-SingleUseConsts-mir-pass] lldb-command: next -//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select +//@ [maximally-steppable] lldb-check: [...]let e = "hi bob";[...] +//@ [maximally-steppable] lldb-command: next +//@ [maximally-steppable] lldb-command: frame select +//@ [maximally-steppable] lldb-check: [...]let f = b"hi bob";[...] +//@ [maximally-steppable] lldb-command: next +//@ [maximally-steppable] lldb-command: frame select +//@ [maximally-steppable] lldb-check: [...]let g = b'9';[...] +//@ [maximally-steppable] lldb-command: next +//@ [maximally-steppable] lldb-command: frame select //@ lldb-check: [...]let h = ["whatever"; 8];[...] //@ lldb-command: next //@ lldb-command: frame select @@ -107,12 +118,12 @@ //@ cdb-check: [...]: let mut c = 27; //@ cdb-command: p //@ cdb-check: [...]: let d = c = 99; -//@ [no-SingleUseConsts-mir-pass] cdb-command: p -//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let e = "hi bob"; -//@ [no-SingleUseConsts-mir-pass] cdb-command: p -//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let f = b"hi bob"; -//@ [no-SingleUseConsts-mir-pass] cdb-command: p -//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let g = b'9'; +//@ [maximally-steppable] cdb-command: p +//@ [maximally-steppable] cdb-check: [...]: let e = "hi bob"; +//@ [maximally-steppable] cdb-command: p +//@ [maximally-steppable] cdb-check: [...]: let f = b"hi bob"; +//@ [maximally-steppable] cdb-command: p +//@ [maximally-steppable] cdb-check: [...]: let g = b'9'; //@ cdb-command: p //@ cdb-check: [...]: let h = ["whatever"; 8]; //@ cdb-command: p diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index 3f57eb9ad79bd..c2f6183e3c7b0 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -16,9 +16,9 @@ extern crate macro_stepping; // exports new_scope!() //@ compile-flags: -g -// FIXME(#128945): SingleUseConsts shouldn't need to be disabled. -//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass -//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts +// See explanation in `tests/debuginfo/basic-stepping.rs`. +//@ revisions: opt-level-0 maximally-steppable +//@ [maximally-steppable] compile-flags: -Zmir-enable-passes=-SingleUseConsts // === GDB TESTS =================================================================================== @@ -51,7 +51,7 @@ extern crate macro_stepping; // exports new_scope!() //@ gdb-check:[...]#inc-loc2[...] //@ gdb-command:next //@ gdb-command:frame -//@ [no-SingleUseConsts-mir-pass] gdb-check:[...]#inc-loc3[...] +//@ [maximally-steppable] gdb-check:[...]#inc-loc3[...] // === LLDB TESTS ================================================================================== diff --git a/tests/run-make/simd-ffi/simd.rs b/tests/run-make/simd-ffi/simd.rs index 1cd961ff87e7b..3f12dabdb65ea 100644 --- a/tests/run-make/simd-ffi/simd.rs +++ b/tests/run-make/simd-ffi/simd.rs @@ -35,7 +35,7 @@ extern "C" { fn integer(a: i32x4, b: i32x4) -> i32x4; // vmaxq_s32 #[cfg(target_arch = "aarch64")] - #[link_name = "llvm.aarch64.neon.maxs.v4i32"] + #[link_name = "llvm.aarch64.neon.smax.v4i32"] fn integer(a: i32x4, b: i32x4) -> i32x4; // Use a generic LLVM intrinsic to do type checking on other platforms diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr index af94a33e4d7d3..83e84938d74ba 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -9,18 +9,6 @@ help: consider restricting type parameter `T` with trait `X` LL | impl X<'b, T>> X<'_, T> for (S,) { | ++++++++++++++++++ -error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied - --> $DIR/hr-associated-type-bound-param-6.rs:18:5 - | -LL | <(i32,) as X>::f("abc"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32` - | -help: the trait `X<'_, T>` is implemented for `(S,)` - --> $DIR/hr-associated-type-bound-param-6.rs:12:1 - | -LL | impl X<'_, T> for (S,) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:18:18 | @@ -41,6 +29,18 @@ LL | for<'b> T: X<'b, T>, LL | fn f(x: &>::U) { | - required by a bound in this associated function +error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:18:5 + | +LL | <(i32,) as X>::f("abc"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32` + | +help: the trait `X<'_, T>` is implemented for `(S,)` + --> $DIR/hr-associated-type-bound-param-6.rs:12:1 + | +LL | impl X<'_, T> for (S,) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `i32: X<'_, i32>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:18:27 | diff --git a/tests/ui/issues/issue-29516.rs b/tests/ui/auto-traits/distinct-type-tuple-by-negative-impl.rs similarity index 78% rename from tests/ui/issues/issue-29516.rs rename to tests/ui/auto-traits/distinct-type-tuple-by-negative-impl.rs index 52fd5ba8839d2..229a5583199b7 100644 --- a/tests/ui/issues/issue-29516.rs +++ b/tests/ui/auto-traits/distinct-type-tuple-by-negative-impl.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ check-pass #![feature(auto_traits)] #![feature(negative_impls)] diff --git a/tests/ui/issues/issue-3874.rs b/tests/ui/binding/ref-in-let-lhs-in-field.rs similarity index 76% rename from tests/ui/issues/issue-3874.rs rename to tests/ui/binding/ref-in-let-lhs-in-field.rs index 251e8e1da6d34..1b859ccd80b49 100644 --- a/tests/ui/issues/issue-3874.rs +++ b/tests/ui/binding/ref-in-let-lhs-in-field.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ build-pass #![allow(dead_code)] diff --git a/tests/ui/codegen/deprecated-llvm-intrinsic.rs b/tests/ui/codegen/deprecated-llvm-intrinsic.rs new file mode 100644 index 0000000000000..33bc5f419151a --- /dev/null +++ b/tests/ui/codegen/deprecated-llvm-intrinsic.rs @@ -0,0 +1,28 @@ +//@ add-minicore +//@ build-fail +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted, repr_simd, simd_ffi)] +#![no_std] +#![no_core] +#![allow(internal_features, non_camel_case_types, improper_ctypes)] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct i8x8([i8; 8]); + +extern "unadjusted" { + #[deny(deprecated_llvm_intrinsic)] + #[link_name = "llvm.aarch64.neon.rbit.v8i8"] + fn foo(a: i8x8) -> i8x8; + //~^ ERROR: using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead +} + +#[target_feature(enable = "neon")] +pub unsafe fn bar(a: i8x8) -> i8x8 { + foo(a) +} diff --git a/tests/ui/codegen/deprecated-llvm-intrinsic.stderr b/tests/ui/codegen/deprecated-llvm-intrinsic.stderr new file mode 100644 index 0000000000000..40e4684a8ea4f --- /dev/null +++ b/tests/ui/codegen/deprecated-llvm-intrinsic.stderr @@ -0,0 +1,14 @@ +error: using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead + --> $DIR/deprecated-llvm-intrinsic.rs:21:5 + | +LL | fn foo(a: i8x8) -> i8x8; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/deprecated-llvm-intrinsic.rs:19:12 + | +LL | #[deny(deprecated_llvm_intrinsic)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.rs b/tests/ui/codegen/incorrect-arch-intrinsic.rs new file mode 100644 index 0000000000000..9576cb8f81318 --- /dev/null +++ b/tests/ui/codegen/incorrect-arch-intrinsic.rs @@ -0,0 +1,18 @@ +//@ build-fail +//@ ignore-s390x +//@ normalize-stderr: "target arch `(.*)`" -> "target arch `TARGET_ARCH`" +//@ ignore-backends: gcc + +#![feature(link_llvm_intrinsics, abi_unadjusted)] + +extern "unadjusted" { + #[link_name = "llvm.s390.sfpc"] + fn foo(a: i32); + //~^ ERROR: intrinsic `llvm.s390.sfpc` cannot be used with target arch +} + +pub fn main() { + unsafe { + foo(0); + } +} diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.stderr b/tests/ui/codegen/incorrect-arch-intrinsic.stderr new file mode 100644 index 0000000000000..5b44419aa741f --- /dev/null +++ b/tests/ui/codegen/incorrect-arch-intrinsic.stderr @@ -0,0 +1,8 @@ +error: intrinsic `llvm.s390.sfpc` cannot be used with target arch `TARGET_ARCH` + --> $DIR/incorrect-arch-intrinsic.rs:10:5 + | +LL | fn foo(a: i32); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs new file mode 100644 index 0000000000000..4b86f37f922a6 --- /dev/null +++ b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs @@ -0,0 +1,14 @@ +//@ build-fail +//@ ignore-backends: gcc + +#![feature(link_llvm_intrinsics, abi_unadjusted)] + +extern "unadjusted" { + #[link_name = "llvm.assume"] + fn foo(); + //~^ ERROR: intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()` +} + +pub fn main() { + unsafe { foo() } +} diff --git a/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr new file mode 100644 index 0000000000000..4e58e5ebdc731 --- /dev/null +++ b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr @@ -0,0 +1,8 @@ +error: intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()` + --> $DIR/incorrect-llvm-intrinsic-signature.rs:8:5 + | +LL | fn foo(); + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/codegen/unknown-llvm-intrinsic.rs b/tests/ui/codegen/unknown-llvm-intrinsic.rs new file mode 100644 index 0000000000000..bbb4df8c0b271 --- /dev/null +++ b/tests/ui/codegen/unknown-llvm-intrinsic.rs @@ -0,0 +1,14 @@ +//@ build-fail +//@ ignore-backends: gcc + +#![feature(link_llvm_intrinsics, abi_unadjusted)] + +extern "unadjusted" { + #[link_name = "llvm.abcde"] + fn foo(); + //~^ ERROR: unknown LLVM intrinsic `llvm.abcde` +} + +pub fn main() { + unsafe { foo() } +} diff --git a/tests/ui/codegen/unknown-llvm-intrinsic.stderr b/tests/ui/codegen/unknown-llvm-intrinsic.stderr new file mode 100644 index 0000000000000..5417140c69795 --- /dev/null +++ b/tests/ui/codegen/unknown-llvm-intrinsic.stderr @@ -0,0 +1,8 @@ +error: unknown LLVM intrinsic `llvm.abcde` + --> $DIR/unknown-llvm-intrinsic.rs:8:5 + | +LL | fn foo(); + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/deref/derefmut-closure-drop-order.rs b/tests/ui/deref/derefmut-closure-drop-order.rs new file mode 100644 index 0000000000000..b95ae68f1734f --- /dev/null +++ b/tests/ui/deref/derefmut-closure-drop-order.rs @@ -0,0 +1,47 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16774 + +//@ run-pass +#![feature(box_patterns)] + +use std::ops::{Deref, DerefMut}; + +struct X(Box); + +static mut DESTRUCTOR_RAN: bool = false; + +impl Drop for X { + fn drop(&mut self) { + unsafe { + assert!(!DESTRUCTOR_RAN); + DESTRUCTOR_RAN = true; + } + } +} + +impl Deref for X { + type Target = isize; + + fn deref(&self) -> &isize { + let &X(box ref x) = self; + x + } +} + +impl DerefMut for X { + fn deref_mut(&mut self) -> &mut isize { + let &mut X(box ref mut x) = self; + x + } +} + +fn main() { + { + let mut test = X(Box::new(5)); + { + let mut change = || { *test = 10 }; + change(); + } + assert_eq!(*test, 10); + } + assert!(unsafe { DESTRUCTOR_RAN }); +} diff --git a/tests/ui/eii/attribute_targets.stderr b/tests/ui/eii/attribute_targets.stderr index bf04c323c95ca..8166609e19740 100644 --- a/tests/ui/eii/attribute_targets.stderr +++ b/tests/ui/eii/attribute_targets.stderr @@ -1,106 +1,106 @@ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:7:1 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:9:1 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:13:1 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:15:1 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:21:1 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:23:1 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:27:1 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:29:1 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:32:5 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:34:5 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:39:1 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:41:1 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:44:5 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:46:5 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:51:1 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:53:1 | LL | #[eii] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/attribute_targets.rs:56:5 | LL | #[foo] | ^^^^^^ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/attribute_targets.rs:58:5 | LL | #[eii] diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index b60a1dd0b2156..8806c7fa7d8ce 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -3,7 +3,7 @@ //@ run-pass //@ check-run-results //@ 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 EIIs with default implementations. // When there's no explicit declaration, the default should be called from the declaring crate. diff --git a/tests/ui/eii/default/call_default_panics.rs b/tests/ui/eii/default/call_default_panics.rs index 96b2742aa8e0a..db664e0cbcb0d 100644 --- a/tests/ui/eii/default/call_default_panics.rs +++ b/tests/ui/eii/default/call_default_panics.rs @@ -5,7 +5,7 @@ //@ needs-unwind //@ exec-env:RUST_BACKTRACE=1 //@ 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 // A small test to make sure that unwinding works properly. // diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index b887697574892..1a972774beaeb 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -4,7 +4,7 @@ //@ run-pass //@ check-run-results //@ 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 EIIs with default implementations. // When an explicit implementation is given in one dependency, and the declaration is in another, diff --git a/tests/ui/eii/default/local_crate.rs b/tests/ui/eii/default/local_crate.rs index d98c2fac4234e..fd4fd459c52fb 100644 --- a/tests/ui/eii/default/local_crate.rs +++ b/tests/ui/eii/default/local_crate.rs @@ -1,7 +1,7 @@ //@ run-pass //@ check-run-results //@ 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 EIIs with default implementations. // In the same crate, when there's no explicit declaration, the default should be called. diff --git a/tests/ui/eii/default/local_crate_explicit.rs b/tests/ui/eii/default/local_crate_explicit.rs index a4cc54fcd31fc..200905b8753a0 100644 --- a/tests/ui/eii/default/local_crate_explicit.rs +++ b/tests/ui/eii/default/local_crate_explicit.rs @@ -1,7 +1,7 @@ //@ run-pass //@ check-run-results //@ 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 EIIs with default implementations. // In the same crate, the explicit implementation should get priority. diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 3269778aca0c4..2128cac70eb30 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -2,7 +2,7 @@ //@ aux-build: impl1.rs //@ aux-build: impl2.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 that EIIs error properly, even if the conflicting implementations live in another crate. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index 4c883d28d74a4..b0f1b1266e4ca 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -3,7 +3,7 @@ //@ aux-build: impl2.rs //@ aux-build: impl3.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 the error message when there are multiple implementations of an EII in many crates. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index b046760745097..4b2b0fc111b58 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -4,7 +4,7 @@ //@ aux-build: impl3.rs //@ aux-build: impl4.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 the error message when there are multiple implementations of an EII in many crates. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/multiple_impls.rs b/tests/ui/eii/duplicate/multiple_impls.rs index c02c783223ac3..5ce2a27e16957 100644 --- a/tests/ui/eii/duplicate/multiple_impls.rs +++ b/tests/ui/eii/duplicate/multiple_impls.rs @@ -1,7 +1,7 @@ //@ run-pass //@ check-run-results //@ 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 one function could implement two EIIs. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs b/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs index 8564a5a748477..0d71f4854d344 100644 --- a/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs +++ b/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs @@ -6,7 +6,7 @@ const A: () = (); #[eii] fn A() {} //~ ERROR the name `A` is defined multiple times -//~^ ERROR expected function, found constant -//~| ERROR expected function, found constant +//~^ ERROR expected function or static, found constant +//~| ERROR expected function or static, found constant fn main() {} diff --git a/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr b/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr index ea4ec604e7aa4..34998f33cc92e 100644 --- a/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr +++ b/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr @@ -9,17 +9,17 @@ LL | fn A() {} | = note: `A` must be defined only once in the value namespace of this module -error[E0423]: expected function, found constant `self::A` +error[E0423]: expected function or static, found constant `self::A` --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4 | LL | fn A() {} - | ^ not a function + | ^ not a function or static -error[E0423]: expected function, found constant `A` +error[E0423]: expected function or static, found constant `A` --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4 | LL | fn A() {} - | ^ not a function + | ^ not a function or static error: aborting due to 3 previous errors diff --git a/tests/ui/eii/error_statement_position.stderr b/tests/ui/eii/error_statement_position.stderr index f14e6c33e64f5..c6af18044db8d 100644 --- a/tests/ui/eii/error_statement_position.stderr +++ b/tests/ui/eii/error_statement_position.stderr @@ -1,4 +1,4 @@ -error: `#[eii]` is only valid on functions +error: `#[eii]` is only valid on functions and statics --> $DIR/error_statement_position.rs:8:5 | LL | #[eii] diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs index 5fcf33336b402..bc6c17f463a78 100644 --- a/tests/ui/eii/errors.rs +++ b/tests/ui/eii/errors.rs @@ -25,11 +25,9 @@ unsafe extern "Rust" { safe fn bar(x: u64) -> u64; } -#[foo] //~ ERROR `#[foo]` is only valid on functions -static X: u64 = 4; -#[foo] //~ ERROR `#[foo]` is only valid on functions +#[foo] //~ ERROR `#[foo]` is only valid on functions and statics const Y: u64 = 4; -#[foo] //~ ERROR `#[foo]` is only valid on functions +#[foo] //~ ERROR `#[foo]` is only valid on functions and statics macro bar() {} #[foo()] diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr index c7eb96a9c2190..553ae622cb36f 100644 --- a/tests/ui/eii/errors.stderr +++ b/tests/ui/eii/errors.stderr @@ -52,47 +52,41 @@ error: `#[eii_declaration(...)]` expects a list of one or two elements LL | #[eii_declaration = "unsafe"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/errors.rs:28:1 | LL | #[foo] | ^^^^^^ -error: `#[foo]` is only valid on functions +error: `#[foo]` is only valid on functions and statics --> $DIR/errors.rs:30:1 | LL | #[foo] | ^^^^^^ -error: `#[foo]` is only valid on functions - --> $DIR/errors.rs:32:1 - | -LL | #[foo] - | ^^^^^^ - error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` - --> $DIR/errors.rs:35:1 + --> $DIR/errors.rs:33:1 | LL | #[foo()] | ^^^^^^^^ error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` - --> $DIR/errors.rs:37:1 + --> $DIR/errors.rs:35:1 | LL | #[foo(default, bar)] | ^^^^^^^^^^^^^^^^^^^^ error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` - --> $DIR/errors.rs:39:1 + --> $DIR/errors.rs:37:1 | LL | #[foo("default")] | ^^^^^^^^^^^^^^^^^ error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` - --> $DIR/errors.rs:41:1 + --> $DIR/errors.rs:39:1 | LL | #[foo = "default"] | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/eii/linking/codegen_cross_crate.rs b/tests/ui/eii/linking/codegen_cross_crate.rs index 2958a0f10521b..192aac5920704 100644 --- a/tests/ui/eii/linking/codegen_cross_crate.rs +++ b/tests/ui/eii/linking/codegen_cross_crate.rs @@ -3,7 +3,7 @@ //@ 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 +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether calling EIIs works with the declaration in another crate. diff --git a/tests/ui/eii/linking/codegen_single_crate.rs b/tests/ui/eii/linking/codegen_single_crate.rs index 8e85c354bba1c..d0e9c015da418 100644 --- a/tests/ui/eii/linking/codegen_single_crate.rs +++ b/tests/ui/eii/linking/codegen_single_crate.rs @@ -1,7 +1,7 @@ //@ run-pass //@ check-run-results //@ 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 calling EIIs works with the declaration in the same crate. #![feature(extern_item_impls)] diff --git a/tests/ui/eii/linking/same-symbol.rs b/tests/ui/eii/linking/same-symbol.rs index baf36ff4f5a0a..afba9b7750262 100644 --- a/tests/ui/eii/linking/same-symbol.rs +++ b/tests/ui/eii/linking/same-symbol.rs @@ -1,7 +1,7 @@ //@ run-pass //@ check-run-results //@ 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 #![feature(extern_item_impls)] diff --git a/tests/ui/eii/shadow_builtin.rs b/tests/ui/eii/shadow_builtin.rs new file mode 100644 index 0000000000000..5f619b79d01a4 --- /dev/null +++ b/tests/ui/eii/shadow_builtin.rs @@ -0,0 +1,17 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether calling EIIs works with the declaration in the same crate. +#![feature(extern_item_impls)] + +#[eii(inline)] +//~^ ERROR `#[inline]` required, but not found +fn test(x: u64); + +#[inline] +//~^ ERROR `inline` is ambiguous +fn test_impl(x: u64) { + println!("{x:?}") +} + +fn main() { } diff --git a/tests/ui/eii/shadow_builtin.stderr b/tests/ui/eii/shadow_builtin.stderr new file mode 100644 index 0000000000000..d48e66a18af20 --- /dev/null +++ b/tests/ui/eii/shadow_builtin.stderr @@ -0,0 +1,26 @@ +error[E0659]: `inline` is ambiguous + --> $DIR/shadow_builtin.rs:11:3 + | +LL | #[inline] + | ^^^^^^ ambiguous name + | + = note: ambiguous because of a name conflict with a builtin attribute + = note: `inline` could refer to a built-in attribute +note: `inline` could also refer to the attribute macro defined here + --> $DIR/shadow_builtin.rs:7:1 + | +LL | #[eii(inline)] + | ^^^^^^^^^^^^^^ + = help: use `crate::inline` to refer to this attribute macro unambiguously + +error: `#[inline]` required, but not found + --> $DIR/shadow_builtin.rs:7:7 + | +LL | #[eii(inline)] + | ^^^^^^ expected because `#[inline]` was declared here in crate `shadow_builtin` + | + = help: expected at least one implementation in crate `shadow_builtin` or any of its dependencies + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/eii/static/argument_required.rs b/tests/ui/eii/static/argument_required.rs new file mode 100644 index 0000000000000..114b8a35de5cf --- /dev/null +++ b/tests/ui/eii/static/argument_required.rs @@ -0,0 +1,11 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii] +//~^ ERROR `#[eii]` requires the name as an explicit argument when used on a static +static HELLO: u64; + +fn main() { } diff --git a/tests/ui/eii/static/argument_required.stderr b/tests/ui/eii/static/argument_required.stderr new file mode 100644 index 0000000000000..9e5ee398f77d8 --- /dev/null +++ b/tests/ui/eii/static/argument_required.stderr @@ -0,0 +1,8 @@ +error: `#[eii]` requires the name as an explicit argument when used on a static + --> $DIR/argument_required.rs:7:1 + | +LL | #[eii] + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/auxiliary/cross_crate_decl.rs b/tests/ui/eii/static/auxiliary/cross_crate_decl.rs new file mode 100644 index 0000000000000..06b7daca22074 --- /dev/null +++ b/tests/ui/eii/static/auxiliary/cross_crate_decl.rs @@ -0,0 +1,6 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(extern_item_impls)] + +#[eii(eii1)] +pub static DECL1: u64; diff --git a/tests/ui/eii/static/auxiliary/cross_crate_def.rs b/tests/ui/eii/static/auxiliary/cross_crate_def.rs new file mode 100644 index 0000000000000..70933440a62be --- /dev/null +++ b/tests/ui/eii/static/auxiliary/cross_crate_def.rs @@ -0,0 +1,9 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] +#![feature(extern_item_impls)] + +#[eii(eii1)] +pub static DECL1: u64; + +#[eii1] +pub static EII1_IMPL: u64 = 5; diff --git a/tests/ui/eii/static/cross_crate_decl.rs b/tests/ui/eii/static/cross_crate_decl.rs new file mode 100644 index 0000000000000..63e3511198e1d --- /dev/null +++ b/tests/ui/eii/static/cross_crate_decl.rs @@ -0,0 +1,21 @@ +//@ run-pass +//@ check-run-results +//@ aux-build: cross_crate_decl.rs +//@ compile-flags: -O +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether calling EIIs works with the declaration in another crate. + +extern crate cross_crate_decl as codegen; + +#[codegen::eii1] +static EII1_IMPL: u64 = 5; + +// what you would write: +fn main() { + // directly + println!("{}", EII1_IMPL); + // through the alias + println!("{}", codegen::DECL1); +} diff --git a/tests/ui/eii/static/cross_crate_decl.run.stdout b/tests/ui/eii/static/cross_crate_decl.run.stdout new file mode 100644 index 0000000000000..fd3c81a4d7631 --- /dev/null +++ b/tests/ui/eii/static/cross_crate_decl.run.stdout @@ -0,0 +1,2 @@ +5 +5 diff --git a/tests/ui/eii/static/cross_crate_def.rs b/tests/ui/eii/static/cross_crate_def.rs new file mode 100644 index 0000000000000..a0b6afbfd760b --- /dev/null +++ b/tests/ui/eii/static/cross_crate_def.rs @@ -0,0 +1,18 @@ +//@ run-pass +//@ check-run-results +//@ aux-build: cross_crate_def.rs +//@ compile-flags: -O +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether calling EIIs works with the declaration and definition in another crate. + +extern crate cross_crate_def as codegen; + +// what you would write: +fn main() { + // directly + println!("{}", codegen::EII1_IMPL); + // through the alias + println!("{}", codegen::DECL1); +} diff --git a/tests/ui/eii/static/cross_crate_def.run.stdout b/tests/ui/eii/static/cross_crate_def.run.stdout new file mode 100644 index 0000000000000..fd3c81a4d7631 --- /dev/null +++ b/tests/ui/eii/static/cross_crate_def.run.stdout @@ -0,0 +1,2 @@ +5 +5 diff --git a/tests/ui/eii/static/duplicate.rs b/tests/ui/eii/static/duplicate.rs new file mode 100644 index 0000000000000..12b2e56c07e4e --- /dev/null +++ b/tests/ui/eii/static/duplicate.rs @@ -0,0 +1,25 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +static HELLO: u64; + +#[hello] +static HELLO_IMPL1: u64 = 5; +//~^ ERROR multiple implementations of `#[hello]` + +#[hello] +static HELLO_IMPL2: u64 = 6; + +// what you would write: +fn main() { + // directly + println!("{HELLO_IMPL1}"); + println!("{HELLO_IMPL2}"); + + // through the alias + println!("{HELLO}"); +} diff --git a/tests/ui/eii/static/duplicate.stderr b/tests/ui/eii/static/duplicate.stderr new file mode 100644 index 0000000000000..270664c8c74c6 --- /dev/null +++ b/tests/ui/eii/static/duplicate.stderr @@ -0,0 +1,13 @@ +error: multiple implementations of `#[hello]` + --> $DIR/duplicate.rs:11:1 + | +LL | static HELLO_IMPL1: u64 = 5; + | ^^^^^^^^^^^^^^^^^^^^^^^ first implemented here in crate `duplicate` +... +LL | static HELLO_IMPL2: u64 = 6; + | ----------------------- also implemented here in crate `duplicate` + | + = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/mismatch_fn_static.rs b/tests/ui/eii/static/mismatch_fn_static.rs new file mode 100644 index 0000000000000..298fdca18d967 --- /dev/null +++ b/tests/ui/eii/static/mismatch_fn_static.rs @@ -0,0 +1,14 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +fn hello() -> u64; + +#[hello] +//~^ ERROR `#[hello]` must be used on a function +static HELLO_IMPL: u64 = 5; + +fn main() { } diff --git a/tests/ui/eii/static/mismatch_fn_static.stderr b/tests/ui/eii/static/mismatch_fn_static.stderr new file mode 100644 index 0000000000000..e8fa5f85b1f13 --- /dev/null +++ b/tests/ui/eii/static/mismatch_fn_static.stderr @@ -0,0 +1,8 @@ +error: `#[hello]` must be used on a function + --> $DIR/mismatch_fn_static.rs:10:1 + | +LL | #[hello] + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/mismatch_mut.rs b/tests/ui/eii/static/mismatch_mut.rs new file mode 100644 index 0000000000000..87c2c4128aa5e --- /dev/null +++ b/tests/ui/eii/static/mismatch_mut.rs @@ -0,0 +1,22 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +//~^ ERROR `#[eii]` cannot be used on mutable statics +static mut HELLO: u64; + +#[hello] +//~^ ERROR mutability does not match with the definition of`#[hello]` +static HELLO_IMPL: u64 = 5; + +// what you would write: +fn main() { + // directly + println!("{HELLO_IMPL}"); + + // through the alias + println!("{}", unsafe { HELLO }); +} diff --git a/tests/ui/eii/static/mismatch_mut.stderr b/tests/ui/eii/static/mismatch_mut.stderr new file mode 100644 index 0000000000000..537ac0de3c3a2 --- /dev/null +++ b/tests/ui/eii/static/mismatch_mut.stderr @@ -0,0 +1,14 @@ +error: `#[eii]` cannot be used on mutable statics + --> $DIR/mismatch_mut.rs:7:1 + | +LL | #[eii(hello)] + | ^^^^^^^^^^^^^ + +error: mutability does not match with the definition of`#[hello]` + --> $DIR/mismatch_mut.rs:11:1 + | +LL | #[hello] + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/eii/static/mismatch_mut2.rs b/tests/ui/eii/static/mismatch_mut2.rs new file mode 100644 index 0000000000000..ab525e418adeb --- /dev/null +++ b/tests/ui/eii/static/mismatch_mut2.rs @@ -0,0 +1,21 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +static HELLO: u64; + +#[hello] +//~^ ERROR mutability does not match with the definition of`#[hello]` +static mut HELLO_IMPL: u64 = 5; + +// what you would write: +fn main() { + // directly + println!("{}", unsafe { HELLO_IMPL }); + + // through the alias + println!("{HELLO}"); +} diff --git a/tests/ui/eii/static/mismatch_mut2.stderr b/tests/ui/eii/static/mismatch_mut2.stderr new file mode 100644 index 0000000000000..6ac3df57697db --- /dev/null +++ b/tests/ui/eii/static/mismatch_mut2.stderr @@ -0,0 +1,8 @@ +error: mutability does not match with the definition of`#[hello]` + --> $DIR/mismatch_mut2.rs:10:1 + | +LL | #[hello] + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/mismatch_safety.rs b/tests/ui/eii/static/mismatch_safety.rs new file mode 100644 index 0000000000000..f30326b0755c0 --- /dev/null +++ b/tests/ui/eii/static/mismatch_safety.rs @@ -0,0 +1,21 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +unsafe static HELLO: u64; + +#[hello] +//~^ ERROR safety does not match with the definition of`#[hello]` +static HELLO_IMPL: u64 = 5; + +// what you would write: +fn main() { + // directly + println!("{HELLO_IMPL}"); + + // through the alias + println!("{}", unsafe { HELLO }); +} diff --git a/tests/ui/eii/static/mismatch_safety.stderr b/tests/ui/eii/static/mismatch_safety.stderr new file mode 100644 index 0000000000000..d4fa85778ae11 --- /dev/null +++ b/tests/ui/eii/static/mismatch_safety.stderr @@ -0,0 +1,8 @@ +error: safety does not match with the definition of`#[hello]` + --> $DIR/mismatch_safety.rs:10:1 + | +LL | #[hello] + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/mismatch_safety2.rs b/tests/ui/eii/static/mismatch_safety2.rs new file mode 100644 index 0000000000000..dea45c26292d8 --- /dev/null +++ b/tests/ui/eii/static/mismatch_safety2.rs @@ -0,0 +1,21 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +static HELLO: u64; + +#[hello] +unsafe static HELLO_IMPL: u64 = 5; +//~^ ERROR static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + +// what you would write: +fn main() { + // directly + println!("{HELLO_IMPL}"); + + // through the alias + println!("{}", unsafe { HELLO }); +} diff --git a/tests/ui/eii/static/mismatch_safety2.stderr b/tests/ui/eii/static/mismatch_safety2.stderr new file mode 100644 index 0000000000000..6957a6202b614 --- /dev/null +++ b/tests/ui/eii/static/mismatch_safety2.stderr @@ -0,0 +1,8 @@ +error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + --> $DIR/mismatch_safety2.rs:11:1 + | +LL | unsafe static HELLO_IMPL: u64 = 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/mismatch_static_fn.rs b/tests/ui/eii/static/mismatch_static_fn.rs new file mode 100644 index 0000000000000..cd9a8109dc339 --- /dev/null +++ b/tests/ui/eii/static/mismatch_static_fn.rs @@ -0,0 +1,16 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +static HELLO: u64; + +#[hello] +//~^ ERROR `#[hello]` must be used on a static +fn hello_impl() -> u64 { + 5 +} + +fn main() { } diff --git a/tests/ui/eii/static/mismatch_static_fn.stderr b/tests/ui/eii/static/mismatch_static_fn.stderr new file mode 100644 index 0000000000000..639e3cfa3beb3 --- /dev/null +++ b/tests/ui/eii/static/mismatch_static_fn.stderr @@ -0,0 +1,8 @@ +error: `#[hello]` must be used on a static + --> $DIR/mismatch_static_fn.rs:10:1 + | +LL | #[hello] + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/multiple_decls.rs b/tests/ui/eii/static/multiple_decls.rs new file mode 100644 index 0000000000000..791e2725087f1 --- /dev/null +++ b/tests/ui/eii/static/multiple_decls.rs @@ -0,0 +1,12 @@ +#![feature(extern_item_impls)] + +const A: () = (); +#[eii(A)] +static A: u64; +//~^ ERROR the name `A` is defined multiple times +//~| ERROR expected function or static, found constant `A` + +#[A] +static A_IMPL: u64 = 5; + +fn main() {} diff --git a/tests/ui/eii/static/multiple_decls.stderr b/tests/ui/eii/static/multiple_decls.stderr new file mode 100644 index 0000000000000..fcc5d93c5f993 --- /dev/null +++ b/tests/ui/eii/static/multiple_decls.stderr @@ -0,0 +1,21 @@ +error[E0428]: the name `A` is defined multiple times + --> $DIR/multiple_decls.rs:5:1 + | +LL | const A: () = (); + | ----------------- previous definition of the value `A` here +LL | #[eii(A)] +LL | static A: u64; + | ^^^^^^^^^^^^^^ `A` redefined here + | + = note: `A` must be defined only once in the value namespace of this module + +error[E0423]: expected function or static, found constant `A` + --> $DIR/multiple_decls.rs:5:8 + | +LL | static A: u64; + | ^ not a function or static + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0428. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/eii/static/multiple_impls.rs b/tests/ui/eii/static/multiple_impls.rs new file mode 100644 index 0000000000000..8ad7d87040a36 --- /dev/null +++ b/tests/ui/eii/static/multiple_impls.rs @@ -0,0 +1,20 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether one function could implement two EIIs. +#![feature(extern_item_impls)] + +#[eii(a)] +static A: u64; + +#[eii(b)] +static B: u64; + +#[a] +#[b] +//~^ ERROR static cannot implement multiple EIIs +static IMPL: u64 = 5; + +fn main() { + println!("{A} {B} {IMPL}") +} diff --git a/tests/ui/eii/static/multiple_impls.run.stdout b/tests/ui/eii/static/multiple_impls.run.stdout new file mode 100644 index 0000000000000..58945c2b48291 --- /dev/null +++ b/tests/ui/eii/static/multiple_impls.run.stdout @@ -0,0 +1 @@ +5 5 5 diff --git a/tests/ui/eii/static/multiple_impls.stderr b/tests/ui/eii/static/multiple_impls.stderr new file mode 100644 index 0000000000000..b31331f2483f1 --- /dev/null +++ b/tests/ui/eii/static/multiple_impls.stderr @@ -0,0 +1,10 @@ +error: static cannot implement multiple EIIs + --> $DIR/multiple_impls.rs:14:1 + | +LL | #[b] + | ^^^^ + | + = note: this is not allowed because multiple externally implementable statics that alias may be unintuitive + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/mut.rs b/tests/ui/eii/static/mut.rs new file mode 100644 index 0000000000000..803ffc2297992 --- /dev/null +++ b/tests/ui/eii/static/mut.rs @@ -0,0 +1,21 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +//~^ ERROR `#[eii]` cannot be used on mutable statics +static mut HELLO: u64; + +#[hello] +static mut HELLO_IMPL: u64 = 5; + +// what you would write: +fn main() { + // directly + println!("{}", unsafe { HELLO_IMPL }); + + // through the alias + println!("{}", unsafe { HELLO }); +} diff --git a/tests/ui/eii/static/mut.run.stdout b/tests/ui/eii/static/mut.run.stdout new file mode 100644 index 0000000000000..fd3c81a4d7631 --- /dev/null +++ b/tests/ui/eii/static/mut.run.stdout @@ -0,0 +1,2 @@ +5 +5 diff --git a/tests/ui/eii/static/mut.stderr b/tests/ui/eii/static/mut.stderr new file mode 100644 index 0000000000000..cd3a0ca23c7f4 --- /dev/null +++ b/tests/ui/eii/static/mut.stderr @@ -0,0 +1,8 @@ +error: `#[eii]` cannot be used on mutable statics + --> $DIR/mut.rs:7:1 + | +LL | #[eii(hello)] + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/eii/static/same_address.rs b/tests/ui/eii/static/same_address.rs new file mode 100644 index 0000000000000..81de19406dc49 --- /dev/null +++ b/tests/ui/eii/static/same_address.rs @@ -0,0 +1,21 @@ +//@ run-pass +//@ check-run-results +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs and their declarations share the same address +#![feature(extern_item_impls)] + +#[eii(hello)] +static HELLO: u64; + +#[hello] +static HELLO_IMPL: u64 = 5; + +// what you would write: +fn main() { + assert_eq!( + &HELLO as *const u64 as usize, + &HELLO_IMPL as *const u64 as usize, + ) +} diff --git a/tests/ui/eii/static/simple.rs b/tests/ui/eii/static/simple.rs new file mode 100644 index 0000000000000..661ab9b9835f2 --- /dev/null +++ b/tests/ui/eii/static/simple.rs @@ -0,0 +1,22 @@ +//@ run-pass +//@ check-run-results +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests whether EIIs work on statics +#![feature(extern_item_impls)] + +#[eii(hello)] +static HELLO: u64; + +#[hello] +static HELLO_IMPL: u64 = 5; + +// what you would write: +fn main() { + // directly + println!("{HELLO_IMPL}"); + + // through the alias + println!("{HELLO}"); +} diff --git a/tests/ui/eii/static/simple.run.stdout b/tests/ui/eii/static/simple.run.stdout new file mode 100644 index 0000000000000..fd3c81a4d7631 --- /dev/null +++ b/tests/ui/eii/static/simple.run.stdout @@ -0,0 +1,2 @@ +5 +5 diff --git a/tests/ui/eii/static/subtype.rs b/tests/ui/eii/static/subtype.rs new file mode 100644 index 0000000000000..d98e94fa90322 --- /dev/null +++ b/tests/ui/eii/static/subtype.rs @@ -0,0 +1,18 @@ +//@ check-pass +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests that mismatching types of the declaration and definition are rejected +#![feature(extern_item_impls)] + +use std::ptr; + +#[eii(hello)] +static HELLO: for<'a> fn(&'a u8) -> &'a u8; + +#[hello] +static HELLO_IMPL: for<'a> fn(&'a u8) -> &'static u8 = |_| todo!(); + +fn main() { + +} diff --git a/tests/ui/eii/static/subtype_wrong.rs b/tests/ui/eii/static/subtype_wrong.rs new file mode 100644 index 0000000000000..964a3d767b197 --- /dev/null +++ b/tests/ui/eii/static/subtype_wrong.rs @@ -0,0 +1,17 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests that mismatching types of the declaration and definition are rejected +#![feature(extern_item_impls)] + +use std::ptr; + +#[eii(hello)] +static HELLO: for<'a> fn(&'a u8) -> &'static u8; + +#[hello] +static HELLO_IMPL: for<'a> fn(&'a u8) -> &'a u8 = |_| todo!(); +//~^ ERROR mismatched types + +fn main() { +} diff --git a/tests/ui/eii/static/subtype_wrong.stderr b/tests/ui/eii/static/subtype_wrong.stderr new file mode 100644 index 0000000000000..a20074947c15d --- /dev/null +++ b/tests/ui/eii/static/subtype_wrong.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/subtype_wrong.rs:13:1 + | +LL | static HELLO_IMPL: for<'a> fn(&'a u8) -> &'a u8 = |_| todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'a> fn(&'a _) -> &'static _` + found fn pointer `for<'a> fn(&'a _) -> &'a _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/eii/static/wrong_ty.rs b/tests/ui/eii/static/wrong_ty.rs new file mode 100644 index 0000000000000..beee0a5a0857b --- /dev/null +++ b/tests/ui/eii/static/wrong_ty.rs @@ -0,0 +1,18 @@ +//@ ignore-backends: gcc +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 +//@ ignore-windows +// Tests that mismatching types of the declaration and definition are rejected +#![feature(extern_item_impls)] + +use std::ptr; + +#[eii(hello)] +static HELLO: u64; + +#[hello] +static HELLO_IMPL: bool = true; +//~^ ERROR static `HELLO_IMPL` has a type that is incompatible with the declaration of `#[hello]` [E0806] + +fn main() { + +} diff --git a/tests/ui/eii/static/wrong_ty.stderr b/tests/ui/eii/static/wrong_ty.stderr new file mode 100644 index 0000000000000..5095513527747 --- /dev/null +++ b/tests/ui/eii/static/wrong_ty.stderr @@ -0,0 +1,15 @@ +error[E0806]: static `HELLO_IMPL` has a type that is incompatible with the declaration of `#[hello]` + --> $DIR/wrong_ty.rs:13:1 + | +LL | static HELLO_IMPL: bool = true; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this because of this attribute + --> $DIR/wrong_ty.rs:12:1 + | +LL | #[hello] + | ^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0806`. diff --git a/tests/ui/issues/issue-32782.rs b/tests/ui/feature-gates/feature-gate-check-nested-macro-invocation.rs similarity index 80% rename from tests/ui/issues/issue-32782.rs rename to tests/ui/feature-gates/feature-gate-check-nested-macro-invocation.rs index 1e99a25cec3a5..c81d2e538c7f3 100644 --- a/tests/ui/issues/issue-32782.rs +++ b/tests/ui/feature-gates/feature-gate-check-nested-macro-invocation.rs @@ -1,3 +1,4 @@ +//! Regression test for macro_rules! bar ( () => () ); diff --git a/tests/ui/issues/issue-32782.stderr b/tests/ui/feature-gates/feature-gate-check-nested-macro-invocation.stderr similarity index 89% rename from tests/ui/issues/issue-32782.stderr rename to tests/ui/feature-gates/feature-gate-check-nested-macro-invocation.stderr index 2a1183ab978d0..cc3dda7c1f09a 100644 --- a/tests/ui/issues/issue-32782.stderr +++ b/tests/ui/feature-gates/feature-gate-check-nested-macro-invocation.stderr @@ -1,5 +1,5 @@ error[E0658]: allow_internal_unstable side-steps feature gating and stability checks - --> $DIR/issue-32782.rs:7:9 + --> $DIR/feature-gate-check-nested-macro-invocation.rs:8:9 | LL | #[allow_internal_unstable()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | foo!(); = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error: `#[allow_internal_unstable]` attribute cannot be used on macro calls - --> $DIR/issue-32782.rs:7:9 + --> $DIR/feature-gate-check-nested-macro-invocation.rs:8:9 | LL | #[allow_internal_unstable()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs index a1f3b1fbbc860..a55a6260d6512 100644 --- a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs @@ -2,9 +2,8 @@ //! gate, but the fact that not adding the feature gate will cause the //! diagnostic to not emit the custom diagnostic message //! -#[diagnostic::on_move( - message = "Foo" -)] +#[diagnostic::on_move(message = "Foo")] +//~^ WARN unknown diagnostic attribute #[derive(Debug)] struct Foo; diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr index 9ba6f272cf92b..593120edd1700 100644 --- a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr @@ -1,5 +1,14 @@ +warning: unknown diagnostic attribute + --> $DIR/feature-gate-diagnostic-on-move.rs:5:15 + | +LL | #[diagnostic::on_move(message = "Foo")] + | ^^^^^^^ + | + = help: add `#![feature(diagnostic_on_move)]` to the crate attributes to enable + = note: `#[warn(unknown_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + error[E0382]: use of moved value: `foo` - --> $DIR/feature-gate-diagnostic-on-move.rs:16:15 + --> $DIR/feature-gate-diagnostic-on-move.rs:15:15 | LL | let foo = Foo; | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait @@ -9,14 +18,14 @@ LL | let bar = foo; | ^^^ value used here after move | note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary - --> $DIR/feature-gate-diagnostic-on-move.rs:11:17 + --> $DIR/feature-gate-diagnostic-on-move.rs:10:17 | LL | fn takes_foo(_: Foo) {} | --------- ^^^ this parameter takes ownership of the value | | | in this function note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/feature-gate-diagnostic-on-move.rs:9:1 + --> $DIR/feature-gate-diagnostic-on-move.rs:8:1 | LL | struct Foo; | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -24,6 +33,6 @@ LL | struct Foo; LL | takes_foo(foo); | --- you could clone this value -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr index f6d7ffadaceae..d9c8071339b75 100644 --- a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr @@ -10,6 +10,7 @@ error: unknown diagnostic attribute LL | #[diagnostic::on_unknown(message = "Tada")] | ^^^^^^^^^^ | + = help: add `#![feature(diagnostic_on_unknown)]` to the crate attributes to enable note: the lint level is defined here --> $DIR/feature-gate-diagnostic-on-unknown.rs:1:9 | diff --git a/tests/ui/imports/issue-56125.rs b/tests/ui/imports/issue-56125.rs index 4e7e7ac67c572..a30ac36473bdd 100644 --- a/tests/ui/imports/issue-56125.rs +++ b/tests/ui/imports/issue-56125.rs @@ -15,7 +15,7 @@ mod m2 { mod m3 { mod empty {} use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125` - use issue_56125::*; //~ ERROR `issue_56125` is ambiguous + use issue_56125::*; } fn main() {} diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index 371130facf9d3..f9a169b17a2f9 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -54,24 +54,7 @@ LL | use issue_56125::non_last_segment::non_last_segment::*; = help: consider adding an explicit import of `issue_56125` to disambiguate = help: or use `self::issue_56125` to refer to this module unambiguously -error[E0659]: `issue_56125` is ambiguous - --> $DIR/issue-56125.rs:18:9 - | -LL | use issue_56125::*; - | ^^^^^^^^^^^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution - = note: `issue_56125` could refer to a crate passed with `--extern` - = help: use `::issue_56125` to refer to this crate unambiguously -note: `issue_56125` could also refer to the module imported here - --> $DIR/issue-56125.rs:18:9 - | -LL | use issue_56125::*; - | ^^^^^^^^^^^^^^ - = help: consider adding an explicit import of `issue_56125` to disambiguate - = help: or use `self::issue_56125` to refer to this module unambiguously - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0432, E0659. For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.rs b/tests/ui/imports/shadow-glob-module-resolution-2.rs index c3abd1f75542c..ac2901eb35290 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-2.rs +++ b/tests/ui/imports/shadow-glob-module-resolution-2.rs @@ -14,7 +14,5 @@ use a::*; use e as b; //~^ ERROR: unresolved import `e` use b::c::D as e; -//~^ ERROR: cannot determine resolution for the import -//~| ERROR: cannot determine resolution for the import fn main() { } diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.stderr b/tests/ui/imports/shadow-glob-module-resolution-2.stderr index 26745384dee34..ba8a2ce2d29f8 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-2.stderr +++ b/tests/ui/imports/shadow-glob-module-resolution-2.stderr @@ -1,17 +1,3 @@ -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-2.rs:16:5 - | -LL | use b::c::D as e; - | ^^^^^^^^^^^^ - -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-2.rs:16:5 - | -LL | use b::c::D as e; - | ^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0432]: unresolved import `e` --> $DIR/shadow-glob-module-resolution-2.rs:14:5 | @@ -24,6 +10,6 @@ LL - use e as b; LL + use a as b; | -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.rs b/tests/ui/imports/shadow-glob-module-resolution-4.rs index 581cdc185d3f3..38fe7d17a367f 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-4.rs +++ b/tests/ui/imports/shadow-glob-module-resolution-4.rs @@ -12,8 +12,6 @@ use e as b; use b::C as e; //~^ ERROR: unresolved import `b::C` -//~| ERROR: cannot determine resolution for the import -//~| ERROR: cannot determine resolution for the import fn e() {} diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.stderr b/tests/ui/imports/shadow-glob-module-resolution-4.stderr index 063beb612b132..d94a59347a5b8 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-4.stderr +++ b/tests/ui/imports/shadow-glob-module-resolution-4.stderr @@ -1,23 +1,9 @@ -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-4.rs:13:5 - | -LL | use b::C as e; - | ^^^^^^^^^ - -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-4.rs:13:5 - | -LL | use b::C as e; - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0432]: unresolved import `b::C` --> $DIR/shadow-glob-module-resolution-4.rs:13:5 | LL | use b::C as e; | ^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/issues/issue-3154.rs b/tests/ui/lifetimes/missing-lifetime-in-return.rs similarity index 73% rename from tests/ui/issues/issue-3154.rs rename to tests/ui/lifetimes/missing-lifetime-in-return.rs index 91c7203c1d002..f4ca4347fa41d 100644 --- a/tests/ui/issues/issue-3154.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-return.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3154 + struct Thing<'a, Q:'a> { x: &'a Q } diff --git a/tests/ui/issues/issue-3154.stderr b/tests/ui/lifetimes/missing-lifetime-in-return.stderr similarity index 89% rename from tests/ui/issues/issue-3154.stderr rename to tests/ui/lifetimes/missing-lifetime-in-return.stderr index c17e59f7fc3d6..aa5803e97529c 100644 --- a/tests/ui/issues/issue-3154.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-return.stderr @@ -1,5 +1,5 @@ error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/issue-3154.rs:6:5 + --> $DIR/missing-lifetime-in-return.rs:8:5 | LL | Thing { x: x } | ^^^^^^^^^^^^^^ lifetime `'a` required diff --git a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs index 8bc11ce31d195..61fb67174fde4 100644 --- a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs +++ b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs @@ -1,5 +1,6 @@ // Test for #151358, assertion failed: !worker_thread.is_null() -//~^ ERROR cycle detected when looking up span for `Default` +//~^ ERROR internal compiler error: query cycle when printing cycle detected +//~^^ ERROR cycle detected when getting the resolver for lowering // //@ compile-flags: -Z threads=2 //@ compare-output-by-lines diff --git a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr index 9c1d7b1de33a5..d81b7d142c92f 100644 --- a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr +++ b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr @@ -1,9 +1,21 @@ -error[E0391]: cycle detected when looking up span for `Default` +error: internal compiler error: query cycle when printing cycle detected | - = note: ...which immediately requires looking up span for `Default` again - = note: cycle used when perform lints prior to AST lowering + = note: ...when getting HIR ID of `Default` + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which requires looking up span for `Default`... + = note: ...which again requires getting HIR ID of `Default`, completing the cycle + = note: cycle used when getting the resolver for lowering = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error[E0391]: cycle detected when getting the resolver for lowering + | + = note: ...which requires getting HIR ID of `Default`... + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which again requires getting the resolver for lowering, completing the cycle + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/issues/issue-5100.rs b/tests/ui/pattern/match-errors-derived-error-suppression.rs similarity index 95% rename from tests/ui/issues/issue-5100.rs rename to tests/ui/pattern/match-errors-derived-error-suppression.rs index e9ae551bb77f4..7d817167afcb7 100644 --- a/tests/ui/issues/issue-5100.rs +++ b/tests/ui/pattern/match-errors-derived-error-suppression.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ dont-require-annotations: NOTE #![feature(box_patterns)] diff --git a/tests/ui/issues/issue-5100.stderr b/tests/ui/pattern/match-errors-derived-error-suppression.stderr similarity index 84% rename from tests/ui/issues/issue-5100.stderr rename to tests/ui/pattern/match-errors-derived-error-suppression.stderr index c545f70415c13..6dc5e0eaca6b4 100644 --- a/tests/ui/issues/issue-5100.stderr +++ b/tests/ui/pattern/match-errors-derived-error-suppression.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-5100.rs:9:9 + --> $DIR/match-errors-derived-error-suppression.rs:10:9 | LL | match (true, false) { | ------------- this expression has type `(bool, bool)` @@ -10,7 +10,7 @@ LL | A::B => (), found enum `A` error[E0308]: mismatched types - --> $DIR/issue-5100.rs:18:9 + --> $DIR/match-errors-derived-error-suppression.rs:19:9 | LL | match (true, false) { | ------------- this expression has type `(bool, bool)` @@ -21,7 +21,7 @@ LL | (true, false, false) => () found tuple `(_, _, _)` error[E0308]: mismatched types - --> $DIR/issue-5100.rs:26:9 + --> $DIR/match-errors-derived-error-suppression.rs:27:9 | LL | match (true, false) { | ------------- this expression has type `(bool, bool)` @@ -32,7 +32,7 @@ LL | (true, false, false) => () found tuple `(_, _, _)` error[E0308]: mismatched types - --> $DIR/issue-5100.rs:34:9 + --> $DIR/match-errors-derived-error-suppression.rs:35:9 | LL | match (true, false) { | ------------- this expression has type `(bool, bool)` @@ -43,7 +43,7 @@ LL | box (true, false) => () found struct `Box<_>` error[E0308]: mismatched types - --> $DIR/issue-5100.rs:41:9 + --> $DIR/match-errors-derived-error-suppression.rs:42:9 | LL | match (true, false) { | ------------- this expression has type `(bool, bool)` @@ -54,13 +54,13 @@ LL | &(true, false) => () found reference `&_` error[E0618]: expected function, found `(char, char)` - --> $DIR/issue-5100.rs:49:14 + --> $DIR/match-errors-derived-error-suppression.rs:50:14 | LL | let v = [('a', 'b') | ^^^^^^^^^^- help: consider separating array elements with a comma: `,` error[E0308]: mismatched types - --> $DIR/issue-5100.rs:56:19 + --> $DIR/match-errors-derived-error-suppression.rs:57:19 | LL | let x: char = true; | ---- ^^^^ expected `char`, found `bool` diff --git a/tests/ui/issues/issue-21033.rs b/tests/ui/pattern/match-struct-var-having-boxed-field.rs similarity index 93% rename from tests/ui/issues/issue-21033.rs rename to tests/ui/pattern/match-struct-var-having-boxed-field.rs index e6b13eb3f4b01..963fab4444ecd 100644 --- a/tests/ui/issues/issue-21033.rs +++ b/tests/ui/pattern/match-struct-var-having-boxed-field.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass #![allow(unused_mut)] #![allow(unused_variables)] diff --git a/tests/ui/query-system/query-cycle-printing-issue-151358.rs b/tests/ui/query-system/query-cycle-printing-issue-151358.rs index 04d8664420be8..e71d83bc7b786 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151358.rs +++ b/tests/ui/query-system/query-cycle-printing-issue-151358.rs @@ -1,4 +1,5 @@ -//~ ERROR: cycle detected when looking up span for `Default` +//~ ERROR: cycle when printing cycle detected +//~^ ERROR: cycle detected trait Default {} use std::num::NonZero; fn main() { diff --git a/tests/ui/query-system/query-cycle-printing-issue-151358.stderr b/tests/ui/query-system/query-cycle-printing-issue-151358.stderr index 9c1d7b1de33a5..d81b7d142c92f 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151358.stderr +++ b/tests/ui/query-system/query-cycle-printing-issue-151358.stderr @@ -1,9 +1,21 @@ -error[E0391]: cycle detected when looking up span for `Default` +error: internal compiler error: query cycle when printing cycle detected | - = note: ...which immediately requires looking up span for `Default` again - = note: cycle used when perform lints prior to AST lowering + = note: ...when getting HIR ID of `Default` + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which requires looking up span for `Default`... + = note: ...which again requires getting HIR ID of `Default`, completing the cycle + = note: cycle used when getting the resolver for lowering = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error[E0391]: cycle detected when getting the resolver for lowering + | + = note: ...which requires getting HIR ID of `Default`... + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which again requires getting the resolver for lowering, completing the cycle + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/resolve/query-cycle-issue-124901.rs b/tests/ui/resolve/query-cycle-issue-124901.rs index 6cb1e58b6258f..eacbf73755744 100644 --- a/tests/ui/resolve/query-cycle-issue-124901.rs +++ b/tests/ui/resolve/query-cycle-issue-124901.rs @@ -1,4 +1,5 @@ -//~ ERROR: cycle detected when looking up span for `Default` +//~ ERROR: cycle when printing cycle detected +//~^ ERROR: cycle detected trait Default { type Id; diff --git a/tests/ui/resolve/query-cycle-issue-124901.stderr b/tests/ui/resolve/query-cycle-issue-124901.stderr index 9c1d7b1de33a5..d81b7d142c92f 100644 --- a/tests/ui/resolve/query-cycle-issue-124901.stderr +++ b/tests/ui/resolve/query-cycle-issue-124901.stderr @@ -1,9 +1,21 @@ -error[E0391]: cycle detected when looking up span for `Default` +error: internal compiler error: query cycle when printing cycle detected | - = note: ...which immediately requires looking up span for `Default` again - = note: cycle used when perform lints prior to AST lowering + = note: ...when getting HIR ID of `Default` + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which requires looking up span for `Default`... + = note: ...which again requires getting HIR ID of `Default`, completing the cycle + = note: cycle used when getting the resolver for lowering = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error[E0391]: cycle detected when getting the resolver for lowering + | + = note: ...which requires getting HIR ID of `Default`... + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which again requires getting the resolver for lowering, completing the cycle + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/scalable-vectors/transmute.rs b/tests/ui/scalable-vectors/transmute.rs new file mode 100644 index 0000000000000..5995aa7dbb2fe --- /dev/null +++ b/tests/ui/scalable-vectors/transmute.rs @@ -0,0 +1,39 @@ +//@ build-pass +//@ compile-flags: -Copt-level=3 +//@ only-aarch64 +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features, dead_code, improper_ctypes)] +#![allow(nonstandard_style, private_interfaces)] +#![feature(abi_unadjusted, link_llvm_intrinsics, rustc_attrs)] + +// Tests that use of transmute between `svuint8x2_t` and `svint8x2_t` builds with optimisations +// without any failures from LLVM. + +use std::mem::transmute; + +#[rustc_scalable_vector(16)] +struct svbool_t(bool); + +#[rustc_scalable_vector(16)] +struct svuint8_t(u8); + +#[rustc_scalable_vector] +struct svuint8x2_t(svuint8_t, svuint8_t); + +#[rustc_scalable_vector(16)] +struct svint8_t(i8); + +#[rustc_scalable_vector] +struct svint8x2_t(svint8_t, svint8_t); + +#[target_feature(enable = "sve")] +pub unsafe fn svld2_u8(pg: svbool_t, base: *const i8) -> svuint8x2_t { + unsafe extern "unadjusted" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.sve.ld2.sret.nxv16i8" + )] + fn _svld2_s8(pg: svbool_t, base: *const i8) -> svint8x2_t; + } + transmute(_svld2_s8(pg, base)) +}