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..b2c573c23f891 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3901,12 +3901,17 @@ pub struct Delegation {
pub from_glob: bool,
}
+#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
+pub enum DelegationSuffixes {
+ List(ThinVec<(Ident, Option)>),
+ Glob(Span),
+}
+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct DelegationMac {
pub qself: Option>,
pub prefix: Path,
- // Some for list delegation, and None for glob delegation.
- pub suffixes: Option)>>,
+ pub suffixes: DelegationSuffixes,
pub body: Option>,
}
@@ -3918,6 +3923,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/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 6aa8d5f38ad24..ee4b1d1354300 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -430,6 +430,7 @@ macro_rules! common_visitor_and_walkers {
Defaultness,
Delegation,
DelegationMac,
+ DelegationSuffixes,
DelimArgs,
DelimSpan,
EnumDef,
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..cb9bbf014e013 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) => {
@@ -435,7 +444,10 @@ impl<'a> State<'a> {
&item.vis,
&deleg.qself,
&deleg.prefix,
- deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
+ match &deleg.suffixes {
+ ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
+ ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
+ },
&deleg.body,
),
}
@@ -602,6 +614,7 @@ impl<'a> State<'a> {
ast::Safety::Default,
*defaultness,
define_opaque.as_deref(),
+ &[],
);
}
ast::AssocItemKind::Type(box ast::TyAlias {
@@ -641,7 +654,10 @@ impl<'a> State<'a> {
vis,
&deleg.qself,
&deleg.prefix,
- deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
+ match &deleg.suffixes {
+ ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
+ ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
+ },
&deleg.body,
),
}
@@ -703,18 +719,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 +747,20 @@ impl<'a> State<'a> {
}
}
+ fn print_eii_impl(&mut self, eii: &ast::EiiImpl) {
+ self.word("#[");
+ if let Safety::Unsafe(..) = eii.impl_safety {
+ self.word("unsafe");
+ self.popen();
+ }
+ self.print_path(&eii.eii_macro_path, false, 0);
+ if let Safety::Unsafe(..) = eii.impl_safety {
+ self.pclose();
+ }
+ self.word("]");
+ self.hardbreak();
+ }
+
fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) {
if let Some(define_opaque) = define_opaque {
self.word("#[define_opaque(");
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index f0cb348540da1..73b2727fdab0a 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -709,7 +709,8 @@ pub(crate) struct RustcEiiForeignItemParser;
impl NoArgsAttributeParser for RustcEiiForeignItemParser {
const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
- const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
+ const ALLOWED_TARGETS: AllowedTargets =
+ AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs
index def4069f6b477..23db854252a37 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs
@@ -17,6 +17,7 @@ impl AttributeParser for OnConstParser {
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|this, cx, args| {
if !cx.features().diagnostic_on_const() {
+ // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
index 006b3b66658e0..a79b7d6afbcdc 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
@@ -24,6 +24,7 @@ impl OnMoveParser {
mode: Mode,
) {
if !cx.features().diagnostic_on_move() {
+ // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
index bd5eb4cbf82c7..dcfba68a4cf8b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
@@ -18,6 +18,7 @@ impl OnUnknownParser {
mode: Mode,
) {
if !cx.features().diagnostic_on_unknown() {
+ // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}
let span = cx.attr_span;
diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs
index 7b651ed848288..fd0ef8500c6c3 100644
--- a/compiler/rustc_builtin_macros/src/eii.rs
+++ b/compiler/rustc_builtin_macros/src/eii.rs
@@ -1,7 +1,8 @@
use rustc_ast::token::{Delimiter, TokenKind};
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_ast::{
- Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast,
+ Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Mutability, Path, StmtKind,
+ Visibility, ast,
};
use rustc_ast_pretty::pprust::path_to_string;
use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -10,8 +11,9 @@ use thin_vec::{ThinVec, thin_vec};
use crate::errors::{
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
- EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
- EiiSharedMacroInStatementPosition,
+ EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition,
+ EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault,
+ EiiStaticMultipleImplementations, EiiStaticMutable,
};
/// ```rust
@@ -73,44 +75,72 @@ fn eii_(
});
return vec![orig_item];
} else {
- ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
+ ecx.dcx().emit_err(EiiSharedMacroTarget {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![orig_item];
};
- let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
- item.as_ref()
- else {
- ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
- span: eii_attr_span,
- name: path_to_string(&meta_item.path),
- });
- return vec![Annotatable::Item(item)];
+ let ast::Item { attrs, id: _, span: _, vis, kind, tokens: _ } = item.as_ref();
+ let (item_span, foreign_item_name) = match kind {
+ ItemKind::Fn(func) => (func.sig.span, func.ident),
+ ItemKind::Static(stat) => {
+ // Statics with a default are not supported yet
+ if let Some(stat_body) = &stat.expr {
+ ecx.dcx().emit_err(EiiStaticDefault {
+ span: stat_body.span,
+ name: path_to_string(&meta_item.path),
+ });
+ return vec![];
+ }
+ // Statics must have an explicit name for the eii
+ if meta_item.is_word() {
+ ecx.dcx().emit_err(EiiStaticArgumentRequired {
+ span: eii_attr_span,
+ name: path_to_string(&meta_item.path),
+ });
+ return vec![];
+ }
+
+ // Mut statics are currently not supported
+ if stat.mutability == Mutability::Mut {
+ ecx.dcx().emit_err(EiiStaticMutable {
+ span: eii_attr_span,
+ name: path_to_string(&meta_item.path),
+ });
+ }
+
+ (item.span, stat.ident)
+ }
+ _ => {
+ ecx.dcx().emit_err(EiiSharedMacroTarget {
+ span: eii_attr_span,
+ name: path_to_string(&meta_item.path),
+ });
+ return vec![Annotatable::Item(item)];
+ }
};
+
// only clone what we need
let attrs = attrs.clone();
- let func = (**func).clone();
let vis = vis.clone();
let attrs_from_decl =
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
- let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
+ let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else {
// we don't need to wrap in Annotatable::Stmt conditionally since
// EII can't be used on items in statement position
return vec![Annotatable::Item(item)];
};
- // span of the declaring item without attributes
- let item_span = func.sig.span;
- let foreign_item_name = func.ident;
-
let mut module_items = Vec::new();
- if func.body.is_some() {
- module_items.push(generate_default_impl(
+ if let ItemKind::Fn(func) = kind
+ && func.body.is_some()
+ {
+ module_items.push(generate_default_func_impl(
ecx,
&func,
impl_unsafe,
@@ -125,7 +155,7 @@ fn eii_(
ecx,
eii_attr_span,
item_span,
- func,
+ kind,
vis,
&attrs_from_decl,
));
@@ -148,11 +178,11 @@ fn eii_(
/// declaration of the EII.
fn name_for_impl_macro(
ecx: &mut ExtCtxt<'_>,
- func: &ast::Fn,
+ item_ident: Ident,
meta_item: &MetaItem,
) -> Result {
if meta_item.is_word() {
- Ok(func.ident)
+ Ok(item_ident)
} else if let Some([first]) = meta_item.meta_item_list()
&& let Some(m) = first.meta_item()
&& m.path.segments.len() == 1
@@ -190,7 +220,7 @@ fn filter_attrs_for_multiple_eii_attr(
.collect()
}
-fn generate_default_impl(
+fn generate_default_func_impl(
ecx: &mut ExtCtxt<'_>,
func: &ast::Fn,
impl_unsafe: bool,
@@ -257,7 +287,7 @@ fn generate_foreign_item(
ecx: &mut ExtCtxt<'_>,
eii_attr_span: Span,
item_span: Span,
- mut func: ast::Fn,
+ item_kind: &ItemKind,
vis: Visibility,
attrs_from_decl: &[Attribute],
) -> Box {
@@ -268,30 +298,21 @@ fn generate_foreign_item(
// This attribute makes sure that we later know that this foreign item's symbol should not be.
foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span));
- let abi = match func.sig.header.ext {
- // extern "X" fn => extern "X" {}
- ast::Extern::Explicit(lit, _) => Some(lit),
- // extern fn => extern {}
- ast::Extern::Implicit(_) => None,
- // fn => extern "Rust" {}
- ast::Extern::None => Some(ast::StrLit {
- symbol: sym::Rust,
- suffix: None,
- symbol_unescaped: sym::Rust,
- style: ast::StrStyle::Cooked,
- span: eii_attr_span,
- }),
+ // We set the abi to the default "rust" abi, which can be overridden by `generate_foreign_func`,
+ // if a specific abi was specified on the EII function
+ let mut abi = Some(ast::StrLit {
+ symbol: sym::Rust,
+ suffix: None,
+ symbol_unescaped: sym::Rust,
+ style: ast::StrStyle::Cooked,
+ span: eii_attr_span,
+ });
+ let foreign_kind = match item_kind {
+ ItemKind::Fn(func) => generate_foreign_func(func.clone(), &mut abi),
+ ItemKind::Static(stat) => generate_foreign_static(stat.clone()),
+ _ => unreachable!("Target was checked earlier"),
};
- // ABI has been moved to the extern {} block, so we remove it from the fn item.
- func.sig.header.ext = ast::Extern::None;
- func.body = None;
-
- // And mark safe functions explicitly as `safe fn`.
- if func.sig.header.safety == ast::Safety::Default {
- func.sig.header.safety = ast::Safety::Safe(func.sig.span);
- }
-
ecx.item(
eii_attr_span,
ThinVec::new(),
@@ -304,13 +325,46 @@ fn generate_foreign_item(
id: ast::DUMMY_NODE_ID,
span: item_span,
vis,
- kind: ast::ForeignItemKind::Fn(Box::new(func.clone())),
+ kind: foreign_kind,
tokens: None,
})]),
}),
)
}
+fn generate_foreign_func(
+ mut func: Box,
+ abi: &mut Option,
+) -> ast::ForeignItemKind {
+ match func.sig.header.ext {
+ // extern "X" fn => extern "X" {}
+ ast::Extern::Explicit(lit, _) => *abi = Some(lit),
+ // extern fn => extern {}
+ ast::Extern::Implicit(_) => *abi = None,
+ // no abi was specified, so we keep the default
+ ast::Extern::None => {}
+ };
+
+ // ABI has been moved to the extern {} block, so we remove it from the fn item.
+ func.sig.header.ext = ast::Extern::None;
+ func.body = None;
+
+ // And mark safe functions explicitly as `safe fn`.
+ if func.sig.header.safety == ast::Safety::Default {
+ func.sig.header.safety = ast::Safety::Safe(func.sig.span);
+ }
+
+ ast::ForeignItemKind::Fn(func)
+}
+
+fn generate_foreign_static(mut stat: Box) -> ast::ForeignItemKind {
+ if stat.safety == ast::Safety::Default {
+ stat.safety = ast::Safety::Safe(stat.ident.span);
+ }
+
+ ast::ForeignItemKind::Static(stat)
+}
+
/// Generate a stub macro (a bit like in core) that will roughly look like:
///
/// ```rust, ignore, example
@@ -453,19 +507,25 @@ pub(crate) fn eii_shared_macro(
{
item
} else {
- ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
- span,
- name: path_to_string(&meta_item.path),
- });
+ ecx.dcx().emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
return vec![item];
};
- let ItemKind::Fn(f) = &mut i.kind else {
- ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
- span,
- name: path_to_string(&meta_item.path),
- });
- return vec![item];
+ let eii_impls = match &mut i.kind {
+ ItemKind::Fn(func) => &mut func.eii_impls,
+ ItemKind::Static(stat) => {
+ if !stat.eii_impls.is_empty() {
+ // Reject multiple implementations on one static item
+ // because it might be unintuitive for libraries defining statics the defined statics may alias
+ ecx.dcx().emit_err(EiiStaticMultipleImplementations { span });
+ }
+ &mut stat.eii_impls
+ }
+ _ => {
+ ecx.dcx()
+ .emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
+ return vec![item];
+ }
};
let is_default = if meta_item.is_word() {
@@ -483,7 +543,7 @@ pub(crate) fn eii_shared_macro(
return vec![item];
};
- f.eii_impls.push(EiiImpl {
+ eii_impls.push(EiiImpl {
node_id: DUMMY_NODE_ID,
inner_span: meta_item.path.span,
eii_macro_path: meta_item.path.clone(),
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index b5ac84337465a..ad641beb87d98 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -1117,8 +1117,42 @@ pub(crate) struct EiiExternTargetExpectedUnsafe {
}
#[derive(Diagnostic)]
-#[diag("`#[{$name}]` is only valid on functions")]
-pub(crate) struct EiiSharedMacroExpectedFunction {
+#[diag("`#[{$name}]` is only valid on functions and statics")]
+pub(crate) struct EiiSharedMacroTarget {
+ #[primary_span]
+ pub span: Span,
+ pub name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("static cannot implement multiple EIIs")]
+#[note(
+ "this is not allowed because multiple externally implementable statics that alias may be unintuitive"
+)]
+pub(crate) struct EiiStaticMultipleImplementations {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("`#[{$name}]` cannot be used on statics with a value")]
+pub(crate) struct EiiStaticDefault {
+ #[primary_span]
+ pub span: Span,
+ pub name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("`#[{$name}]` requires the name as an explicit argument when used on a static")]
+pub(crate) struct EiiStaticArgumentRequired {
+ #[primary_span]
+ pub span: Span,
+ pub name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("`#[{$name}]` cannot be used on mutable statics")]
+pub(crate) struct EiiStaticMutable {
#[primary_span]
pub span: Span,
pub name: String,
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index caec20db4c2db..8921395ab76ce 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -211,3 +211,32 @@ pub(crate) struct FixedX18InvalidArch<'a> {
"enabling both `-Zpacked-stack` and the `backchain` target feature is incompatible with the default s390x ABI. Switch to s390x-unknown-none-softfloat if you need both attributes"
)]
pub(crate) struct PackedStackBackchainNeedsSoftfloat;
+
+#[derive(Diagnostic)]
+#[diag(
+ "intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`"
+)]
+pub(crate) struct IntrinsicSignatureMismatch<'a> {
+ pub name: &'a str,
+ pub llvm_fn_ty: &'a str,
+ pub rust_fn_ty: &'a str,
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("unknown LLVM intrinsic `{$name}`")]
+pub(crate) struct UnknownIntrinsic<'a> {
+ pub name: &'a str,
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("intrinsic `{$name}` cannot be used with target arch `{$target_arch}`")]
+pub(crate) struct IntrinsicWrongArch<'a> {
+ pub name: &'a str,
+ pub target_arch: &'a str,
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 3e600914d6f42..d46672bdffb7f 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1,6 +1,6 @@
use std::cmp::Ordering;
use std::ffi::c_uint;
-use std::{assert_matches, ptr};
+use std::{assert_matches, iter, ptr};
use rustc_abi::{
Align, BackendRepr, ExternAbi, Float, HasDataLayout, NumScalableVectors, Primitive, Size,
@@ -21,10 +21,11 @@ use rustc_middle::ty::offload_meta::OffloadMetadata;
use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv};
use rustc_middle::{bug, span_bug};
use rustc_session::config::CrateType;
+use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC;
use rustc_span::{Span, Symbol, sym};
use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
use rustc_target::callconv::PassMode;
-use rustc_target::spec::Os;
+use rustc_target::spec::{Arch, Os};
use tracing::debug;
use crate::abi::FnAbiLlvmExt;
@@ -36,7 +37,8 @@ use crate::builder::gpu_offload::{
use crate::context::CodegenCx;
use crate::declare::declare_raw_fn;
use crate::errors::{
- AutoDiffWithoutEnable, AutoDiffWithoutLto, OffloadWithoutEnable, OffloadWithoutFatLTO,
+ AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch,
+ OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic,
};
use crate::llvm::{self, Type, Value};
use crate::type_of::LayoutLlvmExt;
@@ -818,7 +820,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
&mut self,
instance: ty::Instance<'tcx>,
args: &[OperandRef<'tcx, Self::Value>],
- is_cleanup: bool,
+ _is_cleanup: bool,
) -> Self::Value {
let tcx = self.tcx();
@@ -847,42 +849,29 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
llargument_tys.push(arg_layout.immediate_llvm_type(self));
}
- let fn_ty = self.type_func(&llargument_tys, llreturn_ty);
-
let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) {
llfn
} else {
let sym = tcx.symbol_name(instance).name;
- // FIXME use get_intrinsic
let llfn = if let Some(llfn) = self.get_declared_value(sym) {
llfn
} else {
- // Function addresses in Rust are never significant, allowing functions to
- // be merged.
- let llfn = declare_raw_fn(
- self,
- sym,
- llvm::CCallConv,
- llvm::UnnamedAddr::Global,
- llvm::Visibility::Default,
- fn_ty,
- );
-
- llfn
+ intrinsic_fn(self, sym, llreturn_ty, llargument_tys, instance)
};
self.intrinsic_instances.borrow_mut().insert(instance, llfn);
llfn
};
+ let fn_ty = self.get_type_of_global(fn_ptr);
let mut llargs = vec![];
for arg in args {
match arg.val {
OperandValue::ZeroSized => {}
- OperandValue::Immediate(_) => llargs.push(arg.immediate()),
+ OperandValue::Immediate(a) => llargs.push(a),
OperandValue::Pair(a, b) => {
llargs.push(a);
llargs.push(b);
@@ -908,24 +897,38 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
debug!("call intrinsic {:?} with args ({:?})", instance, llargs);
- let args = self.check_call("call", fn_ty, fn_ptr, &llargs);
+
+ for (dest_ty, arg) in iter::zip(self.func_params_types(fn_ty), &mut llargs) {
+ let src_ty = self.val_ty(arg);
+ assert!(
+ can_autocast(self, src_ty, dest_ty),
+ "Cannot match `{dest_ty:?}` (expected) with {src_ty:?} (found) in `{fn_ptr:?}"
+ );
+
+ *arg = autocast(self, arg, src_ty, dest_ty);
+ }
+
let llret = unsafe {
llvm::LLVMBuildCallWithOperandBundles(
self.llbuilder,
fn_ty,
fn_ptr,
- args.as_ptr() as *const &llvm::Value,
- args.len() as c_uint,
+ llargs.as_ptr(),
+ llargs.len() as c_uint,
ptr::dangling(),
0,
c"".as_ptr(),
)
};
- if is_cleanup {
- self.apply_attrs_to_cleanup_callsite(llret);
- }
- llret
+ let src_ty = self.val_ty(llret);
+ let dest_ty = llreturn_ty;
+ assert!(
+ can_autocast(self, dest_ty, src_ty),
+ "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`"
+ );
+
+ autocast(self, llret, src_ty, dest_ty)
}
fn abort(&mut self) {
@@ -976,6 +979,239 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
}
+fn llvm_arch_for(rust_arch: &Arch) -> Option<&'static str> {
+ Some(match rust_arch {
+ Arch::AArch64 | Arch::Arm64EC => "aarch64",
+ Arch::AmdGpu => "amdgcn",
+ Arch::Arm => "arm",
+ Arch::Bpf => "bpf",
+ Arch::Hexagon => "hexagon",
+ Arch::LoongArch32 | Arch::LoongArch64 => "loongarch",
+ Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => "mips",
+ Arch::Nvptx64 => "nvvm",
+ Arch::PowerPC | Arch::PowerPC64 => "ppc",
+ Arch::RiscV32 | Arch::RiscV64 => "riscv",
+ Arch::S390x => "s390",
+ Arch::SpirV => "spv",
+ Arch::Wasm32 | Arch::Wasm64 => "wasm",
+ Arch::X86 | Arch::X86_64 => "x86",
+ _ => return None, // fallback for unknown archs
+ })
+}
+
+fn can_autocast<'ll>(cx: &CodegenCx<'ll, '_>, rust_ty: &'ll Type, llvm_ty: &'ll Type) -> bool {
+ if rust_ty == llvm_ty {
+ return true;
+ }
+
+ match cx.type_kind(llvm_ty) {
+ // Some LLVM intrinsics return **non-packed** structs, but they can't be mimicked from Rust
+ // due to auto field-alignment in non-packed structs (packed structs are represented in LLVM
+ // as, well, packed structs, so they won't match with those either)
+ TypeKind::Struct if cx.type_kind(rust_ty) == TypeKind::Struct => {
+ let rust_element_tys = cx.struct_element_types(rust_ty);
+ let llvm_element_tys = cx.struct_element_types(llvm_ty);
+
+ if rust_element_tys.len() != llvm_element_tys.len() {
+ return false;
+ }
+
+ iter::zip(rust_element_tys, llvm_element_tys).all(
+ |(rust_element_ty, llvm_element_ty)| {
+ can_autocast(cx, rust_element_ty, llvm_element_ty)
+ },
+ )
+ }
+ TypeKind::Vector => {
+ let llvm_element_ty = cx.element_type(llvm_ty);
+ let element_count = cx.vector_length(llvm_ty) as u64;
+
+ if llvm_element_ty == cx.type_bf16() {
+ rust_ty == cx.type_vector(cx.type_i16(), element_count)
+ } else if llvm_element_ty == cx.type_i1() {
+ let int_width = element_count.next_power_of_two().max(8);
+ rust_ty == cx.type_ix(int_width)
+ } else {
+ false
+ }
+ }
+ TypeKind::BFloat => rust_ty == cx.type_i16(),
+ _ => false,
+ }
+}
+
+fn autocast<'ll>(
+ bx: &mut Builder<'_, 'll, '_>,
+ val: &'ll Value,
+ src_ty: &'ll Type,
+ dest_ty: &'ll Type,
+) -> &'ll Value {
+ if src_ty == dest_ty {
+ return val;
+ }
+ match (bx.type_kind(src_ty), bx.type_kind(dest_ty)) {
+ // re-pack structs
+ (TypeKind::Struct, TypeKind::Struct) => {
+ let mut ret = bx.const_poison(dest_ty);
+ for (idx, (src_element_ty, dest_element_ty)) in
+ iter::zip(bx.struct_element_types(src_ty), bx.struct_element_types(dest_ty))
+ .enumerate()
+ {
+ let elt = bx.extract_value(val, idx as u64);
+ let casted_elt = autocast(bx, elt, src_element_ty, dest_element_ty);
+ ret = bx.insert_value(ret, casted_elt, idx as u64);
+ }
+ ret
+ }
+ // cast from the i1xN vector type to the primitive type
+ (TypeKind::Vector, TypeKind::Integer) if bx.element_type(src_ty) == bx.type_i1() => {
+ let vector_length = bx.vector_length(src_ty) as u64;
+ let int_width = vector_length.next_power_of_two().max(8);
+
+ let val = if vector_length == int_width {
+ val
+ } else {
+ // zero-extends vector
+ let shuffle_indices = match vector_length {
+ 0 => unreachable!("zero length vectors are not allowed"),
+ 1 => vec![0, 1, 1, 1, 1, 1, 1, 1],
+ 2 => vec![0, 1, 2, 2, 2, 2, 2, 2],
+ 3 => vec![0, 1, 2, 3, 3, 3, 3, 3],
+ 4.. => (0..int_width as i32).collect(),
+ };
+ let shuffle_mask =
+ shuffle_indices.into_iter().map(|i| bx.const_i32(i)).collect::>();
+ bx.shuffle_vector(val, bx.const_null(src_ty), bx.const_vector(&shuffle_mask))
+ };
+ bx.bitcast(val, dest_ty)
+ }
+ // cast from the primitive type to the i1xN vector type
+ (TypeKind::Integer, TypeKind::Vector) if bx.element_type(dest_ty) == bx.type_i1() => {
+ let vector_length = bx.vector_length(dest_ty) as u64;
+ let int_width = vector_length.next_power_of_two().max(8);
+
+ let intermediate_ty = bx.type_vector(bx.type_i1(), int_width);
+ let intermediate = bx.bitcast(val, intermediate_ty);
+
+ if vector_length == int_width {
+ intermediate
+ } else {
+ let shuffle_mask: Vec<_> =
+ (0..vector_length).map(|i| bx.const_i32(i as i32)).collect();
+ bx.shuffle_vector(
+ intermediate,
+ bx.const_poison(intermediate_ty),
+ bx.const_vector(&shuffle_mask),
+ )
+ }
+ }
+ _ => bx.bitcast(val, dest_ty), // for `bf16(xN)` <-> `u16(xN)`
+ }
+}
+
+fn intrinsic_fn<'ll, 'tcx>(
+ bx: &Builder<'_, 'll, 'tcx>,
+ name: &str,
+ rust_return_ty: &'ll Type,
+ rust_argument_tys: Vec<&'ll Type>,
+ instance: ty::Instance<'tcx>,
+) -> &'ll Value {
+ let tcx = bx.tcx;
+
+ let rust_fn_ty = bx.type_func(&rust_argument_tys, rust_return_ty);
+
+ let intrinsic = llvm::Intrinsic::lookup(name.as_bytes());
+
+ if let Some(intrinsic) = intrinsic
+ && intrinsic.is_target_specific()
+ {
+ let (llvm_arch, _) = name[5..].split_once('.').unwrap();
+ let rust_arch = &tcx.sess.target.arch;
+
+ if let Some(correct_llvm_arch) = llvm_arch_for(rust_arch)
+ && llvm_arch != correct_llvm_arch
+ {
+ tcx.dcx().emit_fatal(IntrinsicWrongArch {
+ name,
+ target_arch: rust_arch.desc(),
+ span: tcx.def_span(instance.def_id()),
+ });
+ }
+ }
+
+ if let Some(intrinsic) = intrinsic
+ && !intrinsic.is_overloaded()
+ {
+ // FIXME: also do this for overloaded intrinsics
+ let llfn = intrinsic.get_declaration(bx.llmod, &[]);
+ let llvm_fn_ty = bx.get_type_of_global(llfn);
+
+ let llvm_return_ty = bx.get_return_type(llvm_fn_ty);
+ let llvm_argument_tys = bx.func_params_types(llvm_fn_ty);
+ let llvm_is_variadic = bx.func_is_variadic(llvm_fn_ty);
+
+ let is_correct_signature = !llvm_is_variadic
+ && rust_argument_tys.len() == llvm_argument_tys.len()
+ && iter::once((rust_return_ty, llvm_return_ty))
+ .chain(iter::zip(rust_argument_tys, llvm_argument_tys))
+ .all(|(rust_ty, llvm_ty)| can_autocast(bx, rust_ty, llvm_ty));
+
+ if !is_correct_signature {
+ tcx.dcx().emit_fatal(IntrinsicSignatureMismatch {
+ name,
+ llvm_fn_ty: &format!("{llvm_fn_ty:?}"),
+ rust_fn_ty: &format!("{rust_fn_ty:?}"),
+ span: tcx.def_span(instance.def_id()),
+ });
+ }
+
+ return llfn;
+ }
+
+ // Function addresses in Rust are never significant, allowing functions to be merged.
+ let llfn = declare_raw_fn(
+ bx,
+ name,
+ llvm::CCallConv,
+ llvm::UnnamedAddr::Global,
+ llvm::Visibility::Default,
+ rust_fn_ty,
+ );
+
+ if intrinsic.is_none() {
+ let mut new_llfn = None;
+ let can_upgrade = unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn) };
+
+ if !can_upgrade {
+ // This is either plain wrong, or this can be caused by incompatible LLVM versions
+ tcx.dcx().emit_fatal(UnknownIntrinsic { name, span: tcx.def_span(instance.def_id()) });
+ } else if let Some(def_id) = instance.def_id().as_local() {
+ // we can emit diagnostics only for local crates
+ let hir_id = tcx.local_def_id_to_hir_id(def_id);
+
+ // not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
+ let msg = if let Some(new_llfn) = new_llfn {
+ format!(
+ "using deprecated intrinsic `{name}`, `{}` can be used instead",
+ str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
+ )
+ } else {
+ format!("using deprecated intrinsic `{name}`")
+ };
+
+ tcx.emit_node_lint(
+ DEPRECATED_LLVM_INTRINSIC,
+ hir_id,
+ rustc_errors::DiagDecorator(|d| {
+ d.primary_message(msg).span(tcx.hir_span(hir_id));
+ }),
+ );
+ }
+ }
+
+ llfn
+}
+
fn catch_unwind_intrinsic<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
try_func: &'ll Value,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 67fbc0f53adc9..195e050a9b651 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -73,7 +73,6 @@ unsafe extern "C" {
pub(crate) fn LLVMDumpModule(M: &Module);
pub(crate) fn LLVMDumpValue(V: &Value);
pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
- pub(crate) fn LLVMGetReturnType(T: &Type) -> &Type;
pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value);
pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index bc24f1692fcf2..525d1dbe9d0d3 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -921,6 +921,9 @@ unsafe extern "C" {
pub(crate) fn LLVMDoubleTypeInContext(C: &Context) -> &Type;
pub(crate) fn LLVMFP128TypeInContext(C: &Context) -> &Type;
+ // Operations on non-IEEE real types
+ pub(crate) fn LLVMBFloatTypeInContext(C: &Context) -> &Type;
+
// Operations on function types
pub(crate) fn LLVMFunctionType<'a>(
ReturnType: &'a Type,
@@ -930,6 +933,8 @@ unsafe extern "C" {
) -> &'a Type;
pub(crate) fn LLVMCountParamTypes(FunctionTy: &Type) -> c_uint;
pub(crate) fn LLVMGetParamTypes<'a>(FunctionTy: &'a Type, Dest: *mut &'a Type);
+ pub(crate) fn LLVMGetReturnType(FunctionTy: &Type) -> &Type;
+ pub(crate) fn LLVMIsFunctionVarArg(FunctionTy: &Type) -> Bool;
// Operations on struct types
pub(crate) fn LLVMStructTypeInContext<'a>(
@@ -1084,12 +1089,18 @@ unsafe extern "C" {
// Operations about llvm intrinsics
pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint;
+ pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero) -> Bool;
pub(crate) fn LLVMGetIntrinsicDeclaration<'a>(
Mod: &'a Module,
ID: NonZero,
ParamTypes: *const &'a Type,
ParamCount: size_t,
) -> &'a Value;
+ pub(crate) fn LLVMRustUpgradeIntrinsicFunction<'a>(
+ Fn: &'a Value,
+ NewFn: &mut Option<&'a Value>,
+ ) -> bool;
+ pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero) -> bool;
// Operations on parameters
pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>;
@@ -1605,6 +1616,9 @@ unsafe extern "C" {
Packed: Bool,
);
+ pub(crate) fn LLVMCountStructElementTypes(StructTy: &Type) -> c_uint;
+ pub(crate) fn LLVMGetStructElementTypes<'a>(StructTy: &'a Type, Dest: *mut &'a Type);
+
pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 2871326b28b5a..2ec19b1795b5a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -323,6 +323,14 @@ impl Intrinsic {
NonZero::new(id).map(|id| Self { id })
}
+ pub(crate) fn is_overloaded(self) -> bool {
+ unsafe { LLVMIntrinsicIsOverloaded(self.id).is_true() }
+ }
+
+ pub(crate) fn is_target_specific(self) -> bool {
+ unsafe { LLVMRustIsTargetIntrinsic(self.id) }
+ }
+
pub(crate) fn get_declaration<'ll>(
self,
llmod: &'ll Module,
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 0783282bc6e56..2c0a6ff01018c 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -135,7 +135,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
let ty = self.get_type_of_global(aliasee);
for (alias, linkage, visibility) in aliases {
- let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias));
+ let instance = Instance::mono(self.tcx, *alias);
+ let symbol_name = self.tcx.symbol_name(instance);
tracing::debug!("STATIC ALIAS: {alias:?} {linkage:?} {visibility:?}");
let lldecl = llvm::add_alias(
@@ -145,6 +146,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
aliasee,
&CString::new(symbol_name.name).unwrap(),
);
+ // Add the alias name to the set of cached items, so there is no duplicate
+ // instance added to it during the normal `external static` codegen
+ let prev_entry = self.instances.borrow_mut().insert(instance, lldecl);
+
+ // If there already was a previous entry, then `add_static_aliases` was called multiple times for the same `alias`
+ // which would result in incorrect codegen
+ assert!(prev_entry.is_none(), "An instance was already present for {instance:?}");
llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage));
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 2026b06d104df..796f3d9ef60ba 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -77,6 +77,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> {
unsafe { llvm::LLVMAddFunction(self.llmod(), name.as_ptr(), ty) }
}
+ pub(crate) fn get_return_type(&self, ty: &'ll Type) -> &'ll Type {
+ unsafe { llvm::LLVMGetReturnType(ty) }
+ }
+
pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
unsafe {
let n_args = llvm::LLVMCountParamTypes(ty) as usize;
@@ -86,6 +90,20 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> {
args
}
}
+
+ pub(crate) fn func_is_variadic(&self, ty: &'ll Type) -> bool {
+ unsafe { llvm::LLVMIsFunctionVarArg(ty).is_true() }
+ }
+
+ pub(crate) fn struct_element_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
+ unsafe {
+ let n_args = llvm::LLVMCountStructElementTypes(ty) as usize;
+ let mut args = Vec::with_capacity(n_args);
+ llvm::LLVMGetStructElementTypes(ty, args.as_mut_ptr());
+ args.set_len(n_args);
+ args
+ }
+ }
}
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
pub(crate) fn type_bool(&self) -> &'ll Type {
@@ -165,6 +183,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> {
)
}
}
+
+ pub(crate) fn type_bf16(&self) -> &'ll Type {
+ unsafe { llvm::LLVMBFloatTypeInContext(self.llcx()) }
+ }
}
impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> {
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 7fd891395fa02..fd685f534da18 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1019,18 +1019,24 @@ impl SyntaxExtension {
pub fn glob_delegation(
trait_def_id: DefId,
impl_def_id: LocalDefId,
+ star_span: Span,
edition: Edition,
) -> SyntaxExtension {
struct GlobDelegationExpanderImpl {
trait_def_id: DefId,
impl_def_id: LocalDefId,
+ star_span: Span,
}
impl GlobDelegationExpander for GlobDelegationExpanderImpl {
fn expand(
&self,
ecx: &mut ExtCtxt<'_>,
) -> ExpandResult)>, ()> {
- match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) {
+ match ecx.resolver.glob_delegation_suffixes(
+ self.trait_def_id,
+ self.impl_def_id,
+ self.star_span,
+ ) {
Ok(suffixes) => ExpandResult::Ready(suffixes),
Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()),
Err(Indeterminate) => ExpandResult::Retry(()),
@@ -1038,7 +1044,7 @@ impl SyntaxExtension {
}
}
- let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id };
+ let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id, star_span };
SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Arc::new(expander)), edition)
}
@@ -1170,6 +1176,7 @@ pub trait ResolverExpand {
&self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
+ star_span: Span,
) -> Result)>, Indeterminate>;
/// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used
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_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 9f5a01452fdc3..92efab3212ab3 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -8,9 +8,9 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
use rustc_ast::{
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec,
- DUMMY_NODE_ID, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline,
- ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind,
- TyKind, token,
+ DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs,
+ HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId,
+ PatKind, StmtKind, TyKind, token,
};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::parser::AllowExprMetavar;
@@ -2401,7 +2401,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
res
}
None if let Some((deleg, item)) = node.delegation() => {
- let Some(suffixes) = &deleg.suffixes else {
+ let DelegationSuffixes::List(suffixes) = &deleg.suffixes else {
let traitless_qself =
matches!(&deleg.qself, Some(qself) if qself.position == 0);
let (item, of_trait) = match node.to_annotatable() {
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_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 4aff294aeac61..8af8f40d69f56 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -37,6 +37,7 @@ declare_lint_pass! {
DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK,
DEPRECATED,
DEPRECATED_IN_FUTURE,
+ DEPRECATED_LLVM_INTRINSIC,
DEPRECATED_SAFE_2024,
DEPRECATED_WHERE_CLAUSE_LOCATION,
DUPLICATE_FEATURES,
@@ -5597,3 +5598,48 @@ declare_lint! {
report_in_deps: false,
};
}
+
+declare_lint! {
+ /// The `deprecated_llvm_intrinsic` lint detects usage of deprecated LLVM intrinsics.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (requires x86)
+ /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ /// #![feature(link_llvm_intrinsics, abi_unadjusted)]
+ /// #![deny(deprecated_llvm_intrinsic)]
+ ///
+ /// unsafe extern "unadjusted" {
+ /// #[link_name = "llvm.x86.addcarryx.u32"]
+ /// fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8;
+ /// }
+ ///
+ /// #[inline(never)]
+ /// #[target_feature(enable = "adx")]
+ /// pub fn bar(a: u8, b: u32, c: u32, d: &mut u32) -> u8 {
+ /// unsafe { foo(a, b, c, d) }
+ /// }
+ /// ```
+ ///
+ /// This will produce:
+ ///
+ /// ```text
+ /// error: Using deprecated intrinsic `llvm.x86.addcarryx.u32`
+ /// --> example.rs:7:5
+ /// |
+ /// 7 | fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8;
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ /// |
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// LLVM periodically updates its list of intrinsics. Deprecated intrinsics are unlikely
+ /// to be removed, but they may optimize less well than their new versions, so it's
+ /// best to use the new version. Also, some deprecated intrinsics might have buggy
+ /// behavior
+ pub DEPRECATED_LLVM_INTRINSIC,
+ Allow,
+ "detects uses of deprecated LLVM intrinsics",
+ @feature_gate = link_llvm_intrinsics;
+}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index f7fccf6296bd1..c310e580af559 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -9,6 +9,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DiagnosticHandler.h"
@@ -1815,6 +1816,19 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
GV.setSanitizerMetadata(MD);
}
+extern "C" bool LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn,
+ LLVMValueRef *NewFn) {
+ Function *F = unwrap(Fn);
+ Function *NewF = nullptr;
+ bool CanUpgrade = UpgradeIntrinsicFunction(F, NewF, false);
+ *NewFn = wrap(NewF);
+ return CanUpgrade;
+}
+
+extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
+ return Intrinsic::isTargetIntrinsic(ID);
+}
+
// Statically assert that the fixed metadata kind IDs declared in
// `metadata_kind.rs` match the ones actually used by LLVM.
#define FIXED_MD_KIND(VARIANT, VALUE) \
diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs
index 1017ccffb0b2a..d3b1345e93701 100644
--- a/compiler/rustc_middle/src/queries.rs
+++ b/compiler/rustc_middle/src/queries.rs
@@ -1202,7 +1202,7 @@ rustc_queries! {
/// Return the live symbols in the crate for dead code check.
///
/// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone).
- query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx Result<(
+ query live_symbols_and_ignored_derived_traits(_: ()) -> Result<&'tcx (
LocalDefIdSet,
LocalDefIdMap>,
), ErrorGuaranteed> {
@@ -1292,7 +1292,7 @@ rustc_queries! {
/// Return the set of (transitive) callees that may result in a recursive call to `key`,
/// if we were able to walk all callees.
- query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx Option> {
+ query mir_callgraph_cyclic(key: LocalDefId) -> Option<&'tcx UnordSet> {
arena_cache
desc {
"computing (transitive) callees of `{}` that may recurse",
diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs
index 7c7ad12622604..4ab2fbe914965 100644
--- a/compiler/rustc_middle/src/query/arena_cached.rs
+++ b/compiler/rustc_middle/src/query/arena_cached.rs
@@ -1,6 +1,7 @@
use std::mem;
use rustc_arena::TypedArena;
+use rustc_span::ErrorGuaranteed;
use crate::ty::TyCtxt;
@@ -51,6 +52,21 @@ impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> {
}
}
+impl<'tcx, T> ArenaCached<'tcx> for Result<&'tcx T, ErrorGuaranteed> {
+ type Provided = Result;
+ /// The provide value is `Result`, but we only store `T` in the arena.
+ type Allocated = T;
+
+ fn alloc_in_arena(
+ tcx: TyCtxt<'tcx>,
+ typed_arena: &'tcx TypedArena,
+ value: Result,
+ ) -> Self {
+ // Don't store Err(ErrorGuaranteed) in the arena, and wrap the allocated reference in Ok.
+ try { do_alloc(tcx, typed_arena, value?) }
+ }
+}
+
/// Allocates a value in either its dedicated arena, or in the common dropless
/// arena, depending on whether it needs to be dropped.
fn do_alloc<'tcx, T>(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena, value: T) -> &'tcx T {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index ab3683f598208..ccfc9438f1ccf 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -857,7 +857,7 @@ impl<'a> Parser<'a> {
kind: AssocItemKind::DelegationMac(Box::new(DelegationMac {
qself: None,
prefix: of_trait.trait_ref.path.clone(),
- suffixes: None,
+ suffixes: DelegationSuffixes::Glob(whole_reuse_span),
body,
})),
}));
@@ -879,10 +879,12 @@ impl<'a> Parser<'a> {
Ok(if self.eat_path_sep() {
let suffixes = if self.eat(exp!(Star)) {
- None
+ DelegationSuffixes::Glob(self.prev_token.span)
} else {
let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));
- Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0)
+ DelegationSuffixes::List(
+ self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0,
+ )
};
ItemKind::DelegationMac(Box::new(DelegationMac {
@@ -1235,6 +1237,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 +1506,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"),
@@ -1517,7 +1521,10 @@ impl<'a> Parser<'a> {
let span = self.psess.source_map().guess_head_span(span);
let descr = kind.descr();
let help = match kind {
- ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => false,
+ ItemKind::DelegationMac(box DelegationMac {
+ suffixes: DelegationSuffixes::Glob(_),
+ ..
+ }) => false,
_ => true,
};
self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help });
@@ -1636,7 +1643,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..25ef573447c12 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 {
@@ -3873,8 +3872,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
let Some(body) = &delegation.body else { return };
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
- let span = delegation.path.segments.last().unwrap().ident.span;
- let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules());
+ let ident = Ident::new(kw::SelfLower, body.span.normalize_to_macro_rules());
let res = Res::Local(delegation.id);
this.innermost_rib_bindings(ValueNS).insert(ident, res);
@@ -5496,6 +5494,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..f0e757b2d673d 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -4,7 +4,7 @@
use std::mem;
use std::sync::Arc;
-use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, NodeId};
+use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, DelegationSuffixes, NodeId};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
@@ -286,7 +286,8 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive),
InvocationKind::GlobDelegation { ref item, .. } => {
let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
- deleg_impl = Some(self.invocation_parent(invoc_id));
+ let DelegationSuffixes::Glob(star_span) = deleg.suffixes else { unreachable!() };
+ deleg_impl = Some((self.invocation_parent(invoc_id), star_span));
// It is sufficient to consider glob delegation a bang macro for now.
(&deleg.prefix, MacroKind::Bang)
}
@@ -530,6 +531,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
&self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
+ star_span: Span,
) -> Result)>, Indeterminate> {
let target_trait = self.expect_module(trait_def_id);
if !target_trait.unexpanded_invocations.borrow().is_empty() {
@@ -549,13 +551,13 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
let mut idents = Vec::new();
target_trait.for_each_child(self, |this, ident, orig_ident_span, ns, _binding| {
- // FIXME: Adjust hygiene for idents from globs, like for glob imports.
if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id)
&& overriding_keys.contains(&BindingKey::new(ident, ns))
{
// The name is overridden, do not produce it from the glob delegation.
} else {
- idents.push((ident.orig(orig_ident_span), None));
+ // FIXME: Adjust hygiene for idents from globs, like for glob imports.
+ idents.push((ident.orig(star_span.with_ctxt(orig_ident_span.ctxt())), None));
}
});
Ok(idents)
@@ -579,7 +581,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
parent_scope: &ParentScope<'ra>,
node_id: NodeId,
force: bool,
- deleg_impl: Option,
+ deleg_impl: Option<(LocalDefId, Span)>,
invoc_in_mod_inert_attr: Option,
suggestion_span: Option,
) -> Result<(Arc, Res), Indeterminate> {
@@ -712,34 +714,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 },
);
}
@@ -771,7 +794,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
kind: MacroKind,
parent_scope: &ParentScope<'ra>,
force: bool,
- deleg_impl: Option,
+ deleg_impl: Option<(LocalDefId, Span)>,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
ignore_import: Option>,
suggestion_span: Option,
@@ -856,10 +879,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let res = res?;
let ext = match deleg_impl {
- Some(impl_def_id) => match res {
+ Some((impl_def_id, star_span)) => match res {
def::Res::Def(DefKind::Trait, def_id) => {
let edition = self.tcx.sess.edition();
- Some(Arc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition)))
+ Some(Arc::new(SyntaxExtension::glob_delegation(
+ def_id,
+ impl_def_id,
+ star_span,
+ edition,
+ )))
}
_ => None,
},
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index ae559e599f481..9d350166c681b 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -346,7 +346,8 @@ impl T> DerefMut for LazyCell {
}
#[stable(feature = "lazy_cell", since = "1.80.0")]
-impl Default for LazyCell {
+#[rustc_const_unstable(feature = "const_default", issue = "143894")]
+impl const Default for LazyCell {
/// Creates a new lazy value using `Default` as the initializing function.
#[inline]
fn default() -> LazyCell {
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 37562da3cd6b4..1b1489261f62f 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -213,14 +213,13 @@ macro_rules! int_impl {
/// # Examples
///
/// ```
- /// #![feature(int_lowest_highest_one)]
- ///
#[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".highest_one(), None);")]
#[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".highest_one(), Some(0));")]
#[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".highest_one(), Some(4));")]
#[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".highest_one(), Some(4));")]
/// ```
- #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+ #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@@ -234,14 +233,13 @@ macro_rules! int_impl {
/// # Examples
///
/// ```
- /// #![feature(int_lowest_highest_one)]
- ///
#[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".lowest_one(), None);")]
#[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".lowest_one(), Some(0));")]
#[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".lowest_one(), Some(4));")]
#[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".lowest_one(), Some(0));")]
/// ```
- #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+ #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index e2c552e78d6b6..9a330fe592230 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -711,8 +711,6 @@ macro_rules! nonzero_integer {
/// # Examples
///
/// ```
- /// #![feature(int_lowest_highest_one)]
- ///
/// # use core::num::NonZero;
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -722,7 +720,8 @@ macro_rules! nonzero_integer {
/// # Some(())
/// # }
/// ```
- #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+ #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@@ -735,8 +734,6 @@ macro_rules! nonzero_integer {
/// # Examples
///
/// ```
- /// #![feature(int_lowest_highest_one)]
- ///
/// # use core::num::NonZero;
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
@@ -746,7 +743,8 @@ macro_rules! nonzero_integer {
/// # Some(())
/// # }
/// ```
- #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+ #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@@ -1948,8 +1946,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
/// # Examples
///
/// ```
- /// #![feature(uint_bit_width)]
- ///
/// # use core::num::NonZero;
/// #
/// # fn main() { test().unwrap(); }
@@ -1960,7 +1956,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
/// # Some(())
/// # }
/// ```
- #[unstable(feature = "uint_bit_width", issue = "142326")]
+ #[stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index fd43ca742aefb..b925400e19227 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -232,14 +232,13 @@ macro_rules! uint_impl {
/// # Examples
///
/// ```
- /// #![feature(uint_bit_width)]
- ///
#[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".bit_width(), 0);")]
#[doc = concat!("assert_eq!(0b111_", stringify!($SelfT), ".bit_width(), 3);")]
#[doc = concat!("assert_eq!(0b1110_", stringify!($SelfT), ".bit_width(), 4);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.bit_width(), ", stringify!($BITS), ");")]
/// ```
- #[unstable(feature = "uint_bit_width", issue = "142326")]
+ #[stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "uint_bit_width", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@@ -293,14 +292,13 @@ macro_rules! uint_impl {
/// # Examples
///
/// ```
- /// #![feature(int_lowest_highest_one)]
- ///
#[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".highest_one(), None);")]
#[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".highest_one(), Some(0));")]
#[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".highest_one(), Some(4));")]
#[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".highest_one(), Some(4));")]
/// ```
- #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+ #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@@ -317,14 +315,13 @@ macro_rules! uint_impl {
/// # Examples
///
/// ```
- /// #![feature(int_lowest_highest_one)]
- ///
#[doc = concat!("assert_eq!(0b0_", stringify!($SelfT), ".lowest_one(), None);")]
#[doc = concat!("assert_eq!(0b1_", stringify!($SelfT), ".lowest_one(), Some(0));")]
#[doc = concat!("assert_eq!(0b1_0000_", stringify!($SelfT), ".lowest_one(), Some(4));")]
#[doc = concat!("assert_eq!(0b1_1111_", stringify!($SelfT), ".lowest_one(), Some(0));")]
/// ```
- #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+ #[stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_lowest_highest_one", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 305861ea7b698..e46204c6246ab 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -293,6 +293,7 @@ impl const DerefMut for &mut T {
/// unchanged.
#[unstable(feature = "deref_pure_trait", issue = "87121")]
#[lang = "deref_pure"]
+#[rustc_dyn_incompatible_trait]
pub unsafe trait DerefPure: PointeeSized {}
#[unstable(feature = "deref_pure_trait", issue = "87121")]
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index c709b6c432e52..019a2dfaa4476 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -66,7 +66,6 @@
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]
#![feature(int_from_ascii)]
-#![feature(int_lowest_highest_one)]
#![feature(int_roundings)]
#![feature(ip)]
#![feature(is_ascii_octdigit)]
@@ -120,7 +119,6 @@
#![feature(try_find)]
#![feature(try_trait_v2)]
#![feature(type_info)]
-#![feature(uint_bit_width)]
#![feature(uint_carryless_mul)]
#![feature(uint_gather_scatter_bits)]
#![feature(unicode_internals)]
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 9bdde0ae4a537..de1b9c391e8f2 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -375,7 +375,8 @@ impl T> DerefMut for LazyLock {
}
#[stable(feature = "lazy_cell", since = "1.80.0")]
-impl Default for LazyLock {
+#[rustc_const_unstable(feature = "const_default", issue = "143894")]
+impl const Default for LazyLock {
/// Creates a new lazy value using `Default` as the initializing function.
#[inline]
fn default() -> LazyLock {
diff --git a/library/std/tests/sync/lazy_lock.rs b/library/std/tests/sync/lazy_lock.rs
index 68aeea834b4fa..c549094dd1381 100644
--- a/library/std/tests/sync/lazy_lock.rs
+++ b/library/std/tests/sync/lazy_lock.rs
@@ -33,6 +33,15 @@ fn lazy_default() {
assert_eq!(CALLED.load(SeqCst), 1);
}
+#[test]
+fn const_lazy_default() {
+ // using Box as it cannot be initialized in const contexts
+ const X: LazyLock> = <_>::default();
+ const Y: LazyCell> = <_>::default();
+ assert_eq!(**X, 0);
+ assert_eq!(**Y, 0);
+}
+
#[test]
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
fn sync_lazy_new() {
diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs
index 32a7efde2a257..92c4c2f511be3 100644
--- a/library/std/tests/sync/lib.rs
+++ b/library/std/tests/sync/lib.rs
@@ -1,3 +1,5 @@
+#![feature(const_default)]
+#![feature(const_trait_impl)]
#![feature(mapped_lock_guards)]
#![feature(mpmc_channel)]
#![feature(oneshot_channel)]
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index c222aa2305647..991592ec522d0 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2334,6 +2334,10 @@ Please disable assertions with `rust.debug-assertions = false`.
cmd.arg("--verbose");
}
+ if builder.config.cmd.verbose_run_make_subprocess_output() {
+ cmd.arg("--verbose-run-make-subprocess-output");
+ }
+
if builder.config.rustc_debug_assertions {
cmd.arg("--with-rustc-debug-assertions");
}
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 2f1e234d6ebc0..e1b8aa9810c3d 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -422,6 +422,10 @@ pub enum Subcommand {
#[arg(long)]
/// don't capture stdout/stderr of tests
no_capture: bool,
+ #[arg(long, default_value_t = true, action = clap::ArgAction::Set, default_missing_value = "true", num_args = 0..=1, require_equals = true)]
+ /// whether to show verbose subprocess output for run-make tests;
+ /// set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)
+ verbose_run_make_subprocess_output: bool,
#[arg(long)]
/// Use a different codegen backend when running tests.
test_codegen_backend: Option,
@@ -631,6 +635,15 @@ impl Subcommand {
}
}
+ pub fn verbose_run_make_subprocess_output(&self) -> bool {
+ match *self {
+ Subcommand::Test { verbose_run_make_subprocess_output, .. } => {
+ verbose_run_make_subprocess_output
+ }
+ _ => true,
+ }
+ }
+
pub fn rustfix_coverage(&self) -> bool {
match *self {
Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 3ae2373e1da21..331403f959b4c 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -621,4 +621,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
severity: ChangeSeverity::Info,
summary: "`x.py` stopped accepting partial argument names. Use full names to avoid errors.",
},
+ ChangeInfo {
+ change_id: 154587,
+ severity: ChangeSeverity::Info,
+ summary: "New `--verbose-run-make-subprocess-output` flag for `x.py test` (defaults to true). Set `--verbose-run-make-subprocess-output=false` to suppress verbose subprocess output for passing run-make tests when using `--no-capture`.",
+ },
];
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index 83fcfecc1de7b..e19c7a8d4e44f 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -460,6 +460,15 @@ However, revisions or building auxiliary via directives are not currently suppor
`rmake.rs` and `run-make-support` may *not* use any nightly/unstable features,
as they must be compilable by a stage 0 rustc that may be a beta or even stable rustc.
+By default, run-make tests print each subprocess command and its stdout/stderr.
+When running with `--no-capture` on `panic=abort` test suites (such as `cg_clif`),
+this can flood the terminal. Omit `--verbose-run-make-subprocess-output` to
+suppress this output for passing tests — failing tests always print regardless:
+
+```bash
+./x test tests/run-make --no-capture --verbose-run-make-subprocess-output=false
+```
+
#### Quickly check if `rmake.rs` tests can be compiled
You can quickly check if `rmake.rs` tests can be compiled without having to
diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish
index 92af4f04dcba9..689a13452e1bc 100644
--- a/src/etc/completions/x.fish
+++ b/src/etc/completions/x.fish
@@ -420,6 +420,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l extra-checks -d 'comma-sepa
complete -c x -n "__fish_x_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
+complete -c x -n "__fish_x_using_subcommand test" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
complete -c x -n "__fish_x_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
complete -c x -n "__fish_x_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
complete -c x -n "__fish_x_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
@@ -473,6 +474,7 @@ complete -c x -n "__fish_x_using_subcommand t" -l extra-checks -d 'comma-separat
complete -c x -n "__fish_x_using_subcommand t" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
complete -c x -n "__fish_x_using_subcommand t" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
complete -c x -n "__fish_x_using_subcommand t" -l run -d 'whether to execute run-* tests' -r
+complete -c x -n "__fish_x_using_subcommand t" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
complete -c x -n "__fish_x_using_subcommand t" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
complete -c x -n "__fish_x_using_subcommand t" -l config -d 'TOML configuration file for build' -r -F
complete -c x -n "__fish_x_using_subcommand t" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1
index d4bf45f738365..e99ef27c2abca 100644
--- a/src/etc/completions/x.ps1
+++ b/src/etc/completions/x.ps1
@@ -487,6 +487,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
[CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
[CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
[CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+ [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
[CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
[CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
[CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
@@ -547,6 +548,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
[CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
[CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
[CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+ [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
[CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
[CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
[CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 0dbbe1ea43efd..a852df8a7753e 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -420,6 +420,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l extra-checks -d 'comm
complete -c x.py -n "__fish_x.py_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
+complete -c x.py -n "__fish_x.py_using_subcommand test" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
complete -c x.py -n "__fish_x.py_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
complete -c x.py -n "__fish_x.py_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
@@ -473,6 +474,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand t" -l extra-checks -d 'comma-s
complete -c x.py -n "__fish_x.py_using_subcommand t" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
complete -c x.py -n "__fish_x.py_using_subcommand t" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
complete -c x.py -n "__fish_x.py_using_subcommand t" -l run -d 'whether to execute run-* tests' -r
+complete -c x.py -n "__fish_x.py_using_subcommand t" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
complete -c x.py -n "__fish_x.py_using_subcommand t" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
complete -c x.py -n "__fish_x.py_using_subcommand t" -l config -d 'TOML configuration file for build' -r -F
complete -c x.py -n "__fish_x.py_using_subcommand t" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index b4e3b8c580a49..665cb812f2df9 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -487,6 +487,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
[CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
[CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
[CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+ [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
[CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
[CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
[CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
@@ -547,6 +548,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
[CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
[CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
[CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+ [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
[CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
[CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
[CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index 8a7aee2a091c7..5e6db9bcb5325 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -4638,7 +4638,7 @@ _x.py() {
return 0
;;
x.py__test)
- opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+ opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -4668,6 +4668,10 @@ _x.py() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
+ --verbose-run-make-subprocess-output)
+ COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+ return 0
+ ;;
--test-codegen-backend)
COMPREPLY=($(compgen -f "${cur}"))
return 0
@@ -4852,7 +4856,7 @@ _x.py() {
return 0
;;
x.py__test)
- opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+ opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -4882,6 +4886,10 @@ _x.py() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
+ --verbose-run-make-subprocess-output)
+ COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+ return 0
+ ;;
--test-codegen-backend)
COMPREPLY=($(compgen -f "${cur}"))
return 0
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index e24da218a05d8..1f8701c297baa 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -488,6 +488,7 @@ _arguments "${_arguments_options[@]}" : \
'--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
'--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
'--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
'--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
'--config=[TOML configuration file for build]:FILE:_files' \
'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
@@ -550,6 +551,7 @@ _arguments "${_arguments_options[@]}" : \
'--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
'--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
'--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
'--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
'--config=[TOML configuration file for build]:FILE:_files' \
'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh
index a4b44b73f47af..6314fe1307dcb 100644
--- a/src/etc/completions/x.sh
+++ b/src/etc/completions/x.sh
@@ -4638,7 +4638,7 @@ _x() {
return 0
;;
x__test)
- opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+ opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -4668,6 +4668,10 @@ _x() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
+ --verbose-run-make-subprocess-output)
+ COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+ return 0
+ ;;
--test-codegen-backend)
COMPREPLY=($(compgen -f "${cur}"))
return 0
@@ -4852,7 +4856,7 @@ _x() {
return 0
;;
x__test)
- opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+ opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -4882,6 +4886,10 @@ _x() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
+ --verbose-run-make-subprocess-output)
+ COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+ return 0
+ ;;
--test-codegen-backend)
COMPREPLY=($(compgen -f "${cur}"))
return 0
diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh
index 7f43781684b4b..12f441012e60f 100644
--- a/src/etc/completions/x.zsh
+++ b/src/etc/completions/x.zsh
@@ -488,6 +488,7 @@ _arguments "${_arguments_options[@]}" : \
'--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
'--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
'--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
'--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
'--config=[TOML configuration file for build]:FILE:_files' \
'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
@@ -550,6 +551,7 @@ _arguments "${_arguments_options[@]}" : \
'--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
'--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
'--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
'--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
'--config=[TOML configuration file for build]:FILE:_files' \
'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index cfff7da60a6a4..c96c0649753fd 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -339,6 +339,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
expr: le,
safety: ls,
define_opaque: _,
+ eii_impls: _,
}),
Static(box StaticItem {
ident: ri,
@@ -347,6 +348,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
expr: re,
safety: rs,
define_opaque: _,
+ eii_impls: _,
}),
) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()),
(
@@ -540,6 +542,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
expr: le,
safety: ls,
define_opaque: _,
+ eii_impls: _,
}),
Static(box StaticItem {
ident: ri,
@@ -548,6 +551,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
expr: re,
safety: rs,
define_opaque: _,
+ eii_impls: _,
}),
) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs,
(
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index c167580d99d9a..f73d7c96f7e85 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -603,6 +603,10 @@ pub(crate) struct Config {
/// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump.
pub(crate) verbose: bool,
+ /// Whether to enable verbose subprocess output for run-make tests.
+ /// Set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture).
+ pub verbose_run_make_subprocess_output: bool,
+
/// Where to find the remote test client process, if we're using it.
///
/// Note: this is *only* used for target platform executables created by `run-make` test
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index a23e3bb9a90e4..dcea79b18e6a8 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -134,6 +134,11 @@ fn parse_config(args: Vec) -> Config {
)
.optflag("", "optimize-tests", "run tests with optimizations enabled")
.optflag("", "verbose", "run tests verbosely, showing all output")
+ .optflag(
+ "",
+ "verbose-run-make-subprocess-output",
+ "show verbose subprocess output for successful run-make tests",
+ )
.optflag(
"",
"bless",
@@ -471,6 +476,8 @@ fn parse_config(args: Vec) -> Config {
adb_test_dir,
adb_device_status,
verbose: matches.opt_present("verbose"),
+ verbose_run_make_subprocess_output: matches
+ .opt_present("verbose-run-make-subprocess-output"),
only_modified: matches.opt_present("only-modified"),
remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from),
compare_mode,
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index ac8846a263c0d..1044683ae6426 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -231,6 +231,13 @@ impl TestCx<'_> {
}
// Guard against externally-set env vars.
+ // Set env var to enable verbose output for successful commands.
+ // Only set when --verbose-run-make-subprocess-output is passed.
+ cmd.env_remove("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT");
+ if self.config.verbose_run_make_subprocess_output {
+ cmd.env("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT", "1");
+ }
+
cmd.env_remove("__RUSTC_DEBUG_ASSERTIONS_ENABLED");
if self.config.with_rustc_debug_assertions {
// Used for `run_make_support::env::rustc_debug_assertions_enabled`.
diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs
index c71fd714aa660..57ce0c5a6d5f7 100644
--- a/src/tools/compiletest/src/rustdoc_gui_test.rs
+++ b/src/tools/compiletest/src/rustdoc_gui_test.rs
@@ -109,6 +109,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config {
adb_test_dir: Default::default(),
adb_device_status: Default::default(),
verbose: Default::default(),
+ verbose_run_make_subprocess_output: Default::default(),
remote_test_client: Default::default(),
compare_mode: Default::default(),
rustfix_coverage: Default::default(),
diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs
index f44b3861d11d3..93ec44d58d791 100644
--- a/src/tools/run-make-support/src/util.rs
+++ b/src/tools/run-make-support/src/util.rs
@@ -4,7 +4,7 @@ use crate::command::{Command, CompletedProcess};
use crate::env::env_var;
use crate::path_helpers::cwd;
-pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) {
+fn print_command_output(cmd: &Command, output: &CompletedProcess) {
cmd.inspect(|std_cmd| {
eprintln!("{std_cmd:?}");
});
@@ -16,6 +16,15 @@ pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) {
}
}
+pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) {
+ // Only prints when `--verbose-run-make-subprocess-output` is active (env var set),
+ // so that passing tests don't flood the terminal when using `--no-capture`.
+ if std::env::var_os("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT").is_none() {
+ return;
+ }
+ print_command_output(cmd, output);
+}
+
/// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the
/// executed command, failure location, output status and stdout/stderr, and abort the process with
/// exit code `1`.
@@ -29,7 +38,7 @@ pub(crate) fn handle_failed_output(
} else {
eprintln!("command failed at line {caller_line_number}");
}
- verbose_print_command(cmd, &output);
+ print_command_output(cmd, &output);
std::process::exit(1)
}
diff --git a/tests/codegen-llvm/inject-autocast.rs b/tests/codegen-llvm/inject-autocast.rs
new file mode 100644
index 0000000000000..fec9d3f0b1955
--- /dev/null
+++ b/tests/codegen-llvm/inject-autocast.rs
@@ -0,0 +1,93 @@
+//@ compile-flags: -C opt-level=0 -C target-feature=+kl,+avx512vp2intersect,+avx512vl,+avxneconvert
+//@ only-x86_64
+
+#![feature(link_llvm_intrinsics, abi_unadjusted, simd_ffi, portable_simd)]
+#![crate_type = "lib"]
+
+use std::simd::{f32x4, i16x8, i64x2};
+
+#[repr(C, packed)]
+pub struct Bar(u32, i64x2, i64x2, i64x2, i64x2, i64x2, i64x2);
+// CHECK: %Bar = type <{ i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> }>
+
+// CHECK-LABEL: @struct_autocast
+#[no_mangle]
+pub unsafe fn struct_autocast(key_metadata: u32, key: i64x2) -> Bar {
+ extern "unadjusted" {
+ #[link_name = "llvm.x86.encodekey128"]
+ fn foo(key_metadata: u32, key: i64x2) -> Bar;
+ }
+
+ // CHECK: [[A:%[0-9]+]] = call { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } @llvm.x86.encodekey128(i32 {{.*}}, <2 x i64> {{.*}})
+ // CHECK: [[B:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 0
+ // CHECK: [[C:%[0-9]+]] = insertvalue %Bar poison, i32 [[B]], 0
+ // CHECK: [[D:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 1
+ // CHECK: [[E:%[0-9]+]] = insertvalue %Bar [[C]], <2 x i64> [[D]], 1
+ // CHECK: [[F:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 2
+ // CHECK: [[G:%[0-9]+]] = insertvalue %Bar [[E]], <2 x i64> [[F]], 2
+ // CHECK: [[H:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 3
+ // CHECK: [[I:%[0-9]+]] = insertvalue %Bar [[G]], <2 x i64> [[H]], 3
+ // CHECK: [[J:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 4
+ // CHECK: [[K:%[0-9]+]] = insertvalue %Bar [[I]], <2 x i64> [[J]], 4
+ // CHECK: [[L:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 5
+ // CHECK: [[M:%[0-9]+]] = insertvalue %Bar [[K]], <2 x i64> [[L]], 5
+ // CHECK: [[N:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 6
+ // CHECK: insertvalue %Bar [[M]], <2 x i64> [[N]], 6
+ foo(key_metadata, key)
+}
+
+// CHECK-LABEL: @struct_with_i1_vector_autocast
+#[no_mangle]
+pub unsafe fn struct_with_i1_vector_autocast(a: i64x2, b: i64x2) -> (u8, u8) {
+ extern "unadjusted" {
+ #[link_name = "llvm.x86.avx512.vp2intersect.q.128"]
+ fn foo(a: i64x2, b: i64x2) -> (u8, u8);
+ }
+
+ // CHECK: [[A:%[0-9]+]] = call { <2 x i1>, <2 x i1> } @llvm.x86.avx512.vp2intersect.q.128(<2 x i64> {{.*}}, <2 x i64> {{.*}})
+ // CHECK: [[B:%[0-9]+]] = extractvalue { <2 x i1>, <2 x i1> } [[A]], 0
+ // CHECK: [[C:%[0-9]+]] = shufflevector <2 x i1> [[B]], <2 x i1> zeroinitializer, <8 x i32>
+ // CHECK: [[D:%[0-9]+]] = bitcast <8 x i1> [[C]] to i8
+ // CHECK: [[E:%[0-9]+]] = insertvalue { i8, i8 } poison, i8 [[D]], 0
+ // CHECK: [[F:%[0-9]+]] = extractvalue { <2 x i1>, <2 x i1> } [[A]], 1
+ // CHECK: [[G:%[0-9]+]] = shufflevector <2 x i1> [[F]], <2 x i1> zeroinitializer, <8 x i32>
+ // CHECK: [[H:%[0-9]+]] = bitcast <8 x i1> [[G]] to i8
+ // CHECK: insertvalue { i8, i8 } [[E]], i8 [[H]], 1
+ foo(a, b)
+}
+
+// CHECK-LABEL: @i1_vector_autocast
+#[no_mangle]
+pub unsafe fn i1_vector_autocast(a: u8, b: u8) -> u8 {
+ extern "unadjusted" {
+ #[link_name = "llvm.x86.avx512.kadd.b"]
+ fn foo(a: u8, b: u8) -> u8;
+ }
+
+ // CHECK: [[A:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1>
+ // CHECK: [[B:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1>
+ // CHECK: [[C:%[0-9]+]] = call <8 x i1> @llvm.x86.avx512.kadd.b(<8 x i1> [[A]], <8 x i1> [[B]])
+ // CHECK: bitcast <8 x i1> [[C]] to i8
+ foo(a, b)
+}
+
+// CHECK-LABEL: @bf16_vector_autocast
+#[no_mangle]
+pub unsafe fn bf16_vector_autocast(a: f32x4) -> i16x8 {
+ extern "unadjusted" {
+ #[link_name = "llvm.x86.vcvtneps2bf16128"]
+ fn foo(a: f32x4) -> i16x8;
+ }
+
+ // CHECK: [[A:%[0-9]+]] = call <8 x bfloat> @llvm.x86.vcvtneps2bf16128(<4 x float> {{.*}})
+ // CHECK: bitcast <8 x bfloat> [[A]] to <8 x i16>
+ foo(a)
+}
+
+// CHECK: declare { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } @llvm.x86.encodekey128(i32, <2 x i64>)
+
+// CHECK: declare { <2 x i1>, <2 x i1> } @llvm.x86.avx512.vp2intersect.q.128(<2 x i64>, <2 x i64>)
+
+// CHECK: declare <8 x i1> @llvm.x86.avx512.kadd.b(<8 x i1>, <8 x i1>)
+
+// CHECK: declare <8 x bfloat> @llvm.x86.vcvtneps2bf16128(<4 x float>)
diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs
index 238ab12c186ef..a4410c70ba38a 100644
--- a/tests/debuginfo/basic-stepping.rs
+++ b/tests/debuginfo/basic-stepping.rs
@@ -9,9 +9,20 @@
// Debugger tests need debuginfo
//@ compile-flags: -g
-// FIXME(#128945): SingleUseConsts shouldn't need to be disabled.
-//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass
-//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts
+// Some optimization passes _improve_ compile times [1]. So we want to run some
+// passes even with `-Copt-level=0`. That means that some of the lines below can
+// be optimized away. To make regression testing more robust, we also want to
+// run this test with such passes disabled. The solution is to use two
+// revisions. One with default `-Copt-level=0` passes, and one "even less
+// optimized", with enough optimization passes disabled to keep the maximum
+// number of lines steppable.
+//
+// If `-Zmir-enable-passes=-...` ends up being annoying to maintain, we can try
+// switching to `-Zmir-opt-level=0` instead.
+//
+// [1]: https://github.com/rust-lang/compiler-team/issues/319
+//@ revisions: opt-level-0 maximally-steppable
+//@ [maximally-steppable] compile-flags: -Zmir-enable-passes=-SingleUseConsts
// === GDB TESTS ===================================================================================
@@ -20,12 +31,12 @@
//@ gdb-command: next
//@ gdb-check: let d = c = 99;
//@ gdb-command: next
-//@ [no-SingleUseConsts-mir-pass] gdb-check: let e = "hi bob";
-//@ [no-SingleUseConsts-mir-pass] gdb-command: next
-//@ [no-SingleUseConsts-mir-pass] gdb-check: let f = b"hi bob";
-//@ [no-SingleUseConsts-mir-pass] gdb-command: next
-//@ [no-SingleUseConsts-mir-pass] gdb-check: let g = b'9';
-//@ [no-SingleUseConsts-mir-pass] gdb-command: next
+//@ [maximally-steppable] gdb-check: let e = "hi bob";
+//@ [maximally-steppable] gdb-command: next
+//@ [maximally-steppable] gdb-check: let f = b"hi bob";
+//@ [maximally-steppable] gdb-command: next
+//@ [maximally-steppable] gdb-check: let g = b'9';
+//@ [maximally-steppable] gdb-command: next
//@ gdb-check: let h = ["whatever"; 8];
//@ gdb-command: next
//@ gdb-check: let i = [1,2,3,4];
@@ -61,15 +72,15 @@
//@ lldb-check: [...]let d = c = 99;[...]
//@ lldb-command: next
//@ lldb-command: frame select
-//@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let e = "hi bob";[...]
-//@ [no-SingleUseConsts-mir-pass] lldb-command: next
-//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select
-//@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let f = b"hi bob";[...]
-//@ [no-SingleUseConsts-mir-pass] lldb-command: next
-//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select
-//@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let g = b'9';[...]
-//@ [no-SingleUseConsts-mir-pass] lldb-command: next
-//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select
+//@ [maximally-steppable] lldb-check: [...]let e = "hi bob";[...]
+//@ [maximally-steppable] lldb-command: next
+//@ [maximally-steppable] lldb-command: frame select
+//@ [maximally-steppable] lldb-check: [...]let f = b"hi bob";[...]
+//@ [maximally-steppable] lldb-command: next
+//@ [maximally-steppable] lldb-command: frame select
+//@ [maximally-steppable] lldb-check: [...]let g = b'9';[...]
+//@ [maximally-steppable] lldb-command: next
+//@ [maximally-steppable] lldb-command: frame select
//@ lldb-check: [...]let h = ["whatever"; 8];[...]
//@ lldb-command: next
//@ lldb-command: frame select
@@ -107,12 +118,12 @@
//@ cdb-check: [...]: let mut c = 27;
//@ cdb-command: p
//@ cdb-check: [...]: let d = c = 99;
-//@ [no-SingleUseConsts-mir-pass] cdb-command: p
-//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let e = "hi bob";
-//@ [no-SingleUseConsts-mir-pass] cdb-command: p
-//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let f = b"hi bob";
-//@ [no-SingleUseConsts-mir-pass] cdb-command: p
-//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let g = b'9';
+//@ [maximally-steppable] cdb-command: p
+//@ [maximally-steppable] cdb-check: [...]: let e = "hi bob";
+//@ [maximally-steppable] cdb-command: p
+//@ [maximally-steppable] cdb-check: [...]: let f = b"hi bob";
+//@ [maximally-steppable] cdb-command: p
+//@ [maximally-steppable] cdb-check: [...]: let g = b'9';
//@ cdb-command: p
//@ cdb-check: [...]: let h = ["whatever"; 8];
//@ cdb-command: p
diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs
index 3f57eb9ad79bd..c2f6183e3c7b0 100644
--- a/tests/debuginfo/macro-stepping.rs
+++ b/tests/debuginfo/macro-stepping.rs
@@ -16,9 +16,9 @@
extern crate macro_stepping; // exports new_scope!()
//@ compile-flags: -g
-// FIXME(#128945): SingleUseConsts shouldn't need to be disabled.
-//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass
-//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts
+// See explanation in `tests/debuginfo/basic-stepping.rs`.
+//@ revisions: opt-level-0 maximally-steppable
+//@ [maximally-steppable] compile-flags: -Zmir-enable-passes=-SingleUseConsts
// === GDB TESTS ===================================================================================
@@ -51,7 +51,7 @@ extern crate macro_stepping; // exports new_scope!()
//@ gdb-check:[...]#inc-loc2[...]
//@ gdb-command:next
//@ gdb-command:frame
-//@ [no-SingleUseConsts-mir-pass] gdb-check:[...]#inc-loc3[...]
+//@ [maximally-steppable] gdb-check:[...]#inc-loc3[...]
// === LLDB TESTS ==================================================================================
diff --git a/tests/run-make/simd-ffi/simd.rs b/tests/run-make/simd-ffi/simd.rs
index 1cd961ff87e7b..3f12dabdb65ea 100644
--- a/tests/run-make/simd-ffi/simd.rs
+++ b/tests/run-make/simd-ffi/simd.rs
@@ -35,7 +35,7 @@ extern "C" {
fn integer(a: i32x4, b: i32x4) -> i32x4;
// vmaxq_s32
#[cfg(target_arch = "aarch64")]
- #[link_name = "llvm.aarch64.neon.maxs.v4i32"]
+ #[link_name = "llvm.aarch64.neon.smax.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// Use a generic LLVM intrinsic to do type checking on other platforms
diff --git a/tests/ui/codegen/deprecated-llvm-intrinsic.rs b/tests/ui/codegen/deprecated-llvm-intrinsic.rs
new file mode 100644
index 0000000000000..33bc5f419151a
--- /dev/null
+++ b/tests/ui/codegen/deprecated-llvm-intrinsic.rs
@@ -0,0 +1,28 @@
+//@ add-minicore
+//@ build-fail
+//@ compile-flags: --target aarch64-unknown-linux-gnu
+//@ needs-llvm-components: aarch64
+//@ ignore-backends: gcc
+#![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted, repr_simd, simd_ffi)]
+#![no_std]
+#![no_core]
+#![allow(internal_features, non_camel_case_types, improper_ctypes)]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(simd)]
+pub struct i8x8([i8; 8]);
+
+extern "unadjusted" {
+ #[deny(deprecated_llvm_intrinsic)]
+ #[link_name = "llvm.aarch64.neon.rbit.v8i8"]
+ fn foo(a: i8x8) -> i8x8;
+ //~^ ERROR: using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
+}
+
+#[target_feature(enable = "neon")]
+pub unsafe fn bar(a: i8x8) -> i8x8 {
+ foo(a)
+}
diff --git a/tests/ui/codegen/deprecated-llvm-intrinsic.stderr b/tests/ui/codegen/deprecated-llvm-intrinsic.stderr
new file mode 100644
index 0000000000000..40e4684a8ea4f
--- /dev/null
+++ b/tests/ui/codegen/deprecated-llvm-intrinsic.stderr
@@ -0,0 +1,14 @@
+error: using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
+ --> $DIR/deprecated-llvm-intrinsic.rs:21:5
+ |
+LL | fn foo(a: i8x8) -> i8x8;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/deprecated-llvm-intrinsic.rs:19:12
+ |
+LL | #[deny(deprecated_llvm_intrinsic)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.rs b/tests/ui/codegen/incorrect-arch-intrinsic.rs
new file mode 100644
index 0000000000000..9576cb8f81318
--- /dev/null
+++ b/tests/ui/codegen/incorrect-arch-intrinsic.rs
@@ -0,0 +1,18 @@
+//@ build-fail
+//@ ignore-s390x
+//@ normalize-stderr: "target arch `(.*)`" -> "target arch `TARGET_ARCH`"
+//@ ignore-backends: gcc
+
+#![feature(link_llvm_intrinsics, abi_unadjusted)]
+
+extern "unadjusted" {
+ #[link_name = "llvm.s390.sfpc"]
+ fn foo(a: i32);
+ //~^ ERROR: intrinsic `llvm.s390.sfpc` cannot be used with target arch
+}
+
+pub fn main() {
+ unsafe {
+ foo(0);
+ }
+}
diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.stderr b/tests/ui/codegen/incorrect-arch-intrinsic.stderr
new file mode 100644
index 0000000000000..5b44419aa741f
--- /dev/null
+++ b/tests/ui/codegen/incorrect-arch-intrinsic.stderr
@@ -0,0 +1,8 @@
+error: intrinsic `llvm.s390.sfpc` cannot be used with target arch `TARGET_ARCH`
+ --> $DIR/incorrect-arch-intrinsic.rs:10:5
+ |
+LL | fn foo(a: i32);
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs
new file mode 100644
index 0000000000000..4b86f37f922a6
--- /dev/null
+++ b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs
@@ -0,0 +1,14 @@
+//@ build-fail
+//@ ignore-backends: gcc
+
+#![feature(link_llvm_intrinsics, abi_unadjusted)]
+
+extern "unadjusted" {
+ #[link_name = "llvm.assume"]
+ fn foo();
+ //~^ ERROR: intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()`
+}
+
+pub fn main() {
+ unsafe { foo() }
+}
diff --git a/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr
new file mode 100644
index 0000000000000..4e58e5ebdc731
--- /dev/null
+++ b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr
@@ -0,0 +1,8 @@
+error: intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()`
+ --> $DIR/incorrect-llvm-intrinsic-signature.rs:8:5
+ |
+LL | fn foo();
+ | ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/codegen/unknown-llvm-intrinsic.rs b/tests/ui/codegen/unknown-llvm-intrinsic.rs
new file mode 100644
index 0000000000000..bbb4df8c0b271
--- /dev/null
+++ b/tests/ui/codegen/unknown-llvm-intrinsic.rs
@@ -0,0 +1,14 @@
+//@ build-fail
+//@ ignore-backends: gcc
+
+#![feature(link_llvm_intrinsics, abi_unadjusted)]
+
+extern "unadjusted" {
+ #[link_name = "llvm.abcde"]
+ fn foo();
+ //~^ ERROR: unknown LLVM intrinsic `llvm.abcde`
+}
+
+pub fn main() {
+ unsafe { foo() }
+}
diff --git a/tests/ui/codegen/unknown-llvm-intrinsic.stderr b/tests/ui/codegen/unknown-llvm-intrinsic.stderr
new file mode 100644
index 0000000000000..5417140c69795
--- /dev/null
+++ b/tests/ui/codegen/unknown-llvm-intrinsic.stderr
@@ -0,0 +1,8 @@
+error: unknown LLVM intrinsic `llvm.abcde`
+ --> $DIR/unknown-llvm-intrinsic.rs:8:5
+ |
+LL | fn foo();
+ | ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/delegation/generics/query-cycle-oom-154169.rs b/tests/ui/delegation/generics/query-cycle-oom-154169.rs
index 04a2896f6dd21..0636f19a548ae 100644
--- a/tests/ui/delegation/generics/query-cycle-oom-154169.rs
+++ b/tests/ui/delegation/generics/query-cycle-oom-154169.rs
@@ -20,7 +20,6 @@ mod test_2 {
trait Trait {
fn foo() -> Self::Assoc;
//~^ ERROR: associated type `Assoc` not found for `Self`
- //~| ERROR: this function takes 0 arguments but 1 argument was supplied
fn bar(&self) -> u8;
}
@@ -33,6 +32,7 @@ mod test_2 {
impl Trait for S {
reuse Trait::* { &self.0 }
+ //~^ ERROR this function takes 0 arguments but 1 argument was supplied
fn bar(&self) -> u8 { 2 }
}
}
@@ -40,13 +40,13 @@ mod test_2 {
mod test_3 {
trait Trait {
fn foo(&self) -> Self::Assoc<3> { //~ ERROR: associated type `Assoc` not found for `Self`
- //~^ ERROR: no method named `foo` found for reference `&()` in the current scope
[(); 3]
}
}
impl () { //~ ERROR: cannot define inherent `impl` for primitive types
reuse Trait::*;
+ //~^ ERROR no method named `foo` found for reference `&()` in the current scope
}
}
diff --git a/tests/ui/delegation/generics/query-cycle-oom-154169.stderr b/tests/ui/delegation/generics/query-cycle-oom-154169.stderr
index 1baed6fd6748d..682736b7a998a 100644
--- a/tests/ui/delegation/generics/query-cycle-oom-154169.stderr
+++ b/tests/ui/delegation/generics/query-cycle-oom-154169.stderr
@@ -27,7 +27,7 @@ LL | fn foo(&self) -> Self::Assoc<3> {
| ^^^^^ associated type `Assoc` not found
error[E0046]: not all trait items implemented, missing: `foo`
- --> $DIR/query-cycle-oom-154169.rs:27:5
+ --> $DIR/query-cycle-oom-154169.rs:26:5
|
LL | fn foo() -> Self::Assoc;
| ------------------------ `foo` from trait
@@ -36,7 +36,7 @@ LL | impl Trait for u8 {
| ^^^^^^^^^^^^^^^^^ missing `foo` in implementation
error[E0390]: cannot define inherent `impl` for primitive types
- --> $DIR/query-cycle-oom-154169.rs:48:5
+ --> $DIR/query-cycle-oom-154169.rs:47:5
|
LL | impl () {
| ^^^^^^^
@@ -52,13 +52,10 @@ LL | reuse to_reuse::foo { &self.0 }
= help: you might be missing a crate named `to_reuse`
error[E0061]: this function takes 0 arguments but 1 argument was supplied
- --> $DIR/query-cycle-oom-154169.rs:21:12
+ --> $DIR/query-cycle-oom-154169.rs:34:22
|
-LL | fn foo() -> Self::Assoc;
- | ^^^
-...
LL | reuse Trait::* { &self.0 }
- | ------- unexpected argument
+ | ^ ------- unexpected argument
|
note: associated function defined here
--> $DIR/query-cycle-oom-154169.rs:21:12
@@ -67,29 +64,15 @@ LL | fn foo() -> Self::Assoc;
| ^^^
help: remove the extra argument
|
-LL - fn foo() -> Self::Assoc;
-LL -
-LL -
-LL - fn bar(&self) -> u8;
-LL - }
-LL -
-LL - impl Trait for u8 {
-LL -
-LL - fn bar(&self) -> u8 { 1 }
-LL - }
-LL -
-LL - struct S(u8);
-LL -
-LL - impl Trait for S {
LL - reuse Trait::* { &self.0 }
-LL + fn fo&self.0 }
+LL + reuse Trait::&self.0 }
|
error[E0599]: no method named `foo` found for reference `&()` in the current scope
- --> $DIR/query-cycle-oom-154169.rs:42:12
+ --> $DIR/query-cycle-oom-154169.rs:48:22
|
-LL | fn foo(&self) -> Self::Assoc<3> {
- | ^^^ method not found in `&()`
+LL | reuse Trait::*;
+ | ^ method not found in `&()`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following traits define an item `foo`, perhaps you need to implement one of them:
diff --git a/tests/ui/delegation/glob-glob-conflict.rs b/tests/ui/delegation/glob-glob-conflict.rs
index cb07a78b84fef..c1cd3f703e07f 100644
--- a/tests/ui/delegation/glob-glob-conflict.rs
+++ b/tests/ui/delegation/glob-glob-conflict.rs
@@ -3,13 +3,10 @@
trait Trait1 {
fn method(&self) -> u8;
- //~^ ERROR: this function takes 1 argument but 0 arguments were supplied
- //~| ERROR: mismatched types
}
trait Trait2 {
fn method(&self) -> u8;
- //~^ ERROR: this function takes 1 argument but 0 arguments were supplied
- //~| ERROR: mismatched types
+
}
trait Trait {
fn method(&self) -> u8;
@@ -28,10 +25,14 @@ impl Trait2 for u8 {
impl Trait for u8 {
reuse Trait1::*;
reuse Trait2::*; //~ ERROR duplicate definitions with name `method`
+ //~^ ERROR: this function takes 1 argument but 0 arguments were supplied
+ //~| ERROR: mismatched types
}
impl Trait for u16 {
reuse Trait1::*;
reuse Trait1::*; //~ ERROR duplicate definitions with name `method`
+ //~^ ERROR: this function takes 1 argument but 0 arguments were supplied
+ //~| ERROR: mismatched types
}
fn main() {}
diff --git a/tests/ui/delegation/glob-glob-conflict.stderr b/tests/ui/delegation/glob-glob-conflict.stderr
index 4259d71117b7b..f55ee333630c6 100644
--- a/tests/ui/delegation/glob-glob-conflict.stderr
+++ b/tests/ui/delegation/glob-glob-conflict.stderr
@@ -1,5 +1,5 @@
error[E0201]: duplicate definitions with name `method`:
- --> $DIR/glob-glob-conflict.rs:30:5
+ --> $DIR/glob-glob-conflict.rs:27:5
|
LL | fn method(&self) -> u8;
| ----------------------- item in trait
@@ -10,7 +10,7 @@ LL | reuse Trait2::*;
| ^^^^^^^^^^^^^^^^ duplicate definition
error[E0201]: duplicate definitions with name `method`:
- --> $DIR/glob-glob-conflict.rs:34:5
+ --> $DIR/glob-glob-conflict.rs:33:5
|
LL | fn method(&self) -> u8;
| ----------------------- item in trait
@@ -21,35 +21,35 @@ LL | reuse Trait1::*;
| ^^^^^^^^^^^^^^^^ duplicate definition
error[E0061]: this function takes 1 argument but 0 arguments were supplied
- --> $DIR/glob-glob-conflict.rs:10:8
+ --> $DIR/glob-glob-conflict.rs:27:19
|
-LL | fn method(&self) -> u8;
- | ^^^^^^ argument #1 of type `&_` is missing
+LL | reuse Trait2::*;
+ | ^ argument #1 of type `&_` is missing
|
note: method defined here
- --> $DIR/glob-glob-conflict.rs:10:8
+ --> $DIR/glob-glob-conflict.rs:8:8
|
LL | fn method(&self) -> u8;
| ^^^^^^ ----
help: provide the argument
|
-LL | fn method(/* value */)(&self) -> u8;
- | +++++++++++++
+LL | reuse Trait2::*(/* value */);
+ | +++++++++++++
error[E0308]: mismatched types
- --> $DIR/glob-glob-conflict.rs:10:8
+ --> $DIR/glob-glob-conflict.rs:27:19
|
-LL | fn method(&self) -> u8;
- | ^^^^^^- help: consider using a semicolon here: `;`
- | |
- | expected `()`, found `u8`
- | expected `()` because of default return type
+LL | reuse Trait2::*;
+ | ^- help: consider using a semicolon here: `;`
+ | |
+ | expected `()`, found `u8`
+ | expected `()` because of default return type
error[E0061]: this function takes 1 argument but 0 arguments were supplied
- --> $DIR/glob-glob-conflict.rs:5:8
+ --> $DIR/glob-glob-conflict.rs:33:19
|
-LL | fn method(&self) -> u8;
- | ^^^^^^ argument #1 of type `&_` is missing
+LL | reuse Trait1::*;
+ | ^ argument #1 of type `&_` is missing
|
note: method defined here
--> $DIR/glob-glob-conflict.rs:5:8
@@ -58,17 +58,17 @@ LL | fn method(&self) -> u8;
| ^^^^^^ ----
help: provide the argument
|
-LL | fn method(/* value */)(&self) -> u8;
- | +++++++++++++
+LL | reuse Trait1::*(/* value */);
+ | +++++++++++++
error[E0308]: mismatched types
- --> $DIR/glob-glob-conflict.rs:5:8
+ --> $DIR/glob-glob-conflict.rs:33:19
|
-LL | fn method(&self) -> u8;
- | ^^^^^^- help: consider using a semicolon here: `;`
- | |
- | expected `()`, found `u8`
- | expected `()` because of default return type
+LL | reuse Trait1::*;
+ | ^- help: consider using a semicolon here: `;`
+ | |
+ | expected `()`, found `u8`
+ | expected `()` because of default return type
error: aborting due to 6 previous errors
diff --git a/tests/ui/delegation/impl-reuse-negative-traits.rs b/tests/ui/delegation/impl-reuse-negative-traits.rs
index 7bcbc82f03db8..8bc2b72708599 100644
--- a/tests/ui/delegation/impl-reuse-negative-traits.rs
+++ b/tests/ui/delegation/impl-reuse-negative-traits.rs
@@ -4,7 +4,6 @@
trait Trait {
fn foo(&self);
- //~^ ERROR negative impls cannot have any items [E0749]
}
struct S;
@@ -15,5 +14,6 @@ impl Trait for S {
struct F(S);
reuse impl !Trait for F { &self.0 }
+//~^ ERROR negative impls cannot have any items
fn main() {}
diff --git a/tests/ui/delegation/impl-reuse-negative-traits.stderr b/tests/ui/delegation/impl-reuse-negative-traits.stderr
index 1be6ef715920d..7510fdd89d7c6 100644
--- a/tests/ui/delegation/impl-reuse-negative-traits.stderr
+++ b/tests/ui/delegation/impl-reuse-negative-traits.stderr
@@ -1,8 +1,8 @@
error[E0749]: negative impls cannot have any items
- --> $DIR/impl-reuse-negative-traits.rs:6:8
+ --> $DIR/impl-reuse-negative-traits.rs:16:1
|
-LL | fn foo(&self);
- | ^^^
+LL | reuse impl !Trait for F { &self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/delegation/impl-reuse-pass.rs b/tests/ui/delegation/impl-reuse-pass.rs
index 90060b03f9efd..578e8c08e7038 100644
--- a/tests/ui/delegation/impl-reuse-pass.rs
+++ b/tests/ui/delegation/impl-reuse-pass.rs
@@ -173,19 +173,6 @@ mod macros {
macro_rules! m { () => { M } }
reuse impl Trait for m!() { self_0_ref!(self) }
- struct S1(u8);
- macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } }
- one_line_reuse!(self);
-
- struct S2(u8);
- macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } }
- one_line_reuse_expr!(self.0);
-
- struct S3(u8);
- macro_rules! s3 { () => { S3 } }
- macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } }
- one_line_reuse_expr2!(self.0);
-
fn f() {
let s = S(1);
s.foo();
@@ -194,18 +181,6 @@ mod macros {
let m = M(41);
m.foo();
m.bar();
-
- let s1 = S1(2);
- s1.foo();
- s1.bar();
-
- let s2 = S2(4);
- s2.foo();
- s2.bar();
-
- let s3 = S3(5);
- s3.foo();
- s3.bar();
}
}
diff --git a/tests/ui/delegation/impl-reuse-self-hygiene.rs b/tests/ui/delegation/impl-reuse-self-hygiene.rs
new file mode 100644
index 0000000000000..b49e4419703a7
--- /dev/null
+++ b/tests/ui/delegation/impl-reuse-self-hygiene.rs
@@ -0,0 +1,28 @@
+#![allow(incomplete_features)]
+#![feature(fn_delegation)]
+
+trait Trait {
+ fn foo(&self) -> u8 { 0 }
+ fn bar(&self) -> u8 { 1 }
+}
+
+struct S1(u8);
+macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } }
+//~^ ERROR expected value, found module `self`
+//~| ERROR expected value, found module `self`
+one_line_reuse!(self);
+
+struct S2(u8);
+macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } }
+one_line_reuse_expr!(self.0);
+//~^ ERROR expected value, found module `self`
+//~| ERROR expected value, found module `self`
+
+struct S3(u8);
+macro_rules! s3 { () => { S3 } }
+macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } }
+one_line_reuse_expr2!(self.0);
+//~^ ERROR expected value, found module `self`
+//~| ERROR expected value, found module `self`
+
+fn main() {}
diff --git a/tests/ui/delegation/impl-reuse-self-hygiene.stderr b/tests/ui/delegation/impl-reuse-self-hygiene.stderr
new file mode 100644
index 0000000000000..ae93829809e4f
--- /dev/null
+++ b/tests/ui/delegation/impl-reuse-self-hygiene.stderr
@@ -0,0 +1,68 @@
+error[E0424]: expected value, found module `self`
+ --> $DIR/impl-reuse-self-hygiene.rs:10:76
+ |
+LL | macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } }
+ | --------------------------^^^^^----
+ | | |
+ | | `self` value is a keyword only available in methods with a `self` parameter
+ | `self` not allowed in an implementation
+...
+LL | one_line_reuse!(self);
+ | --------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `one_line_reuse` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/impl-reuse-self-hygiene.rs:10:76
+ |
+LL | macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } }
+ | --------------------------^^^^^----
+ | | |
+ | | `self` value is a keyword only available in methods with a `self` parameter
+ | `self` not allowed in an implementation
+...
+LL | one_line_reuse!(self);
+ | --------------------- in this macro invocation
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+ = note: this error originates in the macro `one_line_reuse` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/impl-reuse-self-hygiene.rs:17:22
+ |
+LL | macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } }
+ | ------------------------------ `self` not allowed in an implementation
+LL | one_line_reuse_expr!(self.0);
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/impl-reuse-self-hygiene.rs:17:22
+ |
+LL | macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } }
+ | ------------------------------ `self` not allowed in an implementation
+LL | one_line_reuse_expr!(self.0);
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/impl-reuse-self-hygiene.rs:24:23
+ |
+LL | macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } }
+ | --------------------------------- `self` not allowed in an implementation
+LL | one_line_reuse_expr2!(self.0);
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/impl-reuse-self-hygiene.rs:24:23
+ |
+LL | macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } }
+ | --------------------------------- `self` not allowed in an implementation
+LL | one_line_reuse_expr2!(self.0);
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0424`.
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`.