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/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_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_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_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/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/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/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`.