diff --git a/.gitmodules b/.gitmodules
index 439fde6d7660..8617643a1202 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -25,7 +25,7 @@
[submodule "src/llvm-project"]
path = src/llvm-project
url = https://github.com/rust-lang/llvm-project.git
- branch = rustc/20.1-2025-07-13
+ branch = rustc/21.1-2025-08-01
shallow = true
[submodule "src/doc/embedded-book"]
path = src/doc/embedded-book
diff --git a/Cargo.lock b/Cargo.lock
index 5a3906c470f7..dbb76ada8377 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -568,7 +568,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "clippy"
-version = "0.1.90"
+version = "0.1.91"
dependencies = [
"anstream",
"askama",
@@ -595,7 +595,7 @@ dependencies = [
[[package]]
name = "clippy_config"
-version = "0.1.90"
+version = "0.1.91"
dependencies = [
"clippy_utils",
"itertools",
@@ -618,7 +618,7 @@ dependencies = [
[[package]]
name = "clippy_lints"
-version = "0.1.90"
+version = "0.1.91"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.1",
@@ -649,7 +649,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
-version = "0.1.90"
+version = "0.1.91"
dependencies = [
"arrayvec",
"itertools",
@@ -1051,7 +1051,7 @@ dependencies = [
[[package]]
name = "declare_clippy_lint"
-version = "0.1.90"
+version = "0.1.91"
[[package]]
name = "derive-where"
diff --git a/RELEASES.md b/RELEASES.md
index 1ae221774dc9..b6dc06286467 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,140 @@
+Version 1.89.0 (2025-08-07)
+==========================
+
+
+
+Language
+--------
+- [Stabilize explicitly inferred const arguments (`feature(generic_arg_infer)`)](https://github.com/rust-lang/rust/pull/141610)
+- [Add a warn-by-default `mismatched_lifetime_syntaxes` lint.](https://github.com/rust-lang/rust/pull/138677)
+ This lint detects when the same lifetime is referred to by different syntax categories between function arguments and return values, which can be confusing to read, especially in unsafe code.
+ This lint supersedes the warn-by-default `elided_named_lifetimes` lint.
+- [Expand `unpredictable_function_pointer_comparisons` to also lint on function pointer comparisons in external macros](https://github.com/rust-lang/rust/pull/134536)
+- [Make the `dangerous_implicit_autorefs` lint deny-by-default](https://github.com/rust-lang/rust/pull/141661)
+- [Stabilize the avx512 target features](https://github.com/rust-lang/rust/pull/138940)
+- [Stabilize `kl` and `widekl` target features for x86](https://github.com/rust-lang/rust/pull/140766)
+- [Stabilize `sha512`, `sm3` and `sm4` target features for x86](https://github.com/rust-lang/rust/pull/140767)
+- [Stabilize LoongArch target features `f`, `d`, `frecipe`, `lasx`, `lbt`, `lsx`, and `lvz`](https://github.com/rust-lang/rust/pull/135015)
+- [Remove `i128` and `u128` from `improper_ctypes_definitions`](https://github.com/rust-lang/rust/pull/137306)
+- [Stabilize `repr128` (`#[repr(u128)]`, `#[repr(i128)]`)](https://github.com/rust-lang/rust/pull/138285)
+- [Allow `#![doc(test(attr(..)))]` everywhere](https://github.com/rust-lang/rust/pull/140560)
+- [Extend temporary lifetime extension to also go through tuple struct and tuple variant constructors](https://github.com/rust-lang/rust/pull/140593)
+- [`extern "C"` functions on the `wasm32-unknown-unknown` target now have a standards compliant ABI](https://blog.rust-lang.org/2025/04/04/c-abi-changes-for-wasm32-unknown-unknown/)
+
+
+
+Compiler
+--------
+- [Default to non-leaf frame pointers on aarch64-linux](https://github.com/rust-lang/rust/pull/140832)
+- [Enable non-leaf frame pointers for Arm64EC Windows](https://github.com/rust-lang/rust/pull/140862)
+- [Set Apple frame pointers by architecture](https://github.com/rust-lang/rust/pull/141797)
+
+
+
+
+Platform Support
+----------------
+- [Add new Tier-3 targets `loongarch32-unknown-none` and `loongarch32-unknown-none-softfloat`](https://github.com/rust-lang/rust/pull/142053)
+- [`x86_64-apple-darwin` is in the process of being demoted to Tier 2 with host tools](https://github.com/rust-lang/rfcs/pull/3841)
+
+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
+---------
+- [Specify the base path for `file!`](https://github.com/rust-lang/rust/pull/134442)
+- [Allow storing `format_args!()` in a variable](https://github.com/rust-lang/rust/pull/140748)
+- [Add `#[must_use]` to `[T; N]::map`](https://github.com/rust-lang/rust/pull/140957)
+- [Implement `DerefMut` for `Lazy{Cell,Lock}`](https://github.com/rust-lang/rust/pull/129334)
+- [Implement `Default` for `array::IntoIter`](https://github.com/rust-lang/rust/pull/141574)
+- [Implement `Clone` for `slice::ChunkBy`](https://github.com/rust-lang/rust/pull/138016)
+- [Implement `io::Seek` for `io::Take`](https://github.com/rust-lang/rust/pull/138023)
+
+
+
+
+Stabilized APIs
+---------------
+
+- [`NonZero`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html)
+- Many intrinsics for x86, not enumerated here
+ - [AVX512 intrinsics](https://github.com/rust-lang/rust/issues/111137)
+ - [`SHA512`, `SM3` and `SM4` intrinsics](https://github.com/rust-lang/rust/issues/126624)
+- [`File::lock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.lock)
+- [`File::lock_shared`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.lock_shared)
+- [`File::try_lock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_lock)
+- [`File::try_lock_shared`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_lock_shared)
+- [`File::unlock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.unlock)
+- [`NonNull::from_ref`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.from_ref)
+- [`NonNull::from_mut`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.from_mut)
+- [`NonNull::without_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.without_provenance)
+- [`NonNull::with_exposed_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.with_exposed_provenance)
+- [`NonNull::expose_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.expose_provenance)
+- [`OsString::leak`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.leak)
+- [`PathBuf::leak`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.leak)
+- [`Result::flatten`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.flatten)
+- [`std::os::linux::net::TcpStreamExt::quickack`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.TcpStreamExt.html#tymethod.quickack)
+- [`std::os::linux::net::TcpStreamExt::set_quickack`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.TcpStreamExt.html#tymethod.set_quickack)
+
+These previously stable APIs are now stable in const contexts:
+
+- [`<[T; N]>::as_mut_slice`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.as_mut_slice)
+- [`<[u8]>::eq_ignore_ascii_case`](https://doc.rust-lang.org/stable/std/primitive.slice.html#impl-%5Bu8%5D/method.eq_ignore_ascii_case)
+- [`str::eq_ignore_ascii_case`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-str/method.eq_ignore_ascii_case)
+
+
+
+
+Cargo
+-----
+- [`cargo fix` and `cargo clippy --fix` now default to the same Cargo target selection as other build commands.](https://github.com/rust-lang/cargo/pull/15192/) Previously it would apply to all targets (like binaries, examples, tests, etc.). The `--edition` flag still applies to all targets.
+- [Stabilize doctest-xcompile.](https://github.com/rust-lang/cargo/pull/15462/) Doctests are now tested when cross-compiling. Just like other tests, it will use the [`runner` setting](https://doc.rust-lang.org/cargo/reference/config.html#targettriplerunner) to run the tests. If you need to disable tests for a target, you can use the [ignore doctest attribute](https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html#ignoring-targets) to specify the targets to ignore.
+
+
+
+
+Rustdoc
+-----
+- [On mobile, make the sidebar full width and linewrap](https://github.com/rust-lang/rust/pull/139831). This makes long section and item names much easier to deal with on mobile.
+
+
+
+
+Compatibility Notes
+-------------------
+- [Make `missing_fragment_specifier` an unconditional error](https://github.com/rust-lang/rust/pull/128425)
+- [Enabling the `neon` target feature on `aarch64-unknown-none-softfloat` causes a warning](https://github.com/rust-lang/rust/pull/135160) because mixing code with and without that target feature is not properly supported by LLVM
+- [Sized Hierarchy: Part I](https://github.com/rust-lang/rust/pull/137944)
+ - Introduces a small breaking change affecting `?Sized` bounds on impls on recursive types which contain associated type projections. It is not expected to affect any existing published crates. Can be fixed by refactoring the involved types or opting into the `sized_hierarchy` unstable feature. See the [FCP report](https://github.com/rust-lang/rust/pull/137944#issuecomment-2912207485) for a code example.
+- The warn-by-default `elided_named_lifetimes` lint is [superseded by the warn-by-default `mismatched_lifetime_syntaxes` lint.](https://github.com/rust-lang/rust/pull/138677)
+- [Error on recursive opaque types earlier in the type checker](https://github.com/rust-lang/rust/pull/139419)
+- [Type inference side effects from requiring element types of array repeat expressions are `Copy` are now only available at the end of type checking](https://github.com/rust-lang/rust/pull/139635)
+- [The deprecated accidentally-stable `std::intrinsics::{copy,copy_nonoverlapping,write_bytes}` are now proper intrinsics](https://github.com/rust-lang/rust/pull/139916). There are no debug assertions guarding against UB, and they cannot be coerced to function pointers.
+- [Remove long-deprecated `std::intrinsics::drop_in_place`](https://github.com/rust-lang/rust/pull/140151)
+- [Make well-formedness predicates no longer coinductive](https://github.com/rust-lang/rust/pull/140208)
+- [Remove hack when checking impl method compatibility](https://github.com/rust-lang/rust/pull/140557)
+- [Remove unnecessary type inference due to built-in trait object impls](https://github.com/rust-lang/rust/pull/141352)
+- [Lint against "stdcall", "fastcall", and "cdecl" on non-x86-32 targets](https://github.com/rust-lang/rust/pull/141435)
+- [Future incompatibility warnings relating to the never type (`!`) are now reported in dependencies](https://github.com/rust-lang/rust/pull/141937)
+- [Ensure `std::ptr::copy_*` intrinsics also perform the static self-init checks](https://github.com/rust-lang/rust/pull/142575)
+- [`extern "C"` functions on the `wasm32-unknown-unknown` target now have a standards compliant ABI](https://blog.rust-lang.org/2025/04/04/c-abi-changes-for-wasm32-unknown-unknown/)
+
+
+
+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.
+
+- [Correctly un-remap compiler sources paths with the `rustc-dev` component](https://github.com/rust-lang/rust/pull/142377)
+
+
Version 1.88.0 (2025-06-26)
==========================
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 1245d4897547..fb42cfea30b4 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -98,7 +98,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
let expr_hir_id = self.lower_node_id(e.id);
- self.lower_attrs(expr_hir_id, &e.attrs, e.span);
+ let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span);
let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
@@ -232,10 +232,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
*fn_arg_span,
),
None => self.lower_expr_closure(
+ attrs,
binder,
*capture_clause,
e.id,
- expr_hir_id,
*constness,
*movability,
fn_decl,
@@ -1052,10 +1052,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_expr_closure(
&mut self,
+ attrs: &[rustc_hir::Attribute],
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
- closure_hir_id: hir::HirId,
constness: Const,
movability: Movability,
decl: &FnDecl,
@@ -1067,15 +1067,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
- let mut coroutine_kind = if this
- .attrs
- .get(&closure_hir_id.local_id)
- .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
- {
- Some(hir::CoroutineKind::Coroutine(Movability::Movable))
- } else {
- None
- };
+
+ let mut coroutine_kind = find_attr!(attrs, AttributeKind::Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
+
// FIXME(contracts): Support contracts on closures?
let body_id = this.lower_fn_body(decl, None, |this| {
this.coroutine_kind = coroutine_kind;
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 42f3569f0f1e..53e64439afc6 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -40,7 +40,7 @@ ast_passes_auto_generic = auto traits cannot have generic parameters
ast_passes_auto_items = auto traits cannot have associated items
.label = {ast_passes_auto_items}
- .suggestion = remove these associated items
+ .suggestion = remove the associated items
ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
.label = {ast_passes_auto_super_lifetime}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index ae482ceb9b72..1c1c5f82f3ef 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -699,19 +699,23 @@ impl<'a> AstValidator<'a> {
}
}
- fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
+ fn deny_super_traits(&self, bounds: &GenericBounds, ident: Span) {
if let [.., last] = &bounds[..] {
- let span = ident_span.shrink_to_hi().to(last.span());
- self.dcx().emit_err(errors::AutoTraitBounds { span, ident: ident_span });
+ let span = bounds.iter().map(|b| b.span()).collect();
+ let removal = ident.shrink_to_hi().to(last.span());
+ self.dcx().emit_err(errors::AutoTraitBounds { span, removal, ident });
}
}
- fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
+ fn deny_where_clause(&self, where_clause: &WhereClause, ident: Span) {
if !where_clause.predicates.is_empty() {
// FIXME: The current diagnostic is misleading since it only talks about
// super trait and lifetime bounds while we should just say “bounds”.
- self.dcx()
- .emit_err(errors::AutoTraitBounds { span: where_clause.span, ident: ident_span });
+ self.dcx().emit_err(errors::AutoTraitBounds {
+ span: vec![where_clause.span],
+ removal: where_clause.span,
+ ident,
+ });
}
}
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 8b5873a3ef37..60f47490f12a 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -344,7 +344,7 @@ pub(crate) struct ModuleNonAscii {
#[diag(ast_passes_auto_generic, code = E0567)]
pub(crate) struct AutoTraitGeneric {
#[primary_span]
- #[suggestion(code = "", applicability = "machine-applicable")]
+ #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
pub span: Span,
#[label]
pub ident: Span,
@@ -354,8 +354,9 @@ pub(crate) struct AutoTraitGeneric {
#[diag(ast_passes_auto_super_lifetime, code = E0568)]
pub(crate) struct AutoTraitBounds {
#[primary_span]
- #[suggestion(code = "", applicability = "machine-applicable")]
- pub span: Span,
+ pub span: Vec,
+ #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
+ pub removal: Span,
#[label]
pub ident: Span,
}
@@ -365,7 +366,7 @@ pub(crate) struct AutoTraitBounds {
pub(crate) struct AutoTraitItems {
#[primary_span]
pub spans: Vec,
- #[suggestion(code = "", applicability = "machine-applicable")]
+ #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
pub total: Span,
#[label]
pub ident: Span,
diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs
new file mode 100644
index 000000000000..ab9330216f6c
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/body.rs
@@ -0,0 +1,15 @@
+//! Attributes that can be found in function body.
+
+use rustc_hir::attrs::AttributeKind;
+use rustc_span::{Symbol, sym};
+
+use super::{NoArgsAttributeParser, OnDuplicate};
+use crate::context::Stage;
+
+pub(crate) struct CoroutineParser;
+
+impl NoArgsAttributeParser for CoroutineParser {
+ const PATH: &[Symbol] = &[sym::coroutine];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span);
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index c574ef78bdf7..f7946ade6d2b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -26,6 +26,7 @@ use crate::parser::ArgParser;
use crate::session_diagnostics::UnusedMultiple;
pub(crate) mod allow_unstable;
+pub(crate) mod body;
pub(crate) mod cfg;
pub(crate) mod cfg_old;
pub(crate) mod codegen_attrs;
diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
index a90ed830cd1d..77b494328c70 100644
--- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
@@ -44,3 +44,55 @@ impl SingleAttributeParser for IgnoreParser {
})
}
}
+
+pub(crate) struct ShouldPanicParser;
+
+impl SingleAttributeParser for ShouldPanicParser {
+ const PATH: &[Symbol] = &[sym::should_panic];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
+ const TEMPLATE: AttributeTemplate =
+ template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason");
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option {
+ Some(AttributeKind::ShouldPanic {
+ span: cx.attr_span,
+ reason: match args {
+ ArgParser::NoArgs => None,
+ ArgParser::NameValue(name_value) => {
+ let Some(str_value) = name_value.value_as_str() else {
+ cx.expected_string_literal(
+ name_value.value_span,
+ Some(name_value.value_as_lit()),
+ );
+ return None;
+ };
+ Some(str_value)
+ }
+ ArgParser::List(list) => {
+ let Some(single) = list.single() else {
+ cx.expected_single_argument(list.span);
+ return None;
+ };
+ let Some(single) = single.meta_item() else {
+ cx.expected_name_value(single.span(), Some(sym::expected));
+ return None;
+ };
+ if !single.path().word_is(sym::expected) {
+ cx.expected_specific_argument_strings(list.span, vec!["expected"]);
+ return None;
+ }
+ let Some(nv) = single.args().name_value() else {
+ cx.expected_name_value(single.span(), Some(sym::expected));
+ return None;
+ };
+ let Some(expected) = nv.value_as_str() else {
+ cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ return None;
+ };
+ Some(expected)
+ }
+ },
+ })
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index c6599f20c2d1..80dfdffdb554 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -16,6 +16,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
use crate::attributes::allow_unstable::{
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
};
+use crate::attributes::body::CoroutineParser;
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
TargetFeatureParser, TrackCallerParser, UsedParser,
@@ -49,7 +50,7 @@ use crate::attributes::semantics::MayDangleParser;
use crate::attributes::stability::{
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
};
-use crate::attributes::test_attrs::IgnoreParser;
+use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
use crate::attributes::traits::{
AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
@@ -173,6 +174,7 @@ attribute_parsers!(
Single,
Single,
Single,
+ Single,
Single,
Single,
Single>,
@@ -184,6 +186,7 @@ attribute_parsers!(
Single>,
Single>,
Single>,
+ Single>,
Single>,
Single>,
Single>,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 321b18c9b78b..752ff8e6f586 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -19,6 +19,7 @@ use std::borrow::Cow;
use std::cell::{OnceCell, RefCell};
use std::marker::PhantomData;
use std::ops::{ControlFlow, Deref};
+use std::rc::Rc;
use borrow_set::LocalsStateAtExit;
use root_cx::BorrowCheckRootCtxt;
@@ -44,6 +45,7 @@ use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}
use rustc_mir_dataflow::move_paths::{
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
};
+use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
@@ -60,11 +62,14 @@ use crate::path_utils::*;
use crate::place_ext::PlaceExt;
use crate::places_conflict::{PlaceConflictBias, places_conflict};
use crate::polonius::PoloniusDiagnosticsContext;
-use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
+use crate::polonius::legacy::{
+ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
+};
use crate::prefixes::PrefixSet;
use crate::region_infer::RegionInferenceContext;
use crate::renumber::RegionCtxt;
use crate::session_diagnostics::VarNeedNotMut;
+use crate::type_check::MirTypeckResults;
mod borrow_set;
mod borrowck_errors;
@@ -321,7 +326,34 @@ fn do_mir_borrowck<'tcx>(
let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
- // Compute non-lexical lifetimes.
+ let location_map = Rc::new(DenseLocationMap::new(body));
+
+ let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input())
+ || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
+ let mut polonius_facts =
+ (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
+
+ // Run the MIR type-checker.
+ let MirTypeckResults {
+ constraints,
+ universal_region_relations,
+ opaque_type_values,
+ polonius_context,
+ } = type_check::type_check(
+ root_cx,
+ &infcx,
+ body,
+ &promoted,
+ universal_regions,
+ &location_table,
+ &borrow_set,
+ &mut polonius_facts,
+ &move_data,
+ Rc::clone(&location_map),
+ );
+
+ // Compute non-lexical lifetimes using the constraints computed
+ // by typechecking the MIR body.
let nll::NllOutput {
regioncx,
polonius_input,
@@ -332,14 +364,19 @@ fn do_mir_borrowck<'tcx>(
} = nll::compute_regions(
root_cx,
&infcx,
- universal_regions,
body,
- &promoted,
&location_table,
&move_data,
&borrow_set,
+ location_map,
+ universal_region_relations,
+ constraints,
+ polonius_facts,
+ polonius_context,
);
+ regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values);
+
// Dump MIR results into a file, if that is enabled. This lets us
// write unit-tests, as well as helping with debugging.
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 41f67e78930f..ca6092e70d25 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -5,7 +5,8 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
-use polonius_engine::{Algorithm, Output};
+use polonius_engine::{Algorithm, AllFacts, Output};
+use rustc_data_structures::frozen::Frozen;
use rustc_index::IndexSlice;
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
@@ -18,14 +19,16 @@ use rustc_span::sym;
use tracing::{debug, instrument};
use crate::borrow_set::BorrowSet;
+use crate::consumers::RustcFacts;
use crate::diagnostics::RegionErrors;
use crate::handle_placeholders::compute_sccs_applying_placeholder_outlives_constraints;
-use crate::polonius::PoloniusDiagnosticsContext;
use crate::polonius::legacy::{
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
};
+use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
use crate::region_infer::RegionInferenceContext;
-use crate::type_check::{self, MirTypeckResults};
+use crate::type_check::MirTypeckRegionConstraints;
+use crate::type_check::free_region_relations::UniversalRegionRelations;
use crate::universal_regions::UniversalRegions;
use crate::{
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
@@ -76,41 +79,18 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
pub(crate) fn compute_regions<'tcx>(
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
infcx: &BorrowckInferCtxt<'tcx>,
- universal_regions: UniversalRegions<'tcx>,
body: &Body<'tcx>,
- promoted: &IndexSlice>,
location_table: &PoloniusLocationTable,
move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>,
+ location_map: Rc,
+ universal_region_relations: Frozen>,
+ constraints: MirTypeckRegionConstraints<'tcx>,
+ mut polonius_facts: Option>,
+ polonius_context: Option,
) -> NllOutput<'tcx> {
- let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
- let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input())
- || is_polonius_legacy_enabled;
let polonius_output = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_output())
- || is_polonius_legacy_enabled;
- let mut polonius_facts =
- (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
-
- let location_map = Rc::new(DenseLocationMap::new(body));
-
- // Run the MIR type-checker.
- let MirTypeckResults {
- constraints,
- universal_region_relations,
- opaque_type_values,
- polonius_context,
- } = type_check::type_check(
- root_cx,
- infcx,
- body,
- promoted,
- universal_regions,
- location_table,
- borrow_set,
- &mut polonius_facts,
- move_data,
- Rc::clone(&location_map),
- );
+ || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints(
constraints,
@@ -173,8 +153,6 @@ pub(crate) fn compute_regions<'tcx>(
infcx.set_tainted_by_errors(guar);
}
- regioncx.infer_opaque_types(root_cx, infcx, opaque_type_values);
-
NllOutput {
regioncx,
polonius_input: polonius_facts.map(Box::new),
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index f5fedbf95c1c..148d0de3bab2 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -769,9 +769,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
TerminatorKind::Call { func, args, .. }
| TerminatorKind::TailCall { func, args, .. } => {
- let call_source = match term.kind {
- TerminatorKind::Call { call_source, .. } => call_source,
- TerminatorKind::TailCall { .. } => CallSource::Normal,
+ let (call_source, destination, is_diverging) = match term.kind {
+ TerminatorKind::Call { call_source, destination, target, .. } => {
+ (call_source, destination, target.is_none())
+ }
+ TerminatorKind::TailCall { .. } => {
+ (CallSource::Normal, RETURN_PLACE.into(), false)
+ }
_ => unreachable!(),
};
@@ -845,9 +849,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
- if let TerminatorKind::Call { destination, target, .. } = term.kind {
- self.check_call_dest(term, &sig, destination, target, term_location);
- }
+ self.check_call_dest(term, &sig, destination, is_diverging, term_location);
// The ordinary liveness rules will ensure that all
// regions in the type of the callee are live here. We
@@ -1874,65 +1876,61 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
term: &Terminator<'tcx>,
sig: &ty::FnSig<'tcx>,
destination: Place<'tcx>,
- target: Option,
+ is_diverging: bool,
term_location: Location,
) {
let tcx = self.tcx();
- match target {
- Some(_) => {
- let dest_ty = destination.ty(self.body, tcx).ty;
- let dest_ty = self.normalize(dest_ty, term_location);
- let category = match destination.as_local() {
- Some(RETURN_PLACE) => {
- if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) =
- self.universal_regions.defining_ty
- {
- if tcx.is_static(def_id) {
- ConstraintCategory::UseAsStatic
- } else {
- ConstraintCategory::UseAsConst
- }
- } else {
- ConstraintCategory::Return(ReturnConstraint::Normal)
- }
- }
- Some(l) if !self.body.local_decls[l].is_user_variable() => {
- ConstraintCategory::Boring
- }
- // The return type of a call is interesting for diagnostics.
- _ => ConstraintCategory::Assignment,
- };
-
- let locations = term_location.to_locations();
-
- if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) {
- span_mirbug!(
- self,
- term,
- "call dest mismatch ({:?} <- {:?}): {:?}",
- dest_ty,
- sig.output(),
- terr
- );
- }
-
- // When `unsized_fn_params` is not enabled,
- // this check is done at `check_local`.
- if self.unsized_feature_enabled() {
- let span = term.source_info.span;
- self.ensure_place_sized(dest_ty, span);
- }
+ if is_diverging {
+ // The signature in this call can reference region variables,
+ // so erase them before calling a query.
+ let output_ty = self.tcx().erase_regions(sig.output());
+ if !output_ty
+ .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
+ {
+ span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
}
- None => {
- // The signature in this call can reference region variables,
- // so erase them before calling a query.
- let output_ty = self.tcx().erase_regions(sig.output());
- if !output_ty.is_privately_uninhabited(
- self.tcx(),
- self.infcx.typing_env(self.infcx.param_env),
- ) {
- span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
+ } else {
+ let dest_ty = destination.ty(self.body, tcx).ty;
+ let dest_ty = self.normalize(dest_ty, term_location);
+ let category = match destination.as_local() {
+ Some(RETURN_PLACE) => {
+ if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) =
+ self.universal_regions.defining_ty
+ {
+ if tcx.is_static(def_id) {
+ ConstraintCategory::UseAsStatic
+ } else {
+ ConstraintCategory::UseAsConst
+ }
+ } else {
+ ConstraintCategory::Return(ReturnConstraint::Normal)
+ }
}
+ Some(l) if !self.body.local_decls[l].is_user_variable() => {
+ ConstraintCategory::Boring
+ }
+ // The return type of a call is interesting for diagnostics.
+ _ => ConstraintCategory::Assignment,
+ };
+
+ let locations = term_location.to_locations();
+
+ if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) {
+ span_mirbug!(
+ self,
+ term,
+ "call dest mismatch ({:?} <- {:?}): {:?}",
+ dest_ty,
+ sig.output(),
+ terr
+ );
+ }
+
+ // When `unsized_fn_params` is not enabled,
+ // this check is done at `check_local`.
+ if self.unsized_feature_enabled() {
+ let span = term.source_info.span;
+ self.ensure_place_sized(dest_ty, span);
}
}
}
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index ba3d8368b2a0..7b57c02b1972 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -5,10 +5,13 @@ use std::assert_matches::assert_matches;
use std::iter;
use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents};
+use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents};
use rustc_ast_pretty::pprust;
+use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, Diag, Level};
use rustc_expand::base::*;
+use rustc_hir::Attribute;
+use rustc_hir::attrs::AttributeKind;
use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Ident, Span, Symbol, sym};
use thin_vec::{ThinVec, thin_vec};
use tracing::debug;
@@ -473,39 +476,19 @@ fn should_ignore_message(i: &ast::Item) -> Option {
}
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
- match attr::find_by_name(&i.attrs, sym::should_panic) {
- Some(attr) => {
- match attr.meta_item_list() {
- // Handle #[should_panic(expected = "foo")]
- Some(list) => {
- let msg = list
- .iter()
- .find(|mi| mi.has_name(sym::expected))
- .and_then(|mi| mi.meta_item())
- .and_then(|mi| mi.value_str());
- if list.len() != 1 || msg.is_none() {
- cx.dcx()
- .struct_span_warn(
- attr.span,
- "argument must be of the form: \
- `expected = \"error message\"`",
- )
- .with_note(
- "errors in this attribute were erroneously \
- allowed and will become a hard error in a \
- future release",
- )
- .emit();
- ShouldPanic::Yes(None)
- } else {
- ShouldPanic::Yes(msg)
- }
- }
- // Handle #[should_panic] and #[should_panic = "expected"]
- None => ShouldPanic::Yes(attr.value_str()),
- }
- }
- None => ShouldPanic::No,
+ if let Some(Attribute::Parsed(AttributeKind::ShouldPanic { reason, .. })) =
+ AttributeParser::parse_limited(
+ cx.sess,
+ &i.attrs,
+ sym::should_panic,
+ i.span,
+ i.node_id(),
+ None,
+ )
+ {
+ ShouldPanic::Yes(reason)
+ } else {
+ ShouldPanic::No
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index a04cfa272376..bec546badc9c 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -310,7 +310,10 @@ fn data_id_for_static(
// `extern_with_linkage_foo` will instead be initialized to
// zero.
- let ref_name = format!("_rust_extern_with_linkage_{}", symbol_name);
+ let ref_name = format!(
+ "_rust_extern_with_linkage_{:016x}_{symbol_name}",
+ tcx.stable_crate_id(LOCAL_CRATE)
+ );
let ref_data_id = module.declare_data(&ref_name, Linkage::Local, false, false).unwrap();
let mut data = DataDescription::new();
data.set_align(align);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 4ff5773a06cb..ed40901ac9b8 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -969,7 +969,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = amount.layout();
match layout.ty.kind() {
- ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
+ ty::Uint(_) | ty::Int(_) => {}
_ => {
report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
return Ok(());
@@ -982,7 +982,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let old =
fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount);
- let old = CValue::by_val(old, layout);
+ let old = CValue::by_val(old, ret.layout());
ret.write_cvalue(fx, old);
}
sym::atomic_xsub => {
@@ -991,7 +991,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = amount.layout();
match layout.ty.kind() {
- ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
+ ty::Uint(_) | ty::Int(_) => {}
_ => {
report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
return Ok(());
@@ -1004,7 +1004,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let old =
fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount);
- let old = CValue::by_val(old, layout);
+ let old = CValue::by_val(old, ret.layout());
ret.write_cvalue(fx, old);
}
sym::atomic_and => {
@@ -1013,7 +1013,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = src.layout();
match layout.ty.kind() {
- ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
+ ty::Uint(_) | ty::Int(_) => {}
_ => {
report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
return Ok(());
@@ -1025,7 +1025,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::And, ptr, src);
- let old = CValue::by_val(old, layout);
+ let old = CValue::by_val(old, ret.layout());
ret.write_cvalue(fx, old);
}
sym::atomic_or => {
@@ -1034,7 +1034,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = src.layout();
match layout.ty.kind() {
- ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
+ ty::Uint(_) | ty::Int(_) => {}
_ => {
report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
return Ok(());
@@ -1046,7 +1046,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Or, ptr, src);
- let old = CValue::by_val(old, layout);
+ let old = CValue::by_val(old, ret.layout());
ret.write_cvalue(fx, old);
}
sym::atomic_xor => {
@@ -1055,7 +1055,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = src.layout();
match layout.ty.kind() {
- ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
+ ty::Uint(_) | ty::Int(_) => {}
_ => {
report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
return Ok(());
@@ -1067,7 +1067,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Xor, ptr, src);
- let old = CValue::by_val(old, layout);
+ let old = CValue::by_val(old, ret.layout());
ret.write_cvalue(fx, old);
}
sym::atomic_nand => {
@@ -1076,7 +1076,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = src.layout();
match layout.ty.kind() {
- ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
+ ty::Uint(_) | ty::Int(_) => {}
_ => {
report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
return Ok(());
@@ -1088,7 +1088,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Nand, ptr, src);
- let old = CValue::by_val(old, layout);
+ let old = CValue::by_val(old, ret.layout());
ret.write_cvalue(fx, old);
}
sym::atomic_max => {
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 34ade3d025f8..f7a7a3f8c7e3 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1671,6 +1671,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
dst: RValue<'gcc>,
src: RValue<'gcc>,
order: AtomicOrdering,
+ ret_ptr: bool,
) -> RValue<'gcc> {
let size = get_maybe_pointer_size(src);
let name = match op {
@@ -1698,6 +1699,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let atomic_function = self.context.get_builtin_function(name);
let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+ // FIXME: If `ret_ptr` is true and `src` is an integer, we should really tell GCC
+ // that this is a pointer operation that needs to preserve provenance -- but like LLVM,
+ // GCC does not currently seems to support that.
let void_ptr_type = self.context.new_type::<*mut ()>();
let volatile_void_ptr_type = void_ptr_type.make_volatile();
let dst = self.context.new_cast(self.location, dst, volatile_void_ptr_type);
@@ -1705,7 +1709,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let new_src_type = atomic_function.get_param(1).to_rvalue().get_type();
let src = self.context.new_bitcast(self.location, src, new_src_type);
let res = self.context.new_call(self.location, atomic_function, &[dst, src, order]);
- self.context.new_cast(self.location, res, src.get_type())
+ let res_type = if ret_ptr { void_ptr_type } else { src.get_type() };
+ self.context.new_cast(self.location, res, res_type)
}
fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) {
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index c04c75e1b11f..873f1f1951c1 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -6,6 +6,7 @@ use rustc_codegen_ssa::traits::{
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
};
use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint,
@@ -384,8 +385,8 @@ fn check_and_apply_linkage<'gcc, 'tcx>(
// linkage and there are no definitions), then
// `extern_with_linkage_foo` will instead be initialized to
// zero.
- let mut real_name = "_rust_extern_with_linkage_".to_string();
- real_name.push_str(sym);
+ let real_name =
+ format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE));
let global2 = cx.define_global(&real_name, gcc_type, is_tls, attrs.link_section);
// TODO(antoyo): set linkage.
let value = cx.const_ptrcast(global1.get_address(None), gcc_type);
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index da2a153d819f..32cdef075e76 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1327,15 +1327,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
&mut self,
op: rustc_codegen_ssa::common::AtomicRmwBinOp,
dst: &'ll Value,
- mut src: &'ll Value,
+ src: &'ll Value,
order: rustc_middle::ty::AtomicOrdering,
+ ret_ptr: bool,
) -> &'ll Value {
- // The only RMW operation that LLVM supports on pointers is compare-exchange.
- let requires_cast_to_int = self.val_ty(src) == self.type_ptr()
- && op != rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXchg;
- if requires_cast_to_int {
- src = self.ptrtoint(src, self.type_isize());
- }
+ // FIXME: If `ret_ptr` is true and `src` is not a pointer, we *should* tell LLVM that the
+ // LHS is a pointer and the operation should be provenance-preserving, but LLVM does not
+ // currently support that (https://github.com/llvm/llvm-project/issues/120837).
let mut res = unsafe {
llvm::LLVMBuildAtomicRMW(
self.llbuilder,
@@ -1346,7 +1344,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
llvm::False, // SingleThreaded
)
};
- if requires_cast_to_int {
+ if ret_ptr && self.val_ty(res) != self.type_ptr() {
res = self.inttoptr(res, self.type_ptr());
}
res
@@ -1886,48 +1884,4 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
) {
self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]);
}
-
- /// Emits a call to `llvm.instrprof.mcdc.parameters`.
- ///
- /// This doesn't produce any code directly, but is used as input by
- /// the LLVM pass that handles coverage instrumentation.
- ///
- /// (See clang's [`CodeGenPGO::emitMCDCParameters`] for comparison.)
- ///
- /// [`CodeGenPGO::emitMCDCParameters`]:
- /// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124
- #[instrument(level = "debug", skip(self))]
- pub(crate) fn mcdc_parameters(
- &mut self,
- fn_name: &'ll Value,
- hash: &'ll Value,
- bitmap_bits: &'ll Value,
- ) {
- self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]);
- }
-
- #[instrument(level = "debug", skip(self))]
- pub(crate) fn mcdc_tvbitmap_update(
- &mut self,
- fn_name: &'ll Value,
- hash: &'ll Value,
- bitmap_index: &'ll Value,
- mcdc_temp: &'ll Value,
- ) {
- let args = &[fn_name, hash, bitmap_index, mcdc_temp];
- self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args);
- }
-
- #[instrument(level = "debug", skip(self))]
- pub(crate) fn mcdc_condbitmap_reset(&mut self, mcdc_temp: &'ll Value) {
- self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
- }
-
- #[instrument(level = "debug", skip(self))]
- pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) {
- let align = self.tcx.data_layout.i32_align.abi;
- let current_tv_index = self.load(self.cx.type_i32(), mcdc_temp, align);
- let new_tv_index = self.add(current_tv_index, cond_index);
- self.store(new_tv_index, mcdc_temp, align);
- }
}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 0b96b63bc857..6b06daf3477f 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -5,7 +5,7 @@ use rustc_codegen_ssa::common;
use rustc_codegen_ssa::traits::*;
use rustc_hir::LangItem;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar,
@@ -191,8 +191,8 @@ fn check_and_apply_linkage<'ll, 'tcx>(
// linkage and there are no definitions), then
// `extern_with_linkage_foo` will instead be initialized to
// zero.
- let mut real_name = "_rust_extern_with_linkage_".to_string();
- real_name.push_str(sym);
+ let real_name =
+ format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE));
let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
span: cx.tcx.def_span(def_id),
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index f6000e728400..a4b60d420f3f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -73,48 +73,6 @@ pub(crate) struct CounterExpression {
pub(crate) rhs: Counter,
}
-pub(crate) mod mcdc {
- use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo};
-
- /// Must match the layout of `LLVMRustMCDCDecisionParameters`.
- #[repr(C)]
- #[derive(Clone, Copy, Debug, Default)]
- pub(crate) struct DecisionParameters {
- bitmap_idx: u32,
- num_conditions: u16,
- }
-
- type LLVMConditionId = i16;
-
- /// Must match the layout of `LLVMRustMCDCBranchParameters`.
- #[repr(C)]
- #[derive(Clone, Copy, Debug, Default)]
- pub(crate) struct BranchParameters {
- condition_id: LLVMConditionId,
- condition_ids: [LLVMConditionId; 2],
- }
-
- impl From for BranchParameters {
- fn from(value: ConditionInfo) -> Self {
- let to_llvm_cond_id = |cond_id: Option| {
- cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1)
- };
- let ConditionInfo { condition_id, true_next_id, false_next_id } = value;
- Self {
- condition_id: to_llvm_cond_id(Some(condition_id)),
- condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)],
- }
- }
- }
-
- impl From for DecisionParameters {
- fn from(info: DecisionInfo) -> Self {
- let DecisionInfo { bitmap_idx, num_conditions } = info;
- Self { bitmap_idx, num_conditions }
- }
- }
-}
-
/// A span of source code coordinates to be embedded in coverage metadata.
///
/// Must match the layout of `LLVMRustCoverageSpan`.
@@ -148,26 +106,14 @@ pub(crate) struct Regions {
pub(crate) code_regions: Vec,
pub(crate) expansion_regions: Vec,
pub(crate) branch_regions: Vec,
- pub(crate) mcdc_branch_regions: Vec,
- pub(crate) mcdc_decision_regions: Vec,
}
impl Regions {
/// Returns true if none of this structure's tables contain any regions.
pub(crate) fn has_no_regions(&self) -> bool {
- let Self {
- code_regions,
- expansion_regions,
- branch_regions,
- mcdc_branch_regions,
- mcdc_decision_regions,
- } = self;
+ let Self { code_regions, expansion_regions, branch_regions } = self;
- code_regions.is_empty()
- && expansion_regions.is_empty()
- && branch_regions.is_empty()
- && mcdc_branch_regions.is_empty()
- && mcdc_decision_regions.is_empty()
+ code_regions.is_empty() && expansion_regions.is_empty() && branch_regions.is_empty()
}
}
@@ -195,21 +141,3 @@ pub(crate) struct BranchRegion {
pub(crate) true_counter: Counter,
pub(crate) false_counter: Counter,
}
-
-/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`.
-#[derive(Clone, Debug)]
-#[repr(C)]
-pub(crate) struct MCDCBranchRegion {
- pub(crate) cov_span: CoverageSpan,
- pub(crate) true_counter: Counter,
- pub(crate) false_counter: Counter,
- pub(crate) mcdc_branch_params: mcdc::BranchParameters,
-}
-
-/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`.
-#[derive(Clone, Debug)]
-#[repr(C)]
-pub(crate) struct MCDCDecisionRegion {
- pub(crate) cov_span: CoverageSpan,
- pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
-}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
index 907d6d41a1fb..bc4f6bb6a82b 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
@@ -63,13 +63,7 @@ pub(crate) fn write_function_mappings_to_buffer(
expressions: &[ffi::CounterExpression],
regions: &ffi::Regions,
) -> Vec {
- let ffi::Regions {
- code_regions,
- expansion_regions,
- branch_regions,
- mcdc_branch_regions,
- mcdc_decision_regions,
- } = regions;
+ let ffi::Regions { code_regions, expansion_regions, branch_regions } = regions;
// SAFETY:
// - All types are FFI-compatible and have matching representations in Rust/C++.
@@ -87,10 +81,6 @@ pub(crate) fn write_function_mappings_to_buffer(
expansion_regions.len(),
branch_regions.as_ptr(),
branch_regions.len(),
- mcdc_branch_regions.as_ptr(),
- mcdc_branch_regions.len(),
- mcdc_decision_regions.as_ptr(),
- mcdc_decision_regions.len(),
buffer,
)
})
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index fd1e7f7f160a..e0da8d368762 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -140,8 +140,6 @@ fn fill_region_tables<'tcx>(
code_regions,
expansion_regions: _, // FIXME(Zalathar): Fill out support for expansion regions
branch_regions,
- mcdc_branch_regions,
- mcdc_decision_regions,
} = &mut covfun.regions;
// For each counter/region pair in this function+file, convert it to a
@@ -161,20 +159,6 @@ fn fill_region_tables<'tcx>(
false_counter: counter_for_bcb(false_bcb),
});
}
- MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params } => {
- mcdc_branch_regions.push(ffi::MCDCBranchRegion {
- cov_span,
- true_counter: counter_for_bcb(true_bcb),
- false_counter: counter_for_bcb(false_bcb),
- mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
- });
- }
- MappingKind::MCDCDecision(mcdc_decision_params) => {
- mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
- cov_span,
- mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
- });
- }
}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 119237abd6b8..6a58f495c9d8 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,11 +1,10 @@
use std::cell::{OnceCell, RefCell};
use std::ffi::{CStr, CString};
-use rustc_abi::Size;
use rustc_codegen_ssa::traits::{
- BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
+ ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
};
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::fx::FxIndexMap;
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance;
use tracing::{debug, instrument};
@@ -28,34 +27,13 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> {
/// symbol name, and `llvm-cov` will exit fatally if it can't resolve that
/// hash back to an entry in the binary's `__llvm_prf_names` linker section.
pub(crate) pgo_func_name_var_map: RefCell, &'ll llvm::Value>>,
- pub(crate) mcdc_condition_bitmap_map: RefCell, Vec<&'ll llvm::Value>>>,
covfun_section_name: OnceCell,
}
impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
pub(crate) fn new() -> Self {
- Self {
- pgo_func_name_var_map: Default::default(),
- mcdc_condition_bitmap_map: Default::default(),
- covfun_section_name: Default::default(),
- }
- }
-
- /// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is
- /// called condition bitmap. In order to handle nested decisions, several condition bitmaps can
- /// be allocated for a function body. These values are named `mcdc.addr.{i}` and are a 32-bit
- /// integers. They respectively hold the condition bitmaps for decisions with a depth of `i`.
- fn try_get_mcdc_condition_bitmap(
- &self,
- instance: &Instance<'tcx>,
- decision_depth: u16,
- ) -> Option<&'ll llvm::Value> {
- self.mcdc_condition_bitmap_map
- .borrow()
- .get(instance)
- .and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
- .copied() // Dereference Option<&&Value> to Option<&Value>
+ Self { pgo_func_name_var_map: Default::default(), covfun_section_name: Default::default() }
}
/// Returns the list of instances considered "used" in this CGU, as
@@ -105,38 +83,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
}
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
- fn init_coverage(&mut self, instance: Instance<'tcx>) {
- let Some(function_coverage_info) =
- self.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
- else {
- return;
- };
-
- // If there are no MC/DC bitmaps to set up, return immediately.
- if function_coverage_info.mcdc_bitmap_bits == 0 {
- return;
- }
-
- let fn_name = self.ensure_pgo_func_name_var(instance);
- let hash = self.const_u64(function_coverage_info.function_source_hash);
- let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
- self.mcdc_parameters(fn_name, hash, bitmap_bits);
-
- // Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps.
- let mut cond_bitmaps = vec![];
- for i in 0..function_coverage_info.mcdc_num_condition_bitmaps {
- // MC/DC intrinsics will perform loads/stores that use the ABI default
- // alignment for i32, so our variable declaration should match.
- let align = self.tcx.data_layout.i32_align.abi;
- let cond_bitmap = self.alloca(Size::from_bytes(4), align);
- llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes());
- self.store(self.const_i32(0), cond_bitmap, align);
- cond_bitmaps.push(cond_bitmap);
- }
-
- self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps);
- }
-
#[instrument(level = "debug", skip(self))]
fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
// Our caller should have already taken care of inlining subtleties,
@@ -153,7 +99,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
// When that happens, we currently just discard those statements, so
// the corresponding code will be undercounted.
// FIXME(Zalathar): Find a better solution for mixed-coverage builds.
- let Some(coverage_cx) = &bx.cx.coverage_cx else { return };
+ let Some(_coverage_cx) = &bx.cx.coverage_cx else { return };
let Some(function_coverage_info) =
bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
@@ -185,30 +131,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
// If a BCB doesn't have an associated physical counter, there's nothing to codegen.
CoverageKind::VirtualCounter { .. } => {}
- CoverageKind::CondBitmapUpdate { index, decision_depth } => {
- let cond_bitmap = coverage_cx
- .try_get_mcdc_condition_bitmap(&instance, decision_depth)
- .expect("mcdc cond bitmap should have been allocated for updating");
- let cond_index = bx.const_i32(index as i32);
- bx.mcdc_condbitmap_update(cond_index, cond_bitmap);
- }
- CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
- let cond_bitmap =
- coverage_cx.try_get_mcdc_condition_bitmap(&instance, decision_depth).expect(
- "mcdc cond bitmap should have been allocated for merging \
- into the global bitmap",
- );
- assert!(
- bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits,
- "bitmap index of the decision out of range"
- );
-
- let fn_name = bx.ensure_pgo_func_name_var(instance);
- let hash = bx.const_u64(function_coverage_info.function_source_hash);
- let bitmap_index = bx.const_u32(bitmap_idx);
- bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
- bx.mcdc_condbitmap_reset(cond_bitmap);
- }
}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 2443194ff483..75d3d27f74e1 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2056,10 +2056,6 @@ unsafe extern "C" {
NumExpansionRegions: size_t,
BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
NumBranchRegions: size_t,
- MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,
- NumMCDCBranchRegions: size_t,
- MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion,
- NumMCDCDecisionRegions: size_t,
BufferOut: &RustString,
);
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 53899da183a3..28d2100f478c 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -262,6 +262,15 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, // only existed in 18
("arm", "fp16") => Some(LLVMFeature::new("fullfp16")),
+ // NVPTX targets added in LLVM 20
+ ("nvptx64", "sm_100") if get_version().0 < 20 => None,
+ ("nvptx64", "sm_100a") if get_version().0 < 20 => None,
+ ("nvptx64", "sm_101") if get_version().0 < 20 => None,
+ ("nvptx64", "sm_101a") if get_version().0 < 20 => None,
+ ("nvptx64", "sm_120") if get_version().0 < 20 => None,
+ ("nvptx64", "sm_120a") if get_version().0 < 20 => None,
+ ("nvptx64", "ptx86") if get_version().0 < 20 => None,
+ ("nvptx64", "ptx87") if get_version().0 < 20 => None,
// Filter out features that are not supported by the current LLVM version
("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq")
if get_version().0 < 20 =>
@@ -324,15 +333,12 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option TargetConfig {
- // Add base features for the target.
- // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
- // The reason is that if LLVM considers a feature implied but we do not, we don't want that to
- // show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of
- // the target CPU, that is still expanded to target features (with all their implied features)
- // by LLVM.
let target_machine = create_informational_target_machine(sess, true);
let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
+ // This closure determines whether the target CPU has the feature according to LLVM. We do
+ // *not* consider the `-Ctarget-feature`s here, as that will be handled later in
+ // `cfg_target_feature`.
if let Some(feat) = to_llvm_features(sess, feature) {
// All the LLVM features this expands to must be enabled.
for llvm_feature in feat {
@@ -371,24 +377,25 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
let target_abi = sess.target.options.abi.as_ref();
let target_pointer_width = sess.target.pointer_width;
let version = get_version();
+ let lt_20_1_1 = version < (20, 1, 1);
+ let lt_21_0_0 = version < (21, 0, 0);
cfg.has_reliable_f16 = match (target_arch, target_os) {
- // Selection failure
- ("s390x", _) => false,
- // LLVM crash without neon (now fixed)
+ // LLVM crash without neon (fixed in llvm20)
("aarch64", _)
- if !cfg.target_features.iter().any(|f| f.as_str() == "neon")
- && version < (20, 1, 1) =>
+ if !cfg.target_features.iter().any(|f| f.as_str() == "neon") && lt_20_1_1 =>
{
false
}
// Unsupported
("arm64ec", _) => false,
+ // Selection failure (fixed in llvm21)
+ ("s390x", _) if lt_21_0_0 => false,
// MinGW ABI bugs
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
// Infinite recursion
("csky", _) => false,
- ("hexagon", _) => false,
+ ("hexagon", _) if lt_21_0_0 => false, // (fixed in llvm21)
("powerpc" | "powerpc64", _) => false,
("sparc" | "sparc64", _) => false,
("wasm32" | "wasm64", _) => false,
@@ -401,9 +408,10 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
cfg.has_reliable_f128 = match (target_arch, target_os) {
// Unsupported
("arm64ec", _) => false,
- // Selection bug
- ("mips64" | "mips64r6", _) => false,
- // Selection bug
+ // Selection bug (fixed in llvm20)
+ ("mips64" | "mips64r6", _) if lt_20_1_1 => false,
+ // Selection bug . This issue is closed
+ // but basic math still does not work.
("nvptx64", _) => false,
// Unsupported https://github.com/llvm/llvm-project/issues/121122
("amdgpu", _) => false,
@@ -413,8 +421,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
// ABI unsupported
("sparc", _) => false,
// Stack alignment bug . NB: tests may
- // not fail if our compiler-builtins is linked.
- ("x86", _) => false,
+ // not fail if our compiler-builtins is linked. (fixed in llvm21)
+ ("x86", _) if lt_21_0_0 => false,
// MinGW ABI bugs
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
// There are no known problems on other platforms, so the only requirement is that symbols
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index a70d0011d161..36ad5ede7c2c 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -101,6 +101,8 @@ codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization
codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
+codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer or pointer type, found `{$ty}`
+
codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}`
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 3710625ac12d..43e1e135a666 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -69,6 +69,15 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTr
set_reuse(&mut ams.cgu_reuse_tracker);
+ if tcx.sess.opts.unstable_opts.print_mono_items
+ && let Some(data) = &ams.cgu_reuse_tracker.data
+ {
+ data.actual_reuse.items().all(|(cgu, reuse)| {
+ println!("CGU_REUSE {cgu} {reuse}");
+ true
+ });
+ }
+
ams.cgu_reuse_tracker.check_expected_reuse(tcx.sess);
});
}
diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs
index d242efaf4fd4..2f68bad1695b 100644
--- a/compiler/rustc_codegen_ssa/src/back/apple.rs
+++ b/compiler/rustc_codegen_ssa/src/back/apple.rs
@@ -17,7 +17,7 @@ mod tests;
/// The canonical name of the desired SDK for a given target.
pub(super) fn sdk_name(target: &Target) -> &'static str {
- match (&*target.os, &*target.abi) {
+ match (&*target.os, &*target.env) {
("macos", "") => "MacOSX",
("ios", "") => "iPhoneOS",
("ios", "sim") => "iPhoneSimulator",
@@ -34,7 +34,7 @@ pub(super) fn sdk_name(target: &Target) -> &'static str {
}
pub(super) fn macho_platform(target: &Target) -> u32 {
- match (&*target.os, &*target.abi) {
+ match (&*target.os, &*target.env) {
("macos", _) => object::macho::PLATFORM_MACOS,
("ios", "macabi") => object::macho::PLATFORM_MACCATALYST,
("ios", "sim") => object::macho::PLATFORM_IOSSIMULATOR,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index b69fbf61185d..6e21f54587f6 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -3026,7 +3026,7 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool
/// We need to communicate five things to the linker on Apple/Darwin targets:
/// - The architecture.
/// - The operating system (and that it's an Apple platform).
-/// - The environment / ABI.
+/// - The environment.
/// - The deployment target.
/// - The SDK version.
fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
@@ -3040,7 +3040,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
// `sess.target.arch` (`target_arch`) is not detailed enough.
let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0;
let target_os = &*sess.target.os;
- let target_abi = &*sess.target.abi;
+ let target_env = &*sess.target.env;
// The architecture name to forward to the linker.
//
@@ -3091,14 +3091,14 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
// > - visionos-simulator
// > - xros-simulator
// > - driverkit
- let platform_name = match (target_os, target_abi) {
+ let platform_name = match (target_os, target_env) {
(os, "") => os,
("ios", "macabi") => "mac-catalyst",
("ios", "sim") => "ios-simulator",
("tvos", "sim") => "tvos-simulator",
("watchos", "sim") => "watchos-simulator",
("visionos", "sim") => "visionos-simulator",
- _ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"),
+ _ => bug!("invalid OS/env combination for Apple target: {target_os}, {target_env}"),
};
let min_version = sess.apple_deployment_target().fmt_full().to_string();
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 050797354b4a..df1e91b12f90 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1805,11 +1805,18 @@ pub(crate) fn exported_symbols(
.collect();
}
- if let CrateType::ProcMacro = crate_type {
+ let mut symbols = if let CrateType::ProcMacro = crate_type {
exported_symbols_for_proc_macro_crate(tcx)
} else {
exported_symbols_for_non_proc_macro(tcx, crate_type)
+ };
+
+ if crate_type == CrateType::Dylib || crate_type == CrateType::ProcMacro {
+ let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
+ symbols.push((metadata_symbol_name, SymbolExportKind::Data));
}
+
+ symbols
}
fn exported_symbols_for_non_proc_macro(
@@ -1842,12 +1849,8 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, Symbol
let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
- let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
- vec![
- (proc_macro_decls_name, SymbolExportKind::Data),
- (metadata_symbol_name, SymbolExportKind::Data),
- ]
+ vec![(proc_macro_decls_name, SymbolExportKind::Data)]
}
pub(crate) fn linked_symbols(
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 4b4b39f53533..7e124f65324a 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId};
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::exported_symbols::{
- ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, metadata_symbol_name,
+ ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
};
use rustc_middle::query::LocalCrate;
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, Ty, TyCtxt};
@@ -289,23 +289,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>(
}));
}
- if tcx.crate_types().contains(&CrateType::Dylib)
- || tcx.crate_types().contains(&CrateType::ProcMacro)
- {
- let symbol_name = metadata_symbol_name(tcx);
- let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
-
- symbols.push((
- exported_symbol,
- SymbolExportInfo {
- level: SymbolExportLevel::C,
- kind: SymbolExportKind::Data,
- used: true,
- rustc_std_internal_symbol: false,
- },
- ));
- }
-
// Sort so we get a stable incr. comp. hash.
symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 3d787d8bdbde..af4adcd19542 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -764,6 +764,14 @@ pub enum InvalidMonomorphization<'tcx> {
ty: Ty<'tcx>,
},
+ #[diag(codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type, code = E0511)]
+ BasicIntegerOrPtrType {
+ #[primary_span]
+ span: Span,
+ name: Symbol,
+ ty: Ty<'tcx>,
+ },
+
#[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = E0511)]
BasicFloatType {
#[primary_span]
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index fc95f62b4a43..3c667b8e8820 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -92,6 +92,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let invalid_monomorphization_int_type = |ty| {
bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
};
+ let invalid_monomorphization_int_or_ptr_type = |ty| {
+ bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerOrPtrType {
+ span,
+ name,
+ ty,
+ });
+ };
let parse_atomic_ordering = |ord: ty::Value<'tcx>| {
let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf();
@@ -351,7 +358,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::atomic_load => {
let ty = fn_args.type_at(0);
if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
- invalid_monomorphization_int_type(ty);
+ invalid_monomorphization_int_or_ptr_type(ty);
return Ok(());
}
let ordering = fn_args.const_at(1).to_value();
@@ -367,7 +374,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::atomic_store => {
let ty = fn_args.type_at(0);
if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
- invalid_monomorphization_int_type(ty);
+ invalid_monomorphization_int_or_ptr_type(ty);
return Ok(());
}
let ordering = fn_args.const_at(1).to_value();
@@ -377,10 +384,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.atomic_store(val, ptr, parse_atomic_ordering(ordering), size);
return Ok(());
}
+ // These are all AtomicRMW ops
sym::atomic_cxchg | sym::atomic_cxchgweak => {
let ty = fn_args.type_at(0);
if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
- invalid_monomorphization_int_type(ty);
+ invalid_monomorphization_int_or_ptr_type(ty);
return Ok(());
}
let succ_ordering = fn_args.const_at(1).to_value();
@@ -407,7 +415,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return Ok(());
}
- // These are all AtomicRMW ops
sym::atomic_max | sym::atomic_min => {
let atom_op = if name == sym::atomic_max {
AtomicRmwBinOp::AtomicMax
@@ -420,7 +427,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let ordering = fn_args.const_at(1).to_value();
let ptr = args[0].immediate();
let val = args[1].immediate();
- bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering))
+ bx.atomic_rmw(
+ atom_op,
+ ptr,
+ val,
+ parse_atomic_ordering(ordering),
+ /* ret_ptr */ false,
+ )
} else {
invalid_monomorphization_int_type(ty);
return Ok(());
@@ -438,21 +451,44 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let ordering = fn_args.const_at(1).to_value();
let ptr = args[0].immediate();
let val = args[1].immediate();
- bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering))
+ bx.atomic_rmw(
+ atom_op,
+ ptr,
+ val,
+ parse_atomic_ordering(ordering),
+ /* ret_ptr */ false,
+ )
} else {
invalid_monomorphization_int_type(ty);
return Ok(());
}
}
- sym::atomic_xchg
- | sym::atomic_xadd
+ sym::atomic_xchg => {
+ let ty = fn_args.type_at(0);
+ let ordering = fn_args.const_at(1).to_value();
+ if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
+ let ptr = args[0].immediate();
+ let val = args[1].immediate();
+ let atomic_op = AtomicRmwBinOp::AtomicXchg;
+ bx.atomic_rmw(
+ atomic_op,
+ ptr,
+ val,
+ parse_atomic_ordering(ordering),
+ /* ret_ptr */ ty.is_raw_ptr(),
+ )
+ } else {
+ invalid_monomorphization_int_or_ptr_type(ty);
+ return Ok(());
+ }
+ }
+ sym::atomic_xadd
| sym::atomic_xsub
| sym::atomic_and
| sym::atomic_nand
| sym::atomic_or
| sym::atomic_xor => {
let atom_op = match name {
- sym::atomic_xchg => AtomicRmwBinOp::AtomicXchg,
sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd,
sym::atomic_xsub => AtomicRmwBinOp::AtomicSub,
sym::atomic_and => AtomicRmwBinOp::AtomicAnd,
@@ -462,14 +498,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => unreachable!(),
};
- let ty = fn_args.type_at(0);
- if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
- let ordering = fn_args.const_at(1).to_value();
- let ptr = args[0].immediate();
- let val = args[1].immediate();
- bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering))
+ // The type of the in-memory data.
+ let ty_mem = fn_args.type_at(0);
+ // The type of the 2nd operand, given by-value.
+ let ty_op = fn_args.type_at(1);
+
+ let ordering = fn_args.const_at(2).to_value();
+ // We require either both arguments to have the same integer type, or the first to
+ // be a pointer and the second to be `usize`.
+ if (int_type_width_signed(ty_mem, bx.tcx()).is_some() && ty_op == ty_mem)
+ || (ty_mem.is_raw_ptr() && ty_op == bx.tcx().types.usize)
+ {
+ let ptr = args[0].immediate(); // of type "pointer to `ty_mem`"
+ let val = args[1].immediate(); // of type `ty_op`
+ bx.atomic_rmw(
+ atom_op,
+ ptr,
+ val,
+ parse_atomic_ordering(ordering),
+ /* ret_ptr */ ty_mem.is_raw_ptr(),
+ )
} else {
- invalid_monomorphization_int_type(ty);
+ invalid_monomorphization_int_or_ptr_type(ty_mem);
return Ok(());
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 50d0f9107445..06873313e2ec 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -296,10 +296,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// Apply debuginfo to the newly allocated locals.
fx.debug_introduce_locals(&mut start_bx, consts_debug_info.unwrap_or_default());
- // If the backend supports coverage, and coverage is enabled for this function,
- // do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps).
- start_bx.init_coverage(instance);
-
// The builders will be created separately for each basic block at `codegen_block`.
// So drop the builder of `start_llbb` to avoid having two at the same time.
drop(start_bx);
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 5459f95c1860..d851c3329802 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -498,6 +498,35 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64);
(is_niche, tagged_discr, 0)
} else {
+ // Thanks to parameter attributes and load metadata, LLVM already knows
+ // the general valid range of the tag. It's possible, though, for there
+ // to be an impossible value *in the middle*, which those ranges don't
+ // communicate, so it's worth an `assume` to let the optimizer know.
+ // Most importantly, this means when optimizing a variant test like
+ // `SELECT(is_niche, complex, CONST) == CONST` it's ok to simplify that
+ // to `!is_niche` because the `complex` part can't possibly match.
+ //
+ // This was previously asserted on `tagged_discr` below, where the
+ // impossible value is more obvious, but that caused an intermediate
+ // value to become multi-use and thus not optimize, so instead this
+ // assumes on the original input which is always multi-use. See
+ //
+ //
+ // FIXME: If we ever get range assume operand bundles in LLVM (so we
+ // don't need the `icmp`s in the instruction stream any more), it
+ // might be worth moving this back to being on the switch argument
+ // where it's more obviously applicable.
+ if niche_variants.contains(&untagged_variant)
+ && bx.cx().sess().opts.optimize != OptLevel::No
+ {
+ let impossible = niche_start
+ .wrapping_add(u128::from(untagged_variant.as_u32()))
+ .wrapping_sub(u128::from(niche_variants.start().as_u32()));
+ let impossible = bx.cx().const_uint_big(tag_llty, impossible);
+ let ne = bx.icmp(IntPredicate::IntNE, tag, impossible);
+ bx.assume(ne);
+ }
+
// With multiple niched variants we'll have to actually compute
// the variant index from the stored tag.
//
@@ -588,20 +617,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
let untagged_variant_const =
bx.cx().const_uint(cast_to, u64::from(untagged_variant.as_u32()));
- // Thanks to parameter attributes and load metadata, LLVM already knows
- // the general valid range of the tag. It's possible, though, for there
- // to be an impossible value *in the middle*, which those ranges don't
- // communicate, so it's worth an `assume` to let the optimizer know.
- // Most importantly, this means when optimizing a variant test like
- // `SELECT(is_niche, complex, CONST) == CONST` it's ok to simplify that
- // to `!is_niche` because the `complex` part can't possibly match.
- if niche_variants.contains(&untagged_variant)
- && bx.cx().sess().opts.optimize != OptLevel::No
- {
- let ne = bx.icmp(IntPredicate::IntNE, tagged_discr, untagged_variant_const);
- bx.assume(ne);
- }
-
let discr = bx.select(is_niche, tagged_discr, untagged_variant_const);
// In principle we could insert assumes on the possible range of `discr`, but
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index d984156c674c..7e4341a82366 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -197,7 +197,10 @@ fn parse_rust_feature_flag<'a>(
/// 2nd component of the return value, respectively).
///
/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is
-/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`.
+/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`. Note that LLVM
+/// may consider features to be implied that we do not and vice-versa. We want `cfg` to be entirely
+/// consistent with Rust feature implications, and thus only consult LLVM to expand the target CPU
+/// to target features.
///
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere.
pub fn cfg_target_feature(
@@ -211,7 +214,15 @@ pub fn cfg_target_feature(
.rust_target_features()
.iter()
.filter(|(feature, _, _)| target_base_has_feature(feature))
- .map(|(feature, _, _)| Symbol::intern(feature))
+ .flat_map(|(base_feature, _, _)| {
+ // Expand the direct base feature into all transitively-implied features. Note that we
+ // cannot simply use the `implied` field of the tuple since that only contains
+ // directly-implied features.
+ //
+ // Iteration order is irrelevant because we're collecting into an `UnordSet`.
+ #[allow(rustc::potential_query_instability)]
+ sess.target.implied_target_features(base_feature).into_iter().map(|f| Symbol::intern(f))
+ })
.collect();
// Add enabled and remove disabled features.
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 4b18146863bf..f417d1a7bf72 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -548,12 +548,15 @@ pub trait BuilderMethods<'a, 'tcx>:
failure_order: AtomicOrdering,
weak: bool,
) -> (Self::Value, Self::Value);
+ /// `ret_ptr` indicates whether the return type (which is also the type `dst` points to)
+ /// is a pointer or the same type as `src`.
fn atomic_rmw(
&mut self,
op: AtomicRmwBinOp,
dst: Self::Value,
src: Self::Value,
order: AtomicOrdering,
+ ret_ptr: bool,
) -> Self::Value;
fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope);
fn set_invariant_load(&mut self, load: Self::Value);
diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
index 0b513dac5037..31482a53b6d4 100644
--- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
@@ -2,11 +2,6 @@ use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance;
pub trait CoverageInfoBuilderMethods<'tcx> {
- /// Performs any start-of-function codegen needed for coverage instrumentation.
- ///
- /// Can be a no-op in backends that don't support coverage instrumentation.
- fn init_coverage(&mut self, _instance: Instance<'tcx>) {}
-
/// Handle the MIR coverage info in a backend-specific way.
///
/// This can potentially be a no-op in backends that don't support
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 982e640fa92a..79e32dcf105c 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -142,7 +142,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|err, self_ty, trait_id| {
// FIXME(const_trait_impl): Do we need any of this on the non-const codepath?
- let trait_ref = TraitRef::from_method(tcx, trait_id, self.args);
+ let trait_ref = TraitRef::from_assoc(tcx, trait_id, self.args);
match self_ty.kind() {
Param(param_ty) => {
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index b8a653698258..a0160d1188d0 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -732,7 +732,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let tcx = *self.tcx;
let trait_def_id = tcx.trait_of_assoc(def_id).unwrap();
- let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args);
+ let virtual_trait_ref = ty::TraitRef::from_assoc(tcx, trait_def_id, virtual_instance.args);
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 3840cdf75750..8ace560d85d1 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -1,6 +1,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(bootstrap, feature(strict_overflow_ops))]
#![doc(rust_logo)]
#![feature(array_try_map)]
#![feature(assert_matches)]
@@ -10,7 +11,6 @@
#![feature(never_type)]
#![feature(rustdoc_internals)]
#![feature(slice_ptr_get)]
-#![feature(strict_overflow_ops)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(unqualified_local_imports)]
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index e6b9759819f1..2dc746754f87 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -18,7 +18,9 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
}
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
- unreachable!(); // because `::should_print_region` returns false
+ // This is reachable (via `pretty_print_dyn_existential`) even though
+ // `::should_print_region` returns false. See #144994.
+ Ok(())
}
fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 96c7ba6ed27b..5a5563c7bb2c 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1382,6 +1382,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
&mut self.long_ty_path
}
+ pub fn with_long_ty_path(mut self, long_ty_path: Option) -> Self {
+ self.long_ty_path = long_ty_path;
+ self
+ }
+
/// Most `emit_producing_guarantee` functions use this as a starting point.
fn emit_producing_nothing(mut self) {
let diag = self.take_diag();
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 84970e7c162b..0c839f94f7f1 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -409,7 +409,7 @@ pub trait Emitter {
if !redundant_span || always_backtrace {
let msg: Cow<'static, _> = match trace.kind {
ExpnKind::Macro(MacroKind::Attr, _) => {
- "this procedural macro expansion".into()
+ "this attribute macro expansion".into()
}
ExpnKind::Macro(MacroKind::Derive, _) => {
"this derive macro expansion".into()
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 5a53670c865d..1f8f3be68092 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -70,6 +70,9 @@ expand_invalid_fragment_specifier =
invalid fragment specifier `{$fragment}`
.help = {$help}
+expand_macro_args_bad_delim = macro attribute argument matchers require parentheses
+expand_macro_args_bad_delim_sugg = the delimiters should be `(` and `)`
+
expand_macro_body_stability =
macros cannot have body stability attributes
.label = invalid body stability attribute
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index fd1391a554a8..e58269991fcb 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -482,3 +482,21 @@ mod metavar_exprs {
pub key: MacroRulesNormalizedIdent,
}
}
+
+#[derive(Diagnostic)]
+#[diag(expand_macro_args_bad_delim)]
+pub(crate) struct MacroArgsBadDelim {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: MacroArgsBadDelimSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(expand_macro_args_bad_delim_sugg, applicability = "machine-applicable")]
+pub(crate) struct MacroArgsBadDelimSugg {
+ #[suggestion_part(code = "(")]
+ pub open: Span,
+ #[suggestion_part(code = ")")]
+ pub close: Span,
+}
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 7a280d671f41..5b9d56ee2bc3 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -7,29 +7,40 @@ use rustc_macros::Subdiagnostic;
use rustc_parse::parser::{Parser, Recovery, token_descr};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::SourceMap;
-use rustc_span::{ErrorGuaranteed, Ident, Span};
+use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span};
use tracing::debug;
use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx};
use crate::expand::{AstFragmentKind, parse_ast_fragment};
use crate::mbe::macro_parser::ParseResult::*;
use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser};
-use crate::mbe::macro_rules::{Tracker, try_match_macro};
+use crate::mbe::macro_rules::{Tracker, try_match_macro, try_match_macro_attr};
pub(super) fn failed_to_match_macro(
psess: &ParseSess,
sp: Span,
def_span: Span,
name: Ident,
- arg: TokenStream,
+ attr_args: Option<&TokenStream>,
+ body: &TokenStream,
rules: &[MacroRule],
) -> (Span, ErrorGuaranteed) {
debug!("failed to match macro");
+ let def_head_span = if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
+ psess.source_map().guess_head_span(def_span)
+ } else {
+ DUMMY_SP
+ };
+
// An error occurred, try the expansion again, tracking the expansion closely for better
// diagnostics.
let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
- let try_success_result = try_match_macro(psess, name, &arg, rules, &mut tracker);
+ let try_success_result = if let Some(attr_args) = attr_args {
+ try_match_macro_attr(psess, name, attr_args, body, rules, &mut tracker)
+ } else {
+ try_match_macro(psess, name, body, rules, &mut tracker)
+ };
if try_success_result.is_ok() {
// Nonterminal parser recovery might turn failed matches into successful ones,
@@ -47,6 +58,18 @@ pub(super) fn failed_to_match_macro(
let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
else {
+ // FIXME: we should report this at macro resolution time, as we do for
+ // `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a
+ // Def.
+ if attr_args.is_none() && !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) {
+ let msg = format!("macro has no rules for function-like invocation `{name}!`");
+ let mut err = psess.dcx().struct_span_err(sp, msg);
+ if !def_head_span.is_dummy() {
+ let msg = "this macro has no rules for function-like invocation";
+ err.span_label(def_head_span, msg);
+ }
+ return (sp, err.emit());
+ }
return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
};
@@ -54,8 +77,8 @@ pub(super) fn failed_to_match_macro(
let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None));
err.span_label(span, label);
- if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
- err.span_label(psess.source_map().guess_head_span(def_span), "when calling this macro");
+ if !def_head_span.is_dummy() {
+ err.span_label(def_head_span, "when calling this macro");
}
annotate_doc_comment(&mut err, psess.source_map(), span);
@@ -79,13 +102,16 @@ pub(super) fn failed_to_match_macro(
}
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
- if let Some((arg, comma_span)) = arg.add_comma() {
+ if attr_args.is_none()
+ && let Some((body, comma_span)) = body.add_comma()
+ {
for rule in rules {
- let parser = parser_from_cx(psess, arg.clone(), Recovery::Allowed);
+ let MacroRule::Func { lhs, .. } = rule else { continue };
+ let parser = parser_from_cx(psess, body.clone(), Recovery::Allowed);
let mut tt_parser = TtParser::new(name);
if let Success(_) =
- tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, &mut NoopTracker)
+ tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker)
{
if comma_span.is_dummy() {
err.note("you might be missing a comma");
@@ -116,13 +142,13 @@ struct CollectTrackerAndEmitter<'dcx, 'matcher> {
struct BestFailure {
token: Token,
- position_in_tokenstream: u32,
+ position_in_tokenstream: (bool, u32),
msg: &'static str,
remaining_matcher: MatcherLoc,
}
impl BestFailure {
- fn is_better_position(&self, position: u32) -> bool {
+ fn is_better_position(&self, position: (bool, u32)) -> bool {
position > self.position_in_tokenstream
}
}
@@ -142,7 +168,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match
}
}
- fn after_arm(&mut self, result: &NamedParseResult) {
+ fn after_arm(&mut self, in_body: bool, result: &NamedParseResult) {
match result {
Success(_) => {
// Nonterminal parser recovery might turn failed matches into successful ones,
@@ -155,14 +181,15 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match
Failure((token, approx_position, msg)) => {
debug!(?token, ?msg, "a new failure of an arm");
+ let position_in_tokenstream = (in_body, *approx_position);
if self
.best_failure
.as_ref()
- .is_none_or(|failure| failure.is_better_position(*approx_position))
+ .is_none_or(|failure| failure.is_better_position(position_in_tokenstream))
{
self.best_failure = Some(BestFailure {
token: *token,
- position_in_tokenstream: *approx_position,
+ position_in_tokenstream,
msg,
remaining_matcher: self
.remaining_matcher
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index bbdff866feba..25987a503663 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -193,15 +193,19 @@ struct MacroState<'a> {
/// Arguments:
/// - `psess` is used to emit diagnostics and lints
/// - `node_id` is used to emit lints
-/// - `lhs` and `rhs` represent the rule
+/// - `args`, `lhs`, and `rhs` represent the rule
pub(super) fn check_meta_variables(
psess: &ParseSess,
node_id: NodeId,
+ args: Option<&TokenTree>,
lhs: &TokenTree,
rhs: &TokenTree,
) -> Result<(), ErrorGuaranteed> {
let mut guar = None;
let mut binders = Binders::default();
+ if let Some(args) = args {
+ check_binders(psess, node_id, args, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar);
+ }
check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar);
check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar);
guar.map_or(Ok(()), Err)
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 52d38c35f980..37b236a2e268 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -6,12 +6,12 @@ use std::{mem, slice};
use ast::token::IdentIsRaw;
use rustc_ast::token::NtPatKind::*;
use rustc_ast::token::TokenKind::*;
-use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
-use rustc_ast::tokenstream::{DelimSpan, TokenStream};
+use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
+use rustc_ast::tokenstream::{self, DelimSpan, TokenStream};
use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
+use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
use rustc_feature::Features;
use rustc_hir as hir;
use rustc_hir::attrs::AttributeKind;
@@ -23,23 +23,26 @@ use rustc_lint_defs::builtin::{
use rustc_parse::exp;
use rustc_parse::parser::{Parser, Recovery};
use rustc_session::Session;
-use rustc_session::parse::ParseSess;
+use rustc_session::parse::{ParseSess, feature_err};
use rustc_span::edition::Edition;
use rustc_span::hygiene::Transparency;
use rustc_span::{Ident, Span, kw, sym};
use tracing::{debug, instrument, trace, trace_span};
+use super::diagnostics::failed_to_match_macro;
use super::macro_parser::{NamedMatches, NamedParseResult};
use super::{SequenceRepetition, diagnostics};
use crate::base::{
- DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
- SyntaxExtensionKind, TTMacroExpander,
+ AttrProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult,
+ SyntaxExtension, SyntaxExtensionKind, TTMacroExpander,
};
+use crate::errors;
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
+use crate::mbe::macro_check::check_meta_variables;
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
use crate::mbe::quoted::{RulePart, parse_one_tt};
use crate::mbe::transcribe::transcribe;
-use crate::mbe::{self, KleeneOp, macro_check};
+use crate::mbe::{self, KleeneOp};
pub(crate) struct ParserAnyMacro<'a> {
parser: Parser<'a>,
@@ -123,10 +126,17 @@ impl<'a> ParserAnyMacro<'a> {
}
}
-pub(super) struct MacroRule {
- pub(super) lhs: Vec,
- lhs_span: Span,
- rhs: mbe::TokenTree,
+pub(super) enum MacroRule {
+ /// A function-style rule, for use with `m!()`
+ Func { lhs: Vec, lhs_span: Span, rhs: mbe::TokenTree },
+ /// An attr rule, for use with `#[m]`
+ Attr {
+ args: Vec,
+ args_span: Span,
+ body: Vec,
+ body_span: Span,
+ rhs: mbe::TokenTree,
+ },
}
pub struct MacroRulesMacroExpander {
@@ -138,10 +148,15 @@ pub struct MacroRulesMacroExpander {
}
impl MacroRulesMacroExpander {
- pub fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, Span)> {
+ pub fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, MultiSpan)> {
// If the rhs contains an invocation like `compile_error!`, don't report it as unused.
- let rule = &self.rules[rule_i];
- if has_compile_error_macro(&rule.rhs) { None } else { Some((&self.name, rule.lhs_span)) }
+ let (span, rhs) = match self.rules[rule_i] {
+ MacroRule::Func { lhs_span, ref rhs, .. } => (MultiSpan::from_span(lhs_span), rhs),
+ MacroRule::Attr { args_span, body_span, ref rhs, .. } => {
+ (MultiSpan::from_spans(vec![args_span, body_span]), rhs)
+ }
+ };
+ if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) }
}
}
@@ -165,6 +180,28 @@ impl TTMacroExpander for MacroRulesMacroExpander {
}
}
+impl AttrProcMacro for MacroRulesMacroExpander {
+ fn expand(
+ &self,
+ cx: &mut ExtCtxt<'_>,
+ sp: Span,
+ args: TokenStream,
+ body: TokenStream,
+ ) -> Result {
+ expand_macro_attr(
+ cx,
+ sp,
+ self.span,
+ self.node_id,
+ self.name,
+ self.transparency,
+ args,
+ body,
+ &self.rules,
+ )
+ }
+}
+
struct DummyExpander(ErrorGuaranteed);
impl TTMacroExpander for DummyExpander {
@@ -197,7 +234,7 @@ pub(super) trait Tracker<'matcher> {
/// This is called after an arm has been parsed, either successfully or unsuccessfully. When
/// this is called, `before_match_loc` was called at least once (with a `MatcherLoc::Eof`).
- fn after_arm(&mut self, _result: &NamedParseResult) {}
+ fn after_arm(&mut self, _in_body: bool, _result: &NamedParseResult) {}
/// For tracing.
fn description() -> &'static str;
@@ -245,14 +282,17 @@ fn expand_macro<'cx>(
match try_success_result {
Ok((rule_index, rule, named_matches)) => {
- let mbe::TokenTree::Delimited(rhs_span, _, ref rhs) = rule.rhs else {
+ let MacroRule::Func { rhs, .. } = rule else {
+ panic!("try_match_macro returned non-func rule");
+ };
+ let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else {
cx.dcx().span_bug(sp, "malformed macro rhs");
};
- let arm_span = rule.rhs.span();
+ let arm_span = rhs_span.entire();
// rhs has holes ( `$id` and `$(...)` that need filled)
let id = cx.current_expansion.id;
- let tts = match transcribe(psess, &named_matches, rhs, rhs_span, transparency, id) {
+ let tts = match transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) {
Ok(tts) => tts,
Err(err) => {
let guar = err.emit();
@@ -280,13 +320,76 @@ fn expand_macro<'cx>(
Err(CanRetry::Yes) => {
// Retry and emit a better error.
let (span, guar) =
- diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules);
+ failed_to_match_macro(cx.psess(), sp, def_span, name, None, &arg, rules);
cx.macro_error_and_trace_macros_diag();
DummyResult::any(span, guar)
}
}
}
+/// Expands the rules based macro defined by `rules` for a given attribute `args` and `body`.
+#[instrument(skip(cx, transparency, args, body, rules))]
+fn expand_macro_attr(
+ cx: &mut ExtCtxt<'_>,
+ sp: Span,
+ def_span: Span,
+ node_id: NodeId,
+ name: Ident,
+ transparency: Transparency,
+ args: TokenStream,
+ body: TokenStream,
+ rules: &[MacroRule],
+) -> Result {
+ let psess = &cx.sess.psess;
+ // Macros defined in the current crate have a real node id,
+ // whereas macros from an external crate have a dummy id.
+ let is_local = node_id != DUMMY_NODE_ID;
+
+ if cx.trace_macros() {
+ let msg = format!(
+ "expanding `$[{name}({})] {}`",
+ pprust::tts_to_string(&args),
+ pprust::tts_to_string(&body),
+ );
+ trace_macros_note(&mut cx.expansions, sp, msg);
+ }
+
+ // Track nothing for the best performance.
+ match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) {
+ Ok((i, rule, named_matches)) => {
+ let MacroRule::Attr { rhs, .. } = rule else {
+ panic!("try_macro_match_attr returned non-attr rule");
+ };
+ let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else {
+ cx.dcx().span_bug(sp, "malformed macro rhs");
+ };
+
+ let id = cx.current_expansion.id;
+ let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id)
+ .map_err(|e| e.emit())?;
+
+ if cx.trace_macros() {
+ let msg = format!("to `{}`", pprust::tts_to_string(&tts));
+ trace_macros_note(&mut cx.expansions, sp, msg);
+ }
+
+ if is_local {
+ cx.resolver.record_macro_rule_usage(node_id, i);
+ }
+
+ Ok(tts)
+ }
+ Err(CanRetry::No(guar)) => Err(guar),
+ Err(CanRetry::Yes) => {
+ // Retry and emit a better error.
+ let (_, guar) =
+ failed_to_match_macro(cx.psess(), sp, def_span, name, Some(&args), &body, rules);
+ cx.trace_macros_diag();
+ Err(guar)
+ }
+ }
+}
+
pub(super) enum CanRetry {
Yes,
/// We are not allowed to retry macro expansion as a fatal error has been emitted already.
@@ -327,6 +430,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
// Try each arm's matchers.
let mut tt_parser = TtParser::new(name);
for (i, rule) in rules.iter().enumerate() {
+ let MacroRule::Func { lhs, .. } = rule else { continue };
let _tracing_span = trace_span!("Matching arm", %i);
// Take a snapshot of the state of pre-expansion gating at this point.
@@ -335,9 +439,9 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut());
- let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, track);
+ let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, track);
- track.after_arm(&result);
+ track.after_arm(true, &result);
match result {
Success(named_matches) => {
@@ -372,6 +476,60 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
Err(CanRetry::Yes)
}
+/// Try expanding the macro attribute. Returns the index of the successful arm and its
+/// named_matches if it was successful, and nothing if it failed. On failure, it's the caller's job
+/// to use `track` accordingly to record all errors correctly.
+#[instrument(level = "debug", skip(psess, attr_args, attr_body, rules, track), fields(tracking = %T::description()))]
+pub(super) fn try_match_macro_attr<'matcher, T: Tracker<'matcher>>(
+ psess: &ParseSess,
+ name: Ident,
+ attr_args: &TokenStream,
+ attr_body: &TokenStream,
+ rules: &'matcher [MacroRule],
+ track: &mut T,
+) -> Result<(usize, &'matcher MacroRule, NamedMatches), CanRetry> {
+ // This uses the same strategy as `try_match_macro`
+ let args_parser = parser_from_cx(psess, attr_args.clone(), T::recovery());
+ let body_parser = parser_from_cx(psess, attr_body.clone(), T::recovery());
+ let mut tt_parser = TtParser::new(name);
+ for (i, rule) in rules.iter().enumerate() {
+ let MacroRule::Attr { args, body, .. } = rule else { continue };
+
+ let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut());
+
+ let result = tt_parser.parse_tt(&mut Cow::Borrowed(&args_parser), args, track);
+ track.after_arm(false, &result);
+
+ let mut named_matches = match result {
+ Success(named_matches) => named_matches,
+ Failure(_) => {
+ mem::swap(&mut gated_spans_snapshot, &mut psess.gated_spans.spans.borrow_mut());
+ continue;
+ }
+ Error(_, _) => return Err(CanRetry::Yes),
+ ErrorReported(guar) => return Err(CanRetry::No(guar)),
+ };
+
+ let result = tt_parser.parse_tt(&mut Cow::Borrowed(&body_parser), body, track);
+ track.after_arm(true, &result);
+
+ match result {
+ Success(body_named_matches) => {
+ psess.gated_spans.merge(gated_spans_snapshot);
+ named_matches.extend(body_named_matches);
+ return Ok((i, rule, named_matches));
+ }
+ Failure(_) => {
+ mem::swap(&mut gated_spans_snapshot, &mut psess.gated_spans.spans.borrow_mut())
+ }
+ Error(_, _) => return Err(CanRetry::Yes),
+ ErrorReported(guar) => return Err(CanRetry::No(guar)),
+ }
+ }
+
+ Err(CanRetry::Yes)
+}
+
/// Converts a macro item into a syntax extension.
pub fn compile_declarative_macro(
sess: &Session,
@@ -382,13 +540,13 @@ pub fn compile_declarative_macro(
span: Span,
node_id: NodeId,
edition: Edition,
-) -> (SyntaxExtension, usize) {
- let mk_syn_ext = |expander| {
- let kind = SyntaxExtensionKind::LegacyBang(expander);
+) -> (SyntaxExtension, Option>, usize) {
+ let mk_syn_ext = |kind| {
let is_local = is_defined_in_current_crate(node_id);
SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local)
};
- let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), 0);
+ let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander));
+ let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0);
let macro_rules = macro_def.macro_rules;
let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
@@ -401,9 +559,30 @@ pub fn compile_declarative_macro(
let mut guar = None;
let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err());
+ let mut has_attr_rules = false;
let mut rules = Vec::new();
while p.token != token::Eof {
+ let args = if p.eat_keyword_noexpect(sym::attr) {
+ has_attr_rules = true;
+ if !features.macro_attr() {
+ feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable")
+ .emit();
+ }
+ if let Some(guar) = check_no_eof(sess, &p, "expected macro attr args") {
+ return dummy_syn_ext(guar);
+ }
+ let args = p.parse_token_tree();
+ check_args_parens(sess, &args);
+ let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition);
+ check_emission(check_lhs(sess, node_id, &args));
+ if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") {
+ return dummy_syn_ext(guar);
+ }
+ Some(args)
+ } else {
+ None
+ };
let lhs_tt = p.parse_token_tree();
let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition);
check_emission(check_lhs(sess, node_id, &lhs_tt));
@@ -416,7 +595,7 @@ pub fn compile_declarative_macro(
let rhs_tt = p.parse_token_tree();
let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition);
check_emission(check_rhs(sess, &rhs_tt));
- check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt));
+ check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt));
let lhs_span = lhs_tt.span();
// Convert the lhs into `MatcherLoc` form, which is better for doing the
// actual matching.
@@ -425,7 +604,17 @@ pub fn compile_declarative_macro(
} else {
return dummy_syn_ext(guar.unwrap());
};
- rules.push(MacroRule { lhs, lhs_span, rhs: rhs_tt });
+ if let Some(args) = args {
+ let args_span = args.span();
+ let mbe::TokenTree::Delimited(.., delimited) = args else {
+ return dummy_syn_ext(guar.unwrap());
+ };
+ let args = mbe::macro_parser::compute_locs(&delimited.tts);
+ let body_span = lhs_span;
+ rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt });
+ } else {
+ rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt });
+ }
if p.token == token::Eof {
break;
}
@@ -451,9 +640,12 @@ pub fn compile_declarative_macro(
// Return the number of rules for unused rule linting, if this is a local macro.
let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 };
- let expander =
- Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules });
- (mk_syn_ext(expander), nrules)
+ let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules });
+ let opt_attr_ext = has_attr_rules.then(|| {
+ let exp = Arc::clone(&exp);
+ Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp)))
+ });
+ (mk_bang_ext(exp), opt_attr_ext, nrules)
}
fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option {
@@ -469,6 +661,18 @@ fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option Result<(), ErrorGuaranteed> {
let e1 = check_lhs_nt_follows(sess, node_id, lhs);
let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs));
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 4eee79a2a71e..04f261ada069 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -54,7 +54,7 @@ declare_features! (
/// Allows using the `amdgpu-kernel` ABI.
(removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None, 120495),
- (removed, abi_c_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391), Some("renamed to abi_cmse_nonsecure_call"), 142146),
+ (removed, abi_c_cmse_nonsecure_call, "1.90.0", Some(81391), Some("renamed to abi_cmse_nonsecure_call"), 142146),
(removed, advanced_slice_patterns, "1.42.0", Some(62254),
Some("merged into `#![feature(slice_patterns)]`"), 67712),
(removed, allocator, "1.0.0", None, None),
@@ -300,7 +300,7 @@ declare_features! (
// FIXME(#141617): we should have a better way to track removed library features, but we reuse
// the infrastructure here so users still get hints. The symbols used here can be remove from
// `symbol.rs` when that happens.
- (removed, concat_idents, "CURRENT_RUSTC_VERSION", Some(29599),
+ (removed, concat_idents, "1.90.0", Some(29599),
Some("use the `${concat(..)}` metavariable expression instead"), 142704),
// -------------------------------------------------------------------------
// feature-group-end: removed library features
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 1303b3317e05..ae1f57c1ef61 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -327,6 +327,7 @@ declare_features! (
(unstable, m68k_target_feature, "1.85.0", Some(134328)),
(unstable, mips_target_feature, "1.27.0", Some(44839)),
(unstable, movrs_target_feature, "1.88.0", Some(137976)),
+ (unstable, nvptx_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
(unstable, powerpc_target_feature, "1.27.0", Some(44839)),
(unstable, prfchw_target_feature, "1.78.0", Some(44839)),
(unstable, riscv_target_feature, "1.45.0", Some(44839)),
@@ -352,7 +353,7 @@ declare_features! (
/// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
(unstable, abi_avr_interrupt, "1.45.0", Some(69664)),
/// Allows `extern "cmse-nonsecure-call" fn()`.
- (unstable, abi_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391)),
+ (unstable, abi_cmse_nonsecure_call, "1.90.0", Some(81391)),
/// Allows `extern "custom" fn()`.
(unstable, abi_custom, "1.89.0", Some(140829)),
/// Allows `extern "gpu-kernel" fn()`.
@@ -552,7 +553,9 @@ declare_features! (
/// to pass custom arguments to the linker.
(unstable, link_arg_attribute, "1.76.0", Some(99427)),
/// Allows fused `loop`/`match` for direct intraprocedural jumps.
- (incomplete, loop_match, "CURRENT_RUSTC_VERSION", Some(132306)),
+ (incomplete, loop_match, "1.90.0", Some(132306)),
+ /// Allow `macro_rules!` attribute rules
+ (unstable, macro_attr, "CURRENT_RUSTC_VERSION", Some(83527)),
/// Give access to additional metadata about declarative macro meta-variables.
(unstable, macro_metavar_expr, "1.61.0", Some(83527)),
/// Provides a way to concatenate identifiers using metavariable expressions.
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 80618422b56d..5f4193154674 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -297,6 +297,9 @@ pub enum AttributeKind {
/// Represents `#[const_trait]`.
ConstTrait(Span),
+ /// Represents `#[coroutine]`.
+ Coroutine(Span),
+
/// Represents `#[coverage(..)]`.
Coverage(Span, CoverageAttrKind),
@@ -433,6 +436,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_object_lifetime_default]`.
RustcObjectLifetimeDefault,
+ /// Represents `#[should_panic]`
+ ShouldPanic { reason: Option, span: Span },
+
/// Represents `#[rustc_skip_during_method_dispatch]`.
SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 9644a597a311..e3a7f0b97a8f 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -28,6 +28,7 @@ impl AttributeKind {
ConstStability { .. } => Yes,
ConstStabilityIndirect => No,
ConstTrait(..) => No,
+ Coroutine(..) => No,
Coverage(..) => No,
DenyExplicitImpl(..) => No,
Deprecation { .. } => Yes,
@@ -69,6 +70,7 @@ impl AttributeKind {
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcObjectLifetimeDefault => No,
+ ShouldPanic { .. } => No,
SkipDuringMethodDispatch { .. } => No,
SpecializationTrait(..) => No,
Stability { .. } => Yes,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c30c830f9af8..34db6f92d928 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1308,6 +1308,7 @@ impl AttributeExt for Attribute {
Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span,
Attribute::Parsed(AttributeKind::MayDangle(span)) => *span,
Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span,
+ Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span,
Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span,
a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
}
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 6e5fe3823ab5..4441dd6ebd66 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -652,16 +652,16 @@ pub(crate) fn check_intrinsic_type(
sym::atomic_store => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit),
sym::atomic_xchg
- | sym::atomic_xadd
- | sym::atomic_xsub
- | sym::atomic_and
- | sym::atomic_nand
- | sym::atomic_or
- | sym::atomic_xor
| sym::atomic_max
| sym::atomic_min
| sym::atomic_umax
| sym::atomic_umin => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)),
+ sym::atomic_xadd
+ | sym::atomic_xsub
+ | sym::atomic_and
+ | sym::atomic_nand
+ | sym::atomic_or
+ | sym::atomic_xor => (2, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(1)], param(0)),
sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit),
other => {
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index e2462c2d4659..ce0e51f106f5 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -223,60 +223,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
"synthetic HIR should have its `generics_of` explicitly fed"
),
- _ => span_bug!(tcx.def_span(def_id), "unhandled node {node:?}"),
+ _ => span_bug!(tcx.def_span(def_id), "generics_of: unexpected node kind {node:?}"),
};
- enum Defaults {
- Allowed,
- // See #36887
- FutureCompatDisallowed,
- Deny,
- }
+ // Add in the self type parameter.
+ let opt_self = if let Node::Item(item) = node
+ && let ItemKind::Trait(..) | ItemKind::TraitAlias(..) = item.kind
+ {
+ // Something of a hack: We reuse the node ID of the trait for the self type parameter.
+ Some(ty::GenericParamDef {
+ index: 0,
+ name: kw::SelfUpper,
+ def_id: def_id.to_def_id(),
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+ })
+ } else {
+ None
+ };
+ let param_default_policy = param_default_policy(node);
let hir_generics = node.generics().unwrap_or(hir::Generics::empty());
- let (opt_self, allow_defaults) = match node {
- Node::Item(item) => {
- match item.kind {
- ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
- // Add in the self type parameter.
- //
- // Something of a hack: use the node id for the trait, also as
- // the node id for the Self type parameter.
- let opt_self = Some(ty::GenericParamDef {
- index: 0,
- name: kw::SelfUpper,
- def_id: def_id.to_def_id(),
- pure_wrt_drop: false,
- kind: ty::GenericParamDefKind::Type {
- has_default: false,
- synthetic: false,
- },
- });
-
- (opt_self, Defaults::Allowed)
- }
- ItemKind::TyAlias(..)
- | ItemKind::Enum(..)
- | ItemKind::Struct(..)
- | ItemKind::Union(..) => (None, Defaults::Allowed),
- ItemKind::Const(..) => (None, Defaults::Deny),
- _ => (None, Defaults::FutureCompatDisallowed),
- }
- }
-
- Node::OpaqueTy(..) => (None, Defaults::Allowed),
-
- // GATs
- Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
- (None, Defaults::Deny)
- }
- Node::ImplItem(item) if matches!(item.kind, ImplItemKind::Type(..)) => {
- (None, Defaults::Deny)
- }
-
- _ => (None, Defaults::FutureCompatDisallowed),
- };
-
let has_self = opt_self.is_some();
let mut parent_has_self = false;
let mut own_start = has_self as u32;
@@ -312,60 +279,53 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
prev + type_start
};
- const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
- `struct`, `enum`, `type`, or `trait` definitions";
-
- own_params.extend(hir_generics.params.iter().filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => None,
- GenericParamKind::Type { default, synthetic, .. } => {
- if default.is_some() {
- match allow_defaults {
- Defaults::Allowed => {}
- Defaults::FutureCompatDisallowed => {
- tcx.node_span_lint(
- lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
- param.hir_id,
- param.span,
- |lint| {
- lint.primary_message(TYPE_DEFAULT_NOT_ALLOWED);
- },
- );
- }
- Defaults::Deny => {
- tcx.dcx().span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
+ own_params.extend(hir_generics.params.iter().filter_map(|param| {
+ const MESSAGE: &str = "defaults for generic parameters are not allowed here";
+ let kind = match param.kind {
+ GenericParamKind::Lifetime { .. } => return None,
+ GenericParamKind::Type { default, synthetic } => {
+ if default.is_some() {
+ match param_default_policy.expect("no policy for generic param default") {
+ ParamDefaultPolicy::Allowed => {}
+ ParamDefaultPolicy::FutureCompatForbidden => {
+ tcx.node_span_lint(
+ lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+ param.hir_id,
+ param.span,
+ |lint| {
+ lint.primary_message(MESSAGE);
+ },
+ );
+ }
+ ParamDefaultPolicy::Forbidden => {
+ tcx.dcx().span_err(param.span, MESSAGE);
+ }
}
}
+
+ ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }
}
+ GenericParamKind::Const { ty: _, default, synthetic } => {
+ if default.is_some() {
+ match param_default_policy.expect("no policy for generic param default") {
+ ParamDefaultPolicy::Allowed => {}
+ ParamDefaultPolicy::FutureCompatForbidden
+ | ParamDefaultPolicy::Forbidden => {
+ tcx.dcx().span_err(param.span, MESSAGE);
+ }
+ }
+ }
- let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
-
- Some(ty::GenericParamDef {
- index: next_index(),
- name: param.name.ident().name,
- def_id: param.def_id.to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind,
- })
- }
- GenericParamKind::Const { ty: _, default, synthetic } => {
- if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
- tcx.dcx().span_err(
- param.span,
- "defaults for const parameters are only allowed in \
- `struct`, `enum`, `type`, or `trait` definitions",
- );
+ ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic }
}
-
- let index = next_index();
-
- Some(ty::GenericParamDef {
- index,
- name: param.name.ident().name,
- def_id: param.def_id.to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic },
- })
- }
+ };
+ Some(ty::GenericParamDef {
+ index: next_index(),
+ name: param.name.ident().name,
+ def_id: param.def_id.to_def_id(),
+ pure_wrt_drop: param.pure_wrt_drop,
+ kind,
+ })
}));
// provide junk type parameter defs - the only place that
@@ -438,6 +398,48 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
}
+#[derive(Clone, Copy)]
+enum ParamDefaultPolicy {
+ Allowed,
+ /// Tracked in .
+ FutureCompatForbidden,
+ Forbidden,
+}
+
+fn param_default_policy(node: Node<'_>) -> Option {
+ use rustc_hir::*;
+
+ Some(match node {
+ Node::Item(item) => match item.kind {
+ ItemKind::Trait(..)
+ | ItemKind::TraitAlias(..)
+ | ItemKind::TyAlias(..)
+ | ItemKind::Enum(..)
+ | ItemKind::Struct(..)
+ | ItemKind::Union(..) => ParamDefaultPolicy::Allowed,
+ ItemKind::Fn { .. } | ItemKind::Impl(_) => ParamDefaultPolicy::FutureCompatForbidden,
+ // Re. GCI, we're not bound by backward compatibility.
+ ItemKind::Const(..) => ParamDefaultPolicy::Forbidden,
+ _ => return None,
+ },
+ Node::TraitItem(item) => match item.kind {
+ // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility.
+ TraitItemKind::Const(..) | TraitItemKind::Type(..) => ParamDefaultPolicy::Forbidden,
+ TraitItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden,
+ },
+ Node::ImplItem(item) => match item.kind {
+ // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility.
+ ImplItemKind::Const(..) | ImplItemKind::Type(..) => ParamDefaultPolicy::Forbidden,
+ ImplItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden,
+ },
+ // Generic params are (semantically) invalid on foreign items. Still, for maximum forward
+ // compatibility, let's hard-reject defaults on them.
+ Node::ForeignItem(_) => ParamDefaultPolicy::Forbidden,
+ Node::OpaqueTy(..) => ParamDefaultPolicy::Allowed,
+ _ => return None,
+ })
+}
+
fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option {
struct LateBoundRegionsDetector<'tcx> {
tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 7e2bfa9f920c..1675aecd2b84 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1135,9 +1135,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
}
} else {
+ let trait_ =
+ tcx.short_string(bound.print_only_trait_path(), err.long_ty_path());
err.note(format!(
- "associated {assoc_kind_str} `{assoc_ident}` could derive from `{}`",
- bound.print_only_trait_path(),
+ "associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`",
));
}
}
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index bac4d70103c3..1ed0756fdd6a 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -159,7 +159,7 @@ hir_typeck_lossy_provenance_ptr2int =
.suggestion = use `.addr()` to obtain the address of a pointer
.help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
-hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
+hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty}`
hir_typeck_naked_asm_outside_naked_fn =
the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
@@ -184,7 +184,7 @@ hir_typeck_never_type_fallback_flowing_into_unsafe_path = never type fallback af
hir_typeck_never_type_fallback_flowing_into_unsafe_union_field = never type fallback affects this union access
.help = specify the type explicitly
-hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
+hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty}`{$trait_missing_method ->
[true] {""}
*[other] {" "}in the current scope
}
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index a8bb6956f101..d15d092b7d3d 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -200,11 +200,11 @@ pub(crate) enum ExplicitDestructorCallSugg {
#[derive(Diagnostic)]
#[diag(hir_typeck_missing_parentheses_in_range, code = E0689)]
-pub(crate) struct MissingParenthesesInRange {
+pub(crate) struct MissingParenthesesInRange<'tcx> {
#[primary_span]
#[label(hir_typeck_missing_parentheses_in_range)]
pub span: Span,
- pub ty_str: String,
+ pub ty: Ty<'tcx>,
pub method_name: String,
#[subdiagnostic]
pub add_missing_parentheses: Option,
@@ -828,13 +828,13 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
#[derive(Diagnostic)]
#[diag(hir_typeck_no_associated_item, code = E0599)]
-pub(crate) struct NoAssociatedItem {
+pub(crate) struct NoAssociatedItem<'tcx> {
#[primary_span]
pub span: Span,
pub item_kind: &'static str,
pub item_ident: Ident,
pub ty_prefix: Cow<'static, str>,
- pub ty_str: String,
+ pub ty: Ty<'tcx>,
pub trait_missing_method: bool,
}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 454ec7ddcafb..0498a9383663 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2745,6 +2745,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let available_field_names = self.available_field_names(variant, expr, skip_fields);
if let Some(field_name) =
find_best_match_for_name(&available_field_names, field.ident.name, None)
+ && !(field.ident.name.as_str().parse::().is_ok()
+ && field_name.as_str().parse::().is_ok())
{
err.span_label(field.ident.span, "unknown field");
err.span_suggestion_verbose(
@@ -3321,18 +3323,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
(base_ty, "")
};
- for (found_fields, args) in
+ for found_fields in
self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id)
{
- let field_names = found_fields.iter().map(|field| field.name).collect::>();
+ let field_names = found_fields.iter().map(|field| field.0.name).collect::>();
let mut candidate_fields: Vec<_> = found_fields
.into_iter()
.filter_map(|candidate_field| {
self.check_for_nested_field_satisfying_condition_for_diag(
span,
- &|candidate_field, _| candidate_field.ident(self.tcx()) == field,
+ &|candidate_field, _| candidate_field == field,
candidate_field,
- args,
vec![],
mod_id,
expr.hir_id,
@@ -3361,6 +3362,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
} else if let Some(field_name) =
find_best_match_for_name(&field_names, field.name, None)
+ && !(field.name.as_str().parse::().is_ok()
+ && field_name.as_str().parse::().is_ok())
{
err.span_suggestion_verbose(
field.span,
@@ -3396,7 +3399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
base_ty: Ty<'tcx>,
mod_id: DefId,
hir_id: HirId,
- ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> {
+ ) -> Vec)>> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
let mut autoderef = self.autoderef(span, base_ty).silence_errors();
@@ -3422,7 +3425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
return None;
}
- return Some((
+ return Some(
fields
.iter()
.filter(move |field| {
@@ -3431,9 +3434,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
// For compile-time reasons put a limit on number of fields we search
.take(100)
+ .map(|field_def| {
+ (
+ field_def.ident(self.tcx).normalize_to_macros_2_0(),
+ field_def.ty(self.tcx, args),
+ )
+ })
.collect::>(),
- *args,
- ));
+ );
+ }
+ ty::Tuple(types) => {
+ return Some(
+ types
+ .iter()
+ .enumerate()
+ // For compile-time reasons put a limit on number of fields we search
+ .take(100)
+ .map(|(i, ty)| (Ident::from_str(&i.to_string()), ty))
+ .collect::>(),
+ );
}
_ => None,
}
@@ -3443,56 +3462,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// This method is called after we have encountered a missing field error to recursively
/// search for the field
+ #[instrument(skip(self, matches, mod_id, hir_id), level = "debug")]
pub(crate) fn check_for_nested_field_satisfying_condition_for_diag(
&self,
span: Span,
- matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
- candidate_field: &ty::FieldDef,
- subst: GenericArgsRef<'tcx>,
+ matches: &impl Fn(Ident, Ty<'tcx>) -> bool,
+ (candidate_name, candidate_ty): (Ident, Ty<'tcx>),
mut field_path: Vec,
mod_id: DefId,
hir_id: HirId,
) -> Option> {
- debug!(
- "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
- span, candidate_field, field_path
- );
-
if field_path.len() > 3 {
// For compile-time reasons and to avoid infinite recursion we only check for fields
// up to a depth of three
- None
- } else {
- field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
- let field_ty = candidate_field.ty(self.tcx, subst);
- if matches(candidate_field, field_ty) {
- return Some(field_path);
- } else {
- for (nested_fields, subst) in self
- .get_field_candidates_considering_privacy_for_diag(
- span, field_ty, mod_id, hir_id,
- )
- {
- // recursively search fields of `candidate_field` if it's a ty::Adt
- for field in nested_fields {
- if let Some(field_path) = self
- .check_for_nested_field_satisfying_condition_for_diag(
- span,
- matches,
- field,
- subst,
- field_path.clone(),
- mod_id,
- hir_id,
- )
- {
- return Some(field_path);
- }
- }
+ return None;
+ }
+ field_path.push(candidate_name);
+ if matches(candidate_name, candidate_ty) {
+ return Some(field_path);
+ }
+ for nested_fields in self.get_field_candidates_considering_privacy_for_diag(
+ span,
+ candidate_ty,
+ mod_id,
+ hir_id,
+ ) {
+ // recursively search fields of `candidate_field` if it's a ty::Adt
+ for field in nested_fields {
+ if let Some(field_path) = self.check_for_nested_field_satisfying_condition_for_diag(
+ span,
+ matches,
+ field,
+ field_path.clone(),
+ mod_id,
+ hir_id,
+ ) {
+ return Some(field_path);
}
}
- None
}
+ None
}
fn check_expr_index(
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 0c0cc752b01a..f7430f7af4e9 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -376,16 +376,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
- let mut file = None;
+ fn suggest_missing_writer(
+ &self,
+ rcvr_ty: Ty<'tcx>,
+ rcvr_expr: &hir::Expr<'tcx>,
+ mut long_ty_path: Option,
+ ) -> Diag<'_> {
let mut err = struct_span_code_err!(
self.dcx(),
rcvr_expr.span,
E0599,
"cannot write into `{}`",
- self.tcx.short_string(rcvr_ty, &mut file),
+ self.tcx.short_string(rcvr_ty, &mut long_ty_path),
);
- *err.long_ty_path() = file;
+ *err.long_ty_path() = long_ty_path;
err.span_note(
rcvr_expr.span,
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
@@ -403,7 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
self_source: SelfSource<'tcx>,
method_name: Ident,
- ty_str_reported: &str,
+ ty: Ty<'tcx>,
err: &mut Diag<'_>,
) {
#[derive(Debug)]
@@ -478,7 +482,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// If the shadowed binding has an itializer expression,
- // use the initializer expression'ty to try to find the method again.
+ // use the initializer expression's ty to try to find the method again.
// For example like: `let mut x = Vec::new();`,
// `Vec::new()` is the itializer expression.
if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
@@ -566,17 +570,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut span = MultiSpan::from_span(sugg_let.span);
span.push_span_label(sugg_let.span,
format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));
+
+ let ty = self.tcx.short_string(ty, err.long_ty_path());
span.push_span_label(
self.tcx.hir_span(recv_id),
- format!(
- "earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
- ),
+ format!("earlier `{rcvr_name}` shadowed here with type `{ty}`"),
);
err.span_note(
span,
format!(
"there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
- that has method `{method_name}` available"
+ that has method `{method_name}` available"
),
);
}
@@ -602,15 +606,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
let mut ty_file = None;
- let (ty_str, short_ty_str) =
- if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
- (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
- } else {
- (
- tcx.short_string(rcvr_ty, &mut ty_file),
- with_forced_trimmed_paths!(rcvr_ty.to_string()),
- )
- };
let is_method = mode == Mode::MethodCall;
let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
let similar_candidate = no_match_data.similar_candidate;
@@ -629,15 +624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We could pass the file for long types into these two, but it isn't strictly necessary
// given how targeted they are.
- if let Err(guar) = self.report_failed_method_call_on_range_end(
- tcx,
- rcvr_ty,
- source,
- span,
- item_ident,
- &short_ty_str,
- &mut ty_file,
- ) {
+ if let Err(guar) =
+ self.report_failed_method_call_on_range_end(tcx, rcvr_ty, source, span, item_ident)
+ {
return guar;
}
if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var(
@@ -647,44 +636,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
item_kind,
item_ident,
- &short_ty_str,
&mut ty_file,
) {
return guar;
}
span = item_ident.span;
- // Don't show generic arguments when the method can't be found in any implementation (#81576).
- let mut ty_str_reported = ty_str.clone();
- if let ty::Adt(_, generics) = rcvr_ty.kind() {
- if generics.len() > 0 {
- let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
- let candidate_found = autoderef.any(|(ty, _)| {
- if let ty::Adt(adt_def, _) = ty.kind() {
- self.tcx
- .inherent_impls(adt_def.did())
- .into_iter()
- .any(|def_id| self.associated_value(*def_id, item_ident).is_some())
- } else {
- false
- }
- });
- let has_deref = autoderef.step_count() > 0;
- if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
- if let Some((path_string, _)) = ty_str.split_once('<') {
- ty_str_reported = path_string.to_string();
- }
- }
- }
- }
-
let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
tcx.is_diagnostic_item(sym::write_macro, def_id)
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
}) && item_ident.name == sym::write_fmt;
let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
- self.suggest_missing_writer(rcvr_ty, rcvr_expr)
+ self.suggest_missing_writer(rcvr_ty, rcvr_expr, ty_file)
} else {
+ // Don't show expanded generic arguments when the method can't be found in any
+ // implementation (#81576).
+ let mut ty = rcvr_ty;
+ if let ty::Adt(def, generics) = rcvr_ty.kind() {
+ if generics.len() > 0 {
+ let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
+ let candidate_found = autoderef.any(|(ty, _)| {
+ if let ty::Adt(adt_def, _) = ty.kind() {
+ self.tcx
+ .inherent_impls(adt_def.did())
+ .into_iter()
+ .any(|def_id| self.associated_value(*def_id, item_ident).is_some())
+ } else {
+ false
+ }
+ });
+ let has_deref = autoderef.step_count() > 0;
+ if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+ ty = self.tcx.at(span).type_of(def.did()).instantiate_identity();
+ }
+ }
+ }
+
let mut err = self.dcx().create_err(NoAssociatedItem {
span,
item_kind,
@@ -695,16 +682,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
rcvr_ty.prefix_string(self.tcx)
},
- ty_str: ty_str_reported.clone(),
+ ty,
trait_missing_method,
});
if is_method {
self.suggest_use_shadowed_binding_with_method(
- source,
- item_ident,
- &ty_str_reported,
- &mut err,
+ source, item_ident, rcvr_ty, &mut err,
);
}
@@ -734,6 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err
};
+
if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
}
@@ -750,6 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if tcx.ty_is_opaque_future(rcvr_ty) && item_ident.name == sym::poll {
+ let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
err.help(format!(
"method `poll` found on `Pin<&mut {ty_str}>`, \
see documentation for `std::pin::Pin`"
@@ -1339,7 +1325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let OnUnimplementedNote { message, label, notes, .. } = self
.err_ctxt()
- .on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
+ .on_unimplemented_note(trait_ref, &obligation, err.long_ty_path());
(message, label, notes)
})
.unwrap()
@@ -1347,6 +1333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(None, None, Vec::new())
};
let primary_message = primary_message.unwrap_or_else(|| {
+ let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
format!(
"the {item_kind} `{item_ident}` exists for {actual_prefix} `{ty_str}`, \
but its trait bounds were not satisfied"
@@ -1409,6 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut find_candidate_for_method = false;
let mut label_span_not_found = |err: &mut Diag<'_>| {
+ let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
let is_string_or_ref_str = match rcvr_ty.kind() {
@@ -2520,8 +2508,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
source: SelfSource<'tcx>,
span: Span,
item_name: Ident,
- ty_str: &str,
- long_ty_path: &mut Option,
) -> Result<(), ErrorGuaranteed> {
if let SelfSource::MethodCall(expr) = source {
for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) {
@@ -2583,18 +2569,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if pick.is_ok() {
let range_span = parent_expr.span.with_hi(expr.span.hi());
- let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
+ return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
span,
- ty_str: ty_str.to_string(),
+ ty: actual,
method_name: item_name.as_str().to_string(),
add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
func_name: item_name.name.as_str().to_string(),
left: range_span.shrink_to_lo(),
right: range_span.shrink_to_hi(),
}),
- });
- *err.long_ty_path() = long_ty_path.take();
- return Err(err.emit());
+ }));
}
}
}
@@ -2610,7 +2594,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
item_kind: &str,
item_name: Ident,
- ty_str: &str,
long_ty_path: &mut Option,
) -> Result<(), ErrorGuaranteed> {
let found_candidate = all_traits(self.tcx)
@@ -2643,14 +2626,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !actual.has_concrete_skeleton()
&& let SelfSource::MethodCall(expr) = source
{
+ let ty_str = self.tcx.short_string(actual, long_ty_path);
let mut err = struct_span_code_err!(
self.dcx(),
span,
E0689,
- "can't call {} `{}` on ambiguous numeric type `{}`",
- item_kind,
- item_name,
- ty_str
+ "can't call {item_kind} `{item_name}` on ambiguous numeric type `{ty_str}`"
);
*err.long_ty_path() = long_ty_path.take();
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
@@ -2792,7 +2773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
if let SelfSource::MethodCall(expr) = source {
let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
- for (fields, args) in self.get_field_candidates_considering_privacy_for_diag(
+ for fields in self.get_field_candidates_considering_privacy_for_diag(
span,
actual,
mod_id,
@@ -2831,7 +2812,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
},
candidate_field,
- args,
vec![],
mod_id,
expr.hir_id,
@@ -3671,7 +3651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
{
debug!("try_alt_rcvr: pick candidate {:?}", pick);
- let did = Some(pick.item.container_id(self.tcx));
+ let did = pick.item.trait_container(self.tcx);
// We don't want to suggest a container type when the missing
// method is `.clone()` or `.deref()` otherwise we'd suggest
// `Arc::new(foo).clone()`, which is far from what the user wants.
@@ -3720,8 +3700,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !alt_rcvr_sugg
// `T: !Unpin`
&& !unpin
- // The method isn't `as_ref`, as it would provide a wrong suggestion for `Pin`.
- && sym::as_ref != item_name.name
// Either `Pin::as_ref` or `Pin::as_mut`.
&& let Some(pin_call) = pin_call
// Search for `item_name` as a method accessible on `Pin`.
@@ -3735,6 +3713,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We skip some common traits that we don't want to consider because autoderefs
// would take care of them.
&& !skippable.contains(&Some(pick.item.container_id(self.tcx)))
+ // Do not suggest pinning when the method is directly on `Pin`.
+ && pick.item.impl_container(self.tcx).map_or(true, |did| {
+ match self.tcx.type_of(did).skip_binder().kind() {
+ ty::Adt(def, _) => Some(def.did()) != self.tcx.lang_items().pin_type(),
+ _ => true,
+ }
+ })
// We don't want to go through derefs.
&& pick.autoderefs == 0
// Check that the method of the same name that was found on the new `Pin`
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 86faab62d03a..16474b231e04 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -777,7 +777,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(
coverage_options,
CoverageOptions {
- level: CoverageLevel::Mcdc,
+ level: CoverageLevel::Branch,
// (don't collapse test-only options onto the same line)
discard_all_spans_in_codegen: true,
}
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs
index 2a5a34cdc6e9..464f4fc34b96 100644
--- a/compiler/rustc_lint/src/lifetime_syntax.rs
+++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -434,7 +434,7 @@ fn emit_mismatch_diagnostic<'tcx>(
lints::MismatchedLifetimeSyntaxesSuggestion::Mixed {
implicit_suggestions,
explicit_anonymous_suggestions,
- tool_only: false,
+ optional_alternative: false,
}
});
@@ -455,7 +455,10 @@ fn emit_mismatch_diagnostic<'tcx>(
let implicit_suggestion = should_suggest_implicit.then(|| {
let suggestions = make_implicit_suggestions(&suggest_change_to_implicit);
- lints::MismatchedLifetimeSyntaxesSuggestion::Implicit { suggestions, tool_only: false }
+ lints::MismatchedLifetimeSyntaxesSuggestion::Implicit {
+ suggestions,
+ optional_alternative: false,
+ }
});
tracing::debug!(
@@ -508,7 +511,7 @@ fn build_mismatch_suggestion(
lints::MismatchedLifetimeSyntaxesSuggestion::Explicit {
lifetime_name,
suggestions,
- tool_only: false,
+ optional_alternative: false,
}
}
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index ef63c0dee8c2..ac6147b16312 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -3292,7 +3292,7 @@ impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSynta
diag.subdiagnostic(s);
for mut s in suggestions {
- s.make_tool_only();
+ s.make_optional_alternative();
diag.subdiagnostic(s);
}
}
@@ -3303,33 +3303,33 @@ impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSynta
pub(crate) enum MismatchedLifetimeSyntaxesSuggestion {
Implicit {
suggestions: Vec,
- tool_only: bool,
+ optional_alternative: bool,
},
Mixed {
implicit_suggestions: Vec,
explicit_anonymous_suggestions: Vec<(Span, String)>,
- tool_only: bool,
+ optional_alternative: bool,
},
Explicit {
lifetime_name: String,
suggestions: Vec<(Span, String)>,
- tool_only: bool,
+ optional_alternative: bool,
},
}
impl MismatchedLifetimeSyntaxesSuggestion {
- fn make_tool_only(&mut self) {
+ fn make_optional_alternative(&mut self) {
use MismatchedLifetimeSyntaxesSuggestion::*;
- let tool_only = match self {
- Implicit { tool_only, .. } | Mixed { tool_only, .. } | Explicit { tool_only, .. } => {
- tool_only
- }
+ let optional_alternative = match self {
+ Implicit { optional_alternative, .. }
+ | Mixed { optional_alternative, .. }
+ | Explicit { optional_alternative, .. } => optional_alternative,
};
- *tool_only = true;
+ *optional_alternative = true;
}
}
@@ -3337,22 +3337,40 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
fn add_to_diag(self, diag: &mut Diag<'_, G>) {
use MismatchedLifetimeSyntaxesSuggestion::*;
- let style = |tool_only| {
- if tool_only { SuggestionStyle::CompletelyHidden } else { SuggestionStyle::ShowAlways }
+ let style = |optional_alternative| {
+ if optional_alternative {
+ SuggestionStyle::CompletelyHidden
+ } else {
+ SuggestionStyle::ShowAlways
+ }
+ };
+
+ let applicability = |optional_alternative| {
+ // `cargo fix` can't handle more than one fix for the same issue,
+ // so hide alternative suggestions from it by marking them as maybe-incorrect
+ if optional_alternative {
+ Applicability::MaybeIncorrect
+ } else {
+ Applicability::MachineApplicable
+ }
};
match self {
- Implicit { suggestions, tool_only } => {
+ Implicit { suggestions, optional_alternative } => {
let suggestions = suggestions.into_iter().map(|s| (s, String::new())).collect();
diag.multipart_suggestion_with_style(
fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit,
suggestions,
- Applicability::MaybeIncorrect,
- style(tool_only),
+ applicability(optional_alternative),
+ style(optional_alternative),
);
}
- Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => {
+ Mixed {
+ implicit_suggestions,
+ explicit_anonymous_suggestions,
+ optional_alternative,
+ } => {
let message = if implicit_suggestions.is_empty() {
fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths
} else {
@@ -3368,12 +3386,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
diag.multipart_suggestion_with_style(
message,
suggestions,
- Applicability::MaybeIncorrect,
- style(tool_only),
+ applicability(optional_alternative),
+ style(optional_alternative),
);
}
- Explicit { lifetime_name, suggestions, tool_only } => {
+ Explicit { lifetime_name, suggestions, optional_alternative } => {
diag.arg("lifetime_name", lifetime_name);
let msg = diag.eagerly_translate(
fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit,
@@ -3382,8 +3400,8 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
diag.multipart_suggestion_with_style(
msg,
suggestions,
- Applicability::MaybeIncorrect,
- style(tool_only),
+ applicability(optional_alternative),
+ style(optional_alternative),
);
}
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 3b84c6b61101..e660b9502627 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2156,6 +2156,7 @@ declare_lint! {
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
reference: "issue #52234 ",
+ report_in_deps: true,
};
crate_level_only
}
@@ -2839,7 +2840,7 @@ declare_lint! {
/// [issue #79813]: https://github.com/rust-lang/rust/issues/79813
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
- Warn,
+ Deny,
"trailing semicolon in macro body used as expression",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
@@ -2887,11 +2888,12 @@ declare_lint! {
/// struct S { /* fields */ }
/// ```
pub LEGACY_DERIVE_HELPERS,
- Warn,
+ Deny,
"detects derive helper attributes that are used before they are introduced",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
reference: "issue #79202 ",
+ report_in_deps: true,
};
}
@@ -4624,11 +4626,12 @@ declare_lint! {
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub PRIVATE_MACRO_USE,
- Warn,
+ Deny,
"detects certain macro bindings that should not be re-exported",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
reference: "issue #120192 ",
+ report_in_deps: true,
};
}
@@ -4828,7 +4831,7 @@ declare_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```rust,compile_fail
/// #![doc = in_root!()]
///
/// macro_rules! in_root { () => { "" } }
@@ -4853,11 +4856,12 @@ declare_lint! {
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub OUT_OF_SCOPE_MACRO_CALLS,
- Warn,
+ Deny,
"detects out of scope calls to `macro_rules` in key-value attributes",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
reference: "issue #124535 ",
+ report_in_deps: true,
};
}
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 069b684ad09b..6c740156c4d1 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -171,6 +171,16 @@ fn main() {
let cxxflags = output(&mut cmd);
let mut cfg = cc::Build::new();
cfg.warnings(false);
+
+ // Prevent critical warnings when we're compiling from rust-lang/rust CI,
+ // except on MSVC, as the compiler throws warnings that are only reported
+ // for this platform. See https://github.com/rust-lang/rust/pull/145031#issuecomment-3162677202
+ // FIXME(llvm22): It looks like the specific problem code has been removed
+ // in https://github.com/llvm/llvm-project/commit/e8fc808bf8e78a3c80d1f8e293a92677b92366dd,
+ // retry msvc once we bump our LLVM version.
+ if std::env::var_os("CI").is_some() && !target.contains("msvc") {
+ cfg.warnings_into_errors(true);
+ }
for flag in cxxflags.split_whitespace() {
// Ignore flags like `-m64` when we're doing a cross build
if is_crossed && flag.starts_with("-m") {
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 4695de8ea09a..22e7c7a160ff 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -37,28 +37,6 @@ static coverage::Counter fromRust(LLVMRustCounter Counter) {
report_fatal_error("Bad LLVMRustCounterKind!");
}
-struct LLVMRustMCDCDecisionParameters {
- uint32_t BitmapIdx;
- uint16_t NumConditions;
-};
-
-struct LLVMRustMCDCBranchParameters {
- int16_t ConditionID;
- int16_t ConditionIDs[2];
-};
-
-static coverage::mcdc::BranchParameters
-fromRust(LLVMRustMCDCBranchParameters Params) {
- return coverage::mcdc::BranchParameters(
- Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]});
-}
-
-static coverage::mcdc::DecisionParameters
-fromRust(LLVMRustMCDCDecisionParameters Params) {
- return coverage::mcdc::DecisionParameters(Params.BitmapIdx,
- Params.NumConditions);
-}
-
// Must match the layout of
// `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`.
struct LLVMRustCoverageSpan {
@@ -90,22 +68,6 @@ struct LLVMRustCoverageBranchRegion {
LLVMRustCounter FalseCount;
};
-// Must match the layout of
-// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`.
-struct LLVMRustCoverageMCDCBranchRegion {
- LLVMRustCoverageSpan Span;
- LLVMRustCounter TrueCount;
- LLVMRustCounter FalseCount;
- LLVMRustMCDCBranchParameters MCDCBranchParams;
-};
-
-// Must match the layout of
-// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`.
-struct LLVMRustCoverageMCDCDecisionRegion {
- LLVMRustCoverageSpan Span;
- LLVMRustMCDCDecisionParameters MCDCDecisionParams;
-};
-
// FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind`
// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L154
enum class LLVMRustCounterExprKind {
@@ -159,10 +121,7 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
const LLVMRustCoverageExpansionRegion *ExpansionRegions,
size_t NumExpansionRegions,
const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions,
- const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
- size_t NumMCDCBranchRegions,
- const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions,
- size_t NumMCDCDecisionRegions, RustStringRef BufferOut) {
+ RustStringRef BufferOut) {
// Convert from FFI representation to LLVM representation.
// Expressions:
@@ -176,8 +135,8 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
}
std::vector MappingRegions;
- MappingRegions.reserve(NumCodeRegions + NumBranchRegions +
- NumMCDCBranchRegions + NumMCDCDecisionRegions);
+ MappingRegions.reserve(NumCodeRegions + NumExpansionRegions +
+ NumBranchRegions);
// Code regions:
for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) {
@@ -201,24 +160,6 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
Region.Span.LineEnd, Region.Span.ColumnEnd));
}
- // MC/DC branch regions:
- for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) {
- MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
- fromRust(Region.TrueCount), fromRust(Region.FalseCount),
- Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
- Region.Span.LineEnd, Region.Span.ColumnEnd,
- fromRust(Region.MCDCBranchParams)));
- }
-
- // MC/DC decision regions:
- for (const auto &Region :
- ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) {
- MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion(
- fromRust(Region.MCDCDecisionParams), Region.Span.FileID,
- Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd,
- Region.Span.ColumnEnd));
- }
-
// Write the converted expressions and mappings to a byte buffer.
auto CoverageMappingWriter = coverage::CoverageMappingWriter(
ArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 8855766ca98f..958e314efabb 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -83,7 +83,7 @@ pub fn walk_native_lib_search_dirs(
// Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
// we must have the support library stubs in the library search path (#121430).
if let Some(sdk_root) = apple_sdk_root
- && sess.target.llvm_target.contains("macabi")
+ && sess.target.env == "macabi"
{
f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index ff9f77be9455..d42c8b947a48 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -19,13 +19,12 @@ use rustc_hir::find_attr;
use rustc_hir_pretty::id_to_string;
use rustc_middle::dep_graph::WorkProductId;
use rustc_middle::middle::dependency_format::Linkage;
-use rustc_middle::middle::exported_symbols::metadata_symbol_name;
use rustc_middle::mir::interpret;
use rustc_middle::query::Providers;
use rustc_middle::traits::specialization_graph;
+use rustc_middle::ty::AssocItemContainer;
use rustc_middle::ty::codec::TyEncoder;
use rustc_middle::ty::fast_reject::{self, TreatParams};
-use rustc_middle::ty::{AssocItemContainer, SymbolName};
use rustc_middle::{bug, span_bug};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
use rustc_session::config::{CrateType, OptLevel, TargetModifier};
@@ -2207,19 +2206,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)],
) -> LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)> {
empty_proc_macro!(self);
- // The metadata symbol name is special. It should not show up in
- // downstream crates.
- let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx));
- self.lazy_array(
- exported_symbols
- .iter()
- .filter(|&(exported_symbol, _)| match *exported_symbol {
- ExportedSymbol::NoDefId(symbol_name) => symbol_name != metadata_symbol_name,
- _ => true,
- })
- .cloned(),
- )
+ self.lazy_array(exported_symbols.iter().cloned())
}
fn encode_dylib_dependency_formats(&mut self) -> LazyArray