diff options
| author | The Miri Cronjob Bot <miri@cron.bot> | 2025-08-27 05:00:43 +0000 |
|---|---|---|
| committer | The Miri Cronjob Bot <miri@cron.bot> | 2025-08-27 05:00:43 +0000 |
| commit | aa583798abbead86c01450106088efba8dc0d54e (patch) | |
| tree | d3bde15db472993fc1d801f93f3c86ab8f669971 | |
| parent | a10bdf93b153211e5daf1b1c147b955e690e30ef (diff) | |
| parent | b8160e9f38329c5c17f642f3e7e8ac702375dad5 (diff) | |
| download | rust-aa583798abbead86c01450106088efba8dc0d54e.tar.gz rust-aa583798abbead86c01450106088efba8dc0d54e.zip | |
Merge ref '269d5b56bcfd' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref: 269d5b56bcfdf2be82213e72ef9a2e4c592a8c6b Filtered ref: a221b1d3ebb78ec8a01dcb1fe6bb165378e2f5c9 This merge was created using https://github.com/rust-lang/josh-sync.
310 files changed, 5533 insertions, 2776 deletions
diff --git a/Cargo.lock b/Cargo.lock index af206e87c45..af7c24abd13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.2" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "blake3" @@ -5988,9 +5988,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "34.0.2" +version = "36.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33696c5f1ff1e083de9f36c3da471abd736362bc173e093f8b0b1ed5a387e39b" +checksum = "20689c88791776219f78c2529700d15e6a9bd57a27858c62e9ef8487956b571c" [[package]] name = "wasm-bindgen" @@ -6052,9 +6052,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d95124e34fee1316222e03b9bbf41af186ecbae2c8b79f8debe6e21b3ff60c5" +checksum = "14cd35d6cae91109a0ffd207b573cf3c741cab7e921dd376ea7aaf2c52a3408c" dependencies = [ "anyhow", "clap", @@ -6062,7 +6062,7 @@ dependencies = [ "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.234.0", + "wasmparser 0.237.0", "wat", "windows-sys 0.59.0", "winsplit", @@ -6089,34 +6089,24 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.234.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170a0157eef517a179f2d20ed7c68df9c3f7f6c1c047782d488bf5a464174684" -dependencies = [ - "leb128fmt", - "wasmparser 0.234.0", -] - -[[package]] -name = "wasm-encoder" -version = "0.236.1" +version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "724fccfd4f3c24b7e589d333fc0429c68042897a7e8a5f8694f31792471841e7" +checksum = "efe92d1321afa53ffc88a57c497bb7330c3cf84c98ffdba4a4caf6a0684fad3c" dependencies = [ "leb128fmt", - "wasmparser 0.236.1", + "wasmparser 0.237.0", ] [[package]] name = "wasm-metadata" -version = "0.234.0" +version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a42fe3f5cbfb56fc65311ef827930d06189160038e81db62188f66b4bf468e3a" +checksum = "4cc0b0a0c4f35ca6efa7a797671372915d4e9659dba2d59edc6fafc931d19997" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.234.0", - "wasmparser 0.234.0", + "wasm-encoder 0.237.0", + "wasmparser 0.237.0", ] [[package]] @@ -6131,46 +6121,45 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.234.0" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be22e5a8f600afce671dd53c8d2dd26b4b7aa810fd18ae27dfc49737f3e02fc5" +checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" dependencies = [ "bitflags", - "hashbrown", "indexmap", - "semver", - "serde", ] [[package]] name = "wasmparser" -version = "0.236.1" +version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" +checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250" dependencies = [ "bitflags", + "hashbrown", "indexmap", "semver", + "serde", ] [[package]] name = "wast" -version = "236.0.1" +version = "237.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3bec4b4db9c6808d394632fd4b0cd4654c32c540bd3237f55ee6a40fff6e51f" +checksum = "fcf66f545acbd55082485cb9a6daab54579cb8628a027162253e8e9f5963c767" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.1", - "wasm-encoder 0.236.1", + "wasm-encoder 0.237.0", ] [[package]] name = "wat" -version = "1.236.1" +version = "1.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64475e2f77d6071ce90624098fc236285ddafa8c3ea1fb386f2c4154b6c2bbdb" +checksum = "27975186f549e4b8d6878b627be732863883c72f7bf4dcf8f96e5f8242f73da9" dependencies = [ "wast", ] @@ -6659,9 +6648,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.234.0" +version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8888169acf4c6c4db535beb405b570eedac13215d6821ca9bd03190f7f8b8c" +checksum = "bfb7674f76c10e82fe00b256a9d4ffb2b8d037d42ab8e9a83ebb3be35c9d0bf6" dependencies = [ "anyhow", "bitflags", @@ -6670,17 +6659,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.234.0", + "wasm-encoder 0.237.0", "wasm-metadata", - "wasmparser 0.234.0", + "wasmparser 0.237.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.234.0" +version = "0.237.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465492df47d8dcc015a3b7f241aed8ea03688fee7c5e04162285c5b1a3539c8b" +checksum = "ce2596a5bc7c24cc965b56ad6ff9e32394c4e401764f89620a888519c6e849ab" dependencies = [ "anyhow", "id-arena", @@ -6691,7 +6680,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.234.0", + "wasmparser 0.237.0", ] [[package]] diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 4c18d5f8675..16fd9241a17 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -407,8 +407,11 @@ #build.profiler = false # Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics. -# Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt` -# sources are available. +# Choosing true requires the LLVM submodule to be managed by bootstrap (i.e. not external) +# so that `compiler-rt` sources are available. +# +# Setting this to a path removes the requirement for a C toolchain, but requires setting the +# path to an existing library containing the builtins library from LLVM's compiler-rt. # # Setting this to `false` generates slower code, but removes the requirement for a C toolchain in # order to run `x check`. @@ -1041,13 +1044,15 @@ #runner = <none> (string) # Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics -# on this target. -# Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt` -# sources are available. +# on this target. Choosing true requires the LLVM submodule to be managed by bootstrap +# (i.e. not external) so that `compiler-rt` sources are available. +# +# Setting this to a path removes the requirement for a C toolchain, but requires setting the +# path to an existing library containing the builtins library from LLVM's compiler-rt. # # Setting this to `false` generates slower code, but removes the requirement for a C toolchain in # order to run `x check`. -#optimized-compiler-builtins = build.optimized-compiler-builtins (bool) +#optimized-compiler-builtins = build.optimized-compiler-builtins (bool or path) # Link the compiler and LLVM against `jemalloc` instead of the default libc allocator. # This overrides the global `rust.jemalloc` option. See that option for more info. diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 40e9d597530..8f24b51f1d9 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -86,6 +86,12 @@ attr_parsing_invalid_repr_hint_no_value = attr_parsing_invalid_since = 'since' must be a Rust version number, such as "1.31.0" +attr_parsing_invalid_style = {$is_used_as_inner -> + [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` + *[other] the `#![{$name}]` attribute can only be used at the crate root + } + .note = This attribute does not have an `!`, which means it is applied to this {$target} + attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}` .note = the value may not exceed `u16::MAX` diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index b884f8f3832..ffdacff7152 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -127,6 +127,7 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser { Warn(Target::Field), Warn(Target::Arm), Warn(Target::MacroDef), + Warn(Target::MacroCall), ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); @@ -174,6 +175,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser { Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), + Warn(Target::MacroCall), ]); fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { @@ -278,6 +280,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser { Warn(Target::MacroDef), Warn(Target::Arm), Warn(Target::Field), + Warn(Target::MacroCall), ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller; } @@ -365,7 +368,8 @@ impl<S: Stage> AttributeParser<S> for UsedParser { } }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]); + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` @@ -450,6 +454,7 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser { Warn(Target::Field), Warn(Target::Arm), Warn(Target::MacroDef), + Warn(Target::MacroCall), ]); } diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 9175d7479e1..2fed09b85e8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,3 +1,5 @@ +use rustc_feature::AttributeType; + use super::prelude::*; pub(crate) struct CrateNameParser; @@ -7,6 +9,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + const TYPE: AttributeType = AttributeType::CrateLevel; // FIXME: crate name is allowed on all targets and ignored, // even though it should only be valid on crates of course diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 39d5ff85d9f..a73430c9d00 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -25,6 +25,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser { Warn(Target::MacroDef), Warn(Target::Arm), Warn(Target::AssocConst), + Warn(Target::MacroCall), ]); const TEMPLATE: AttributeTemplate = template!( Word, diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 66b02697c77..5e4551ccd79 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -110,8 +110,11 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser { const PATH: &[Symbol] = &[sym::link_ordinal]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = - AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + Warn(Target::MacroCall), + ]); const TEMPLATE: AttributeTemplate = template!( List: &["ordinal"], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute" diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 9dad9c893f0..043bc925eac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -12,11 +12,15 @@ //! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the //! contents of attributes, if an attribute appear multiple times in a list //! +//! By default, attributes are allowed anywhere. When adding an attribute that should only be used +//! at the crate root, consider setting the `TYPE` in the parser trait to +//! [`AttributeType::CrateLevel`](rustc_feature::AttributeType::CrateLevel). +//! //! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed. use std::marker::PhantomData; -use rustc_feature::{AttributeTemplate, template}; +use rustc_feature::{AttributeTemplate, AttributeType, template}; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -88,6 +92,8 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static { const ALLOWED_TARGETS: AllowedTargets; + const TYPE: AttributeType = AttributeType::Normal; + /// The parser has gotten a chance to accept the attributes on an item, /// here it can produce an attribute. /// @@ -129,6 +135,8 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static { /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; + const TYPE: AttributeType = AttributeType::Normal; + /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>; } @@ -175,6 +183,8 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> )]; const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; + const TYPE: AttributeType = T::TYPE; + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { Some(self.1?.0) } @@ -259,6 +269,7 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static { const PATH: &[Symbol]; const ON_DUPLICATE: OnDuplicate<S>; const ALLOWED_TARGETS: AllowedTargets; + const TYPE: AttributeType = AttributeType::Normal; /// Create the [`AttributeKind`] given attribute's [`Span`]. const CREATE: fn(Span) -> AttributeKind; @@ -278,6 +289,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE; const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); + const TYPE: AttributeType = T::TYPE; fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { if let Err(span) = args.no_args() { @@ -311,6 +323,8 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static { /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; + const TYPE: AttributeType = AttributeType::Normal; + /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, @@ -346,6 +360,7 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S group.items.extend(T::extend(cx, args)) })]; const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; + const TYPE: AttributeType = T::TYPE; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if let Some(first_span) = self.first_span { diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 4e6aec95e66..fc41c073fd2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -19,6 +19,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser { Warn(Target::Field), Warn(Target::Arm), Warn(Target::MacroDef), + Warn(Target::MacroCall), ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; } diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 9ac18c04e32..b9929d6f1f8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -1,11 +1,13 @@ use super::prelude::*; +const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate), Warn(Target::MacroCall)]); + pub(crate) struct ProcMacroParser; impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser { const PATH: &[Symbol] = &[sym::proc_macro]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = - AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS; const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro; } @@ -13,8 +15,7 @@ pub(crate) struct ProcMacroAttributeParser; impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser { const PATH: &[Symbol] = &[sym::proc_macro_attribute]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = - AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS; const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute; } @@ -23,8 +24,7 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser { const PATH: &[Symbol] = &[sym::proc_macro_derive]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = - AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!( List: &["TraitName", "TraitName, attributes(name1, name2, ...)"], "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros" diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 89ac1b07d16..fbd9a480fbb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -1,5 +1,7 @@ use std::mem; +use rustc_feature::AttributeType; + use super::prelude::*; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, @@ -154,6 +156,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const TYPE: AttributeType = AttributeType::CrateLevel; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore; } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d4b9cfe00ad..b16ef7edd64 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; -use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; +use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId}; use rustc_errors::{Diag, Diagnostic, Level}; -use rustc_feature::AttributeTemplate; +use rustc_feature::{AttributeTemplate, AttributeType}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrPath, HirId}; +use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; use rustc_session::Session; use rustc_span::{ErrorGuaranteed, Span, Symbol}; @@ -80,6 +80,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> { pub(super) template: AttributeTemplate, pub(super) accept_fn: AcceptFn<S>, pub(super) allowed_targets: AllowedTargets, + pub(super) attribute_type: AttributeType, } type AcceptFn<S> = @@ -129,6 +130,7 @@ macro_rules! attribute_parsers { }) }), allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS, + attribute_type: <$names as crate::attributes::AttributeParser<$stage>>::TYPE, }); } @@ -250,6 +252,8 @@ pub trait Stage: Sized + 'static + Sealed { ) -> ErrorGuaranteed; fn should_emit(&self) -> ShouldEmit; + + fn id_is_crate_root(id: Self::Id) -> bool; } // allow because it's a sealed trait @@ -271,6 +275,10 @@ impl Stage for Early { fn should_emit(&self) -> ShouldEmit { self.emit_errors } + + fn id_is_crate_root(id: Self::Id) -> bool { + id == CRATE_NODE_ID + } } // allow because it's a sealed trait @@ -292,6 +300,10 @@ impl Stage for Late { fn should_emit(&self) -> ShouldEmit { ShouldEmit::ErrorsAndLints } + + fn id_is_crate_root(id: Self::Id) -> bool { + id == CRATE_HIR_ID + } } /// used when parsing attributes for miscellaneous things *before* ast lowering diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 60523c2877c..a3558850ef3 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -271,8 +271,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }; (accept.accept_fn)(&mut cx, args); - - if !matches!(self.stage.should_emit(), ShouldEmit::Nothing) { + if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { + Self::check_type(accept.attribute_type, target, &mut cx); self.check_target( path.get_attribute_path(), attr.span, diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 069478e7f0c..b1a971eec32 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -41,8 +41,14 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi .emit_node_span_lint( // This check is here because `deprecated` had its own lint group and removing this would be a breaking change if name.segments[0].name == sym::deprecated - && ![Target::Closure, Target::Expression, Target::Statement, Target::Arm] - .contains(target) + && ![ + Target::Closure, + Target::Expression, + Target::Statement, + Target::Arm, + Target::MacroCall, + ] + .contains(target) { rustc_session::lint::builtin::USELESS_DEPRECATED } else { @@ -60,5 +66,19 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi attr_span: *span, }, ), + + &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => { + lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *span, + session_diagnostics::InvalidAttrStyle { + name: name.clone(), + is_used_as_inner, + target_span: (!is_used_as_inner).then_some(target_span), + target, + }, + ) + } } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 72bee0ddfbf..a639b55e81f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -6,7 +6,7 @@ use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, }; use rustc_feature::AttributeTemplate; -use rustc_hir::AttrPath; +use rustc_hir::{AttrPath, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -826,3 +826,13 @@ pub(crate) struct SuffixedLiteralInAttribute { #[primary_span] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_invalid_style)] +pub(crate) struct InvalidAttrStyle { + pub name: AttrPath, + pub is_used_as_inner: bool, + #[note] + pub target_span: Option<Span>, + pub target: Target, +} diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 9568b791b3f..6f4dd76fa81 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -1,13 +1,14 @@ use std::borrow::Cow; +use rustc_ast::AttrStyle; use rustc_errors::DiagArgValue; -use rustc_feature::Features; +use rustc_feature::{AttributeType, Features}; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{AttrPath, MethodKind, Target}; use rustc_span::Span; use crate::AttributeParser; -use crate::context::Stage; +use crate::context::{AcceptContext, Stage}; use crate::session_diagnostics::InvalidTarget; #[derive(Debug)] @@ -68,7 +69,7 @@ pub(crate) enum Policy { Error(Target), } -impl<S: Stage> AttributeParser<'_, S> { +impl<'sess, S: Stage> AttributeParser<'sess, S> { pub(crate) fn check_target( &self, attr_name: AttrPath, @@ -111,6 +112,32 @@ impl<S: Stage> AttributeParser<'_, S> { } } } + + pub(crate) fn check_type( + attribute_type: AttributeType, + target: Target, + cx: &mut AcceptContext<'_, 'sess, S>, + ) { + let is_crate_root = S::id_is_crate_root(cx.target_id); + + if is_crate_root { + return; + } + + if attribute_type != AttributeType::CrateLevel { + return; + } + + let lint = AttributeLintKind::InvalidStyle { + name: cx.attr_path.clone(), + is_used_as_inner: cx.attr_style == AttrStyle::Inner, + target, + target_span: cx.target_span, + }; + let attr_span = cx.attr_span; + + cx.emit_lint(lint, attr_span); + } } /// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to. diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 1c4ff5a6779..54897371410 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -17,7 +17,7 @@ pub use super::polonius::legacy::{ RichLocation, RustcFacts, }; pub use super::region_infer::RegionInferenceContext; -use crate::{BorrowCheckRootCtxt, do_mir_borrowck}; +use crate::BorrowCheckRootCtxt; /// Struct used during mir borrowck to collect bodies with facts for a typeck root and all /// its nested bodies. @@ -127,13 +127,6 @@ pub fn get_bodies_with_borrowck_facts( ) -> FxHashMap<LocalDefId, BodyWithBorrowckFacts<'_>> { let mut root_cx = BorrowCheckRootCtxt::new(tcx, root_def_id, Some(BorrowckConsumer::new(options))); - - // See comment in `rustc_borrowck::mir_borrowck` - let nested_bodies = tcx.nested_bodies_within(root_def_id); - for def_id in nested_bodies { - root_cx.get_or_insert_nested(def_id); - } - - do_mir_borrowck(&mut root_cx, root_def_id); + root_cx.do_mir_borrowck(); root_cx.consumer.unwrap().bodies } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index ce78ae203a4..5d2dda8b0e7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -22,8 +22,10 @@ use std::ops::{ControlFlow, Deref}; use std::rc::Rc; use borrow_set::LocalsStateAtExit; +use polonius_engine::AllFacts; use root_cx::BorrowCheckRootCtxt; use rustc_abi::FieldIdx; +use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::LintDiagnostic; @@ -32,6 +34,7 @@ use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; +use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; @@ -53,7 +56,7 @@ use smallvec::SmallVec; use tracing::{debug, instrument}; use crate::borrow_set::{BorrowData, BorrowSet}; -use crate::consumers::BodyWithBorrowckFacts; +use crate::consumers::{BodyWithBorrowckFacts, RustcFacts}; use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows}; use crate::diagnostics::{ AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName, @@ -61,15 +64,17 @@ use crate::diagnostics::{ use crate::path_utils::*; use crate::place_ext::PlaceExt; use crate::places_conflict::{PlaceConflictBias, places_conflict}; -use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, }; +use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext}; use crate::prefixes::PrefixSet; use crate::region_infer::RegionInferenceContext; +use crate::region_infer::opaque_types::DeferredOpaqueTypeError; use crate::renumber::RegionCtxt; use crate::session_diagnostics::VarNeedNotMut; -use crate::type_check::MirTypeckResults; +use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::type_check::{Locations, MirTypeckRegionConstraints, MirTypeckResults}; mod borrow_set; mod borrowck_errors; @@ -129,18 +134,7 @@ fn mir_borrowck( Ok(tcx.arena.alloc(opaque_types)) } else { let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None); - // We need to manually borrowck all nested bodies from the HIR as - // we do not generate MIR for dead code. Not doing so causes us to - // never check closures in dead code. - let nested_bodies = tcx.nested_bodies_within(def); - for def_id in nested_bodies { - root_cx.get_or_insert_nested(def_id); - } - - let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } = - do_mir_borrowck(&mut root_cx, def); - debug_assert!(closure_requirements.is_none()); - debug_assert!(used_mut_upvars.is_empty()); + root_cx.do_mir_borrowck(); root_cx.finalize() } } @@ -153,6 +147,8 @@ struct PropagatedBorrowCheckResults<'tcx> { used_mut_upvars: SmallVec<[FieldIdx; 8]>, } +type DeferredClosureRequirements<'tcx> = Vec<(LocalDefId, ty::GenericArgsRef<'tcx>, Locations)>; + /// After we borrow check a closure, we are left with various /// requirements that we have inferred between the free regions that /// appear in the closure's signature or on its field types. These @@ -291,14 +287,31 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { } } -/// Perform the actual borrow checking. -/// -/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`. -#[instrument(skip(root_cx), level = "debug")] -fn do_mir_borrowck<'tcx>( +struct CollectRegionConstraintsResult<'tcx> { + infcx: BorrowckInferCtxt<'tcx>, + body_owned: Body<'tcx>, + promoted: IndexVec<Promoted, Body<'tcx>>, + move_data: MoveData<'tcx>, + borrow_set: BorrowSet<'tcx>, + location_table: PoloniusLocationTable, + location_map: Rc<DenseLocationMap>, + universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, + region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>, + known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>, + constraints: MirTypeckRegionConstraints<'tcx>, + deferred_closure_requirements: DeferredClosureRequirements<'tcx>, + deferred_opaque_type_errors: Vec<DeferredOpaqueTypeError<'tcx>>, + polonius_facts: Option<AllFacts<RustcFacts>>, + polonius_context: Option<PoloniusContext>, +} + +/// Start borrow checking by collecting the region constraints for +/// the current body. This initializes the relevant data structures +/// and then type checks the MIR body. +fn borrowck_collect_region_constraints<'tcx>( root_cx: &mut BorrowCheckRootCtxt<'tcx>, def: LocalDefId, -) -> PropagatedBorrowCheckResults<'tcx> { +) -> CollectRegionConstraintsResult<'tcx> { let tcx = root_cx.tcx; let infcx = BorrowckInferCtxt::new(tcx, def, root_cx.root_def_id()); let (input_body, promoted) = tcx.mir_promoted(def); @@ -334,10 +347,11 @@ fn do_mir_borrowck<'tcx>( // Run the MIR type-checker. let MirTypeckResults { - mut constraints, + constraints, universal_region_relations, region_bound_pairs, known_type_outlives_obligations, + deferred_closure_requirements, polonius_context, } = type_check::type_check( root_cx, @@ -352,16 +366,53 @@ fn do_mir_borrowck<'tcx>( Rc::clone(&location_map), ); - let opaque_type_errors = region_infer::opaque_types::handle_opaque_type_uses( - root_cx, - &infcx, - &body, - &universal_region_relations, - ®ion_bound_pairs, - &known_type_outlives_obligations, - &location_map, - &mut constraints, - ); + CollectRegionConstraintsResult { + infcx, + body_owned, + promoted, + move_data, + borrow_set, + location_table, + location_map, + universal_region_relations, + region_bound_pairs, + known_type_outlives_obligations, + constraints, + deferred_closure_requirements, + deferred_opaque_type_errors: Default::default(), + polonius_facts, + polonius_context, + } +} + +/// Using the region constraints computed by [borrowck_collect_region_constraints] +/// and the additional constraints from [BorrowCheckRootCtxt::handle_opaque_type_uses], +/// compute the region graph and actually check for any borrowck errors. +fn borrowck_check_region_constraints<'tcx>( + root_cx: &mut BorrowCheckRootCtxt<'tcx>, + CollectRegionConstraintsResult { + infcx, + body_owned, + promoted, + move_data, + borrow_set, + location_table, + location_map, + universal_region_relations, + region_bound_pairs: _, + known_type_outlives_obligations: _, + constraints, + deferred_closure_requirements, + deferred_opaque_type_errors, + polonius_facts, + polonius_context, + }: CollectRegionConstraintsResult<'tcx>, +) -> PropagatedBorrowCheckResults<'tcx> { + assert!(!infcx.has_opaque_types_in_storage()); + assert!(deferred_closure_requirements.is_empty()); + let tcx = root_cx.tcx; + let body = &body_owned; + let def = body.source.def_id().expect_local(); // Compute non-lexical lifetimes using the constraints computed // by typechecking the MIR body. @@ -481,7 +532,7 @@ fn do_mir_borrowck<'tcx>( // Compute and report region errors, if any. if nll_errors.is_empty() { - mbcx.report_opaque_type_errors(opaque_type_errors); + mbcx.report_opaque_type_errors(deferred_opaque_type_errors); } else { mbcx.report_region_errors(nll_errors); } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 8608a8a3a66..1517a683531 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -73,6 +73,38 @@ pub(crate) fn replace_regions_in_mir<'tcx>( universal_regions } +/// Computes the closure requirements given the current inference state. +/// +/// This is intended to be used by before [BorrowCheckRootCtxt::handle_opaque_type_uses] +/// because applying member constraints may rely on closure requirements. +/// This is frequently the case of async functions where pretty much everything +/// happens inside of the inner async block but the opaque only gets constrained +/// in the parent function. +pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>( + infcx: &BorrowckInferCtxt<'tcx>, + body: &Body<'tcx>, + location_map: Rc<DenseLocationMap>, + universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>, + constraints: &MirTypeckRegionConstraints<'tcx>, +) -> Option<ClosureRegionRequirements<'tcx>> { + // FIXME(#146079): we shouldn't have to clone all this stuff here. + // Computing the region graph should take at least some of it by reference/`Rc`. + let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints( + constraints.clone(), + &universal_region_relations, + infcx, + ); + let mut regioncx = RegionInferenceContext::new( + &infcx, + lowered_constraints, + universal_region_relations.clone(), + location_map, + ); + + let (closure_region_requirements, _nll_errors) = regioncx.solve(infcx, body, None); + closure_region_requirements +} + /// Computes the (non-lexical) regions from the input MIR. /// /// This may result in errors being reported. diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 33c4879af98..72615cb33b3 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -3,34 +3,34 @@ use std::rc::Rc; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries}; use rustc_infer::traits::ObligationCause; use rustc_macros::extension; -use rustc_middle::mir::{Body, ConstraintCategory}; +use rustc_middle::mir::{Body, ConcreteOpaqueTypes, ConstraintCategory}; use rustc_middle::ty::{ - self, DefiningScopeKind, FallibleTypeFolder, GenericArg, GenericArgsRef, OpaqueHiddenType, - OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, - TypeVisitableExt, fold_regions, + self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef, + OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, + TypeSuperFoldable, TypeVisitableExt, fold_regions, }; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; use rustc_trait_selection::opaque_types::{ - InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid, + NonDefiningUseReason, opaque_type_has_defining_use_args, }; use rustc_trait_selection::solve::NoSolution; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use tracing::{debug, instrument}; use super::reverse_sccs::ReverseSccGraph; +use crate::BorrowckInferCtxt; use crate::consumers::RegionInferenceContext; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::type_check::canonical::fully_perform_op_raw; use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::{RegionClassification, UniversalRegions}; -use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt}; mod member_constraints; mod region_ctxt; @@ -42,7 +42,7 @@ use region_ctxt::RegionCtxt; /// if there are no `RegionErrors`. If there are region errors, it's likely /// that errors here are caused by them and don't need to be handled separately. pub(crate) enum DeferredOpaqueTypeError<'tcx> { - InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>), + InvalidOpaqueTypeArgs(NonDefiningUseReason<'tcx>), LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>), UnexpectedHiddenRegion { /// The opaque type. @@ -58,78 +58,32 @@ pub(crate) enum DeferredOpaqueTypeError<'tcx> { }, } -/// This looks at all uses of opaque types in their defining scope inside -/// of this function. +/// We eagerly map all regions to NLL vars here, as we need to make sure we've +/// introduced nll vars for all used placeholders. /// -/// It first uses all defining uses to compute the actual concrete type of each -/// opaque type definition. -/// -/// We then apply this inferred type to actually check all uses of the opaque. -pub(crate) fn handle_opaque_type_uses<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, +/// We need to resolve inference vars as even though we're in MIR typeck, we may still +/// encounter inference variables, e.g. when checking user types. +pub(crate) fn clone_and_resolve_opaque_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - body: &Body<'tcx>, universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>, - region_bound_pairs: &RegionBoundPairs<'tcx>, - known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>], - location_map: &Rc<DenseLocationMap>, constraints: &mut MirTypeckRegionConstraints<'tcx>, -) -> Vec<DeferredOpaqueTypeError<'tcx>> { - let tcx = infcx.tcx; +) -> (OpaqueTypeStorageEntries, Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>) { let opaque_types = infcx.clone_opaque_types(); - if opaque_types.is_empty() { - return Vec::new(); - } - - // We need to eagerly map all regions to NLL vars here, as we need to make sure we've - // introduced nll vars for all used placeholders. - // - // We need to resolve inference vars as even though we're in MIR typeck, we may still - // encounter inference variables, e.g. when checking user types. let opaque_types_storage_num_entries = infcx.inner.borrow_mut().opaque_types().num_entries(); let opaque_types = opaque_types .into_iter() .map(|entry| { - fold_regions(tcx, infcx.resolve_vars_if_possible(entry), |r, _| { + fold_regions(infcx.tcx, infcx.resolve_vars_if_possible(entry), |r, _| { let vid = if let ty::RePlaceholder(placeholder) = r.kind() { constraints.placeholder_region(infcx, placeholder).as_var() } else { universal_region_relations.universal_regions.to_region_vid(r) }; - Region::new_var(tcx, vid) + Region::new_var(infcx.tcx, vid) }) }) .collect::<Vec<_>>(); - - debug!(?opaque_types); - - let errors = compute_concrete_opaque_types( - root_cx, - infcx, - constraints, - universal_region_relations, - Rc::clone(location_map), - &opaque_types, - ); - - if !errors.is_empty() { - return errors; - } - - let errors = apply_computed_concrete_opaque_types( - root_cx, - infcx, - body, - &universal_region_relations.universal_regions, - region_bound_pairs, - known_type_outlives_obligations, - constraints, - &opaque_types, - ); - - detect_opaque_types_added_while_handling_opaque_types(infcx, opaque_types_storage_num_entries); - - errors + (opaque_types_storage_num_entries, opaque_types) } /// Maps an NLL var to a deterministically chosen equal universal region. @@ -172,6 +126,42 @@ fn nll_var_to_universal_region<'tcx>( } } +/// Collect all defining uses of opaque types inside of this typeck root. This +/// expects the hidden type to be mapped to the definition parameters of the opaque +/// and errors if we end up with distinct hidden types. +fn add_concrete_opaque_type<'tcx>( + tcx: TyCtxt<'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + def_id: LocalDefId, + hidden_ty: OpaqueHiddenType<'tcx>, +) { + // Sometimes two opaque types are the same only after we remap the generic parameters + // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to + // `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we + // only know that once we convert the generic parameters to those of the opaque type. + if let Some(prev) = concrete_opaque_types.0.get_mut(&def_id) { + if prev.ty != hidden_ty.ty { + let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { + let (Ok(e) | Err(e)) = prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit()); + e + }); + prev.ty = Ty::new_error(tcx, guar); + } + // Pick a better span if there is one. + // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. + prev.span = prev.span.substitute_dummy(hidden_ty.span); + } else { + concrete_opaque_types.0.insert(def_id, hidden_ty); + } +} + +fn get_concrete_opaque_type<'tcx>( + concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>, + def_id: LocalDefId, +) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> { + concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) +} + #[derive(Debug)] struct DefiningUse<'tcx> { /// The opaque type using non NLL vars. This uses the actual @@ -193,12 +183,12 @@ struct DefiningUse<'tcx> { /// /// It also means that this whole function is not really soundness critical as we /// recheck all uses of the opaques regardless. -fn compute_concrete_opaque_types<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, +pub(crate) fn compute_concrete_opaque_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - constraints: &MirTypeckRegionConstraints<'tcx>, universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>, + constraints: &MirTypeckRegionConstraints<'tcx>, location_map: Rc<DenseLocationMap>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec<DeferredOpaqueTypeError<'tcx>> { let mut errors = Vec::new(); @@ -211,7 +201,8 @@ fn compute_concrete_opaque_types<'tcx>( // We start by checking each use of an opaque type during type check and // check whether the generic arguments of the opaque type are fully // universal, if so, it's a defining use. - let defining_uses = collect_defining_uses(root_cx, &mut rcx, opaque_types, &mut errors); + let defining_uses = + collect_defining_uses(&mut rcx, concrete_opaque_types, opaque_types, &mut errors); // We now compute and apply member constraints for all regions in the hidden // types of each defining use. This mutates the region values of the `rcx` which @@ -221,14 +212,19 @@ fn compute_concrete_opaque_types<'tcx>( // After applying member constraints, we now check whether all member regions ended // up equal to one of their choice regions and compute the actual concrete type of // the opaque type definition. This is stored in the `root_cx`. - compute_concrete_types_from_defining_uses(root_cx, &rcx, &defining_uses, &mut errors); + compute_concrete_types_from_defining_uses( + &rcx, + concrete_opaque_types, + &defining_uses, + &mut errors, + ); errors } #[instrument(level = "debug", skip_all, ret)] fn collect_defining_uses<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, rcx: &mut RegionCtxt<'_, 'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>, ) -> Vec<DefiningUse<'tcx>> { @@ -238,7 +234,7 @@ fn collect_defining_uses<'tcx>( let non_nll_opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |r| { nll_var_to_universal_region(&rcx, r.as_var()).unwrap_or(r) }); - if let Err(err) = check_opaque_type_parameter_valid( + if let Err(err) = opaque_type_has_defining_use_args( infcx, non_nll_opaque_type_key, hidden_type.span, @@ -248,11 +244,12 @@ fn collect_defining_uses<'tcx>( // with `TypingMode::Borrowck`. if infcx.tcx.use_typing_mode_borrowck() { match err { - InvalidOpaqueTypeArgs::AlreadyReported(guar) => root_cx - .add_concrete_opaque_type( - opaque_type_key.def_id, - OpaqueHiddenType::new_error(infcx.tcx, guar), - ), + NonDefiningUseReason::Tainted(guar) => add_concrete_opaque_type( + infcx.tcx, + concrete_opaque_types, + opaque_type_key.def_id, + OpaqueHiddenType::new_error(infcx.tcx, guar), + ), _ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"), } } else { @@ -281,8 +278,8 @@ fn collect_defining_uses<'tcx>( } fn compute_concrete_types_from_defining_uses<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, rcx: &RegionCtxt<'_, 'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, defining_uses: &[DefiningUse<'tcx>], errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>, ) { @@ -361,7 +358,9 @@ fn compute_concrete_types_from_defining_uses<'tcx>( }, )); } - root_cx.add_concrete_opaque_type( + add_concrete_opaque_type( + tcx, + concrete_opaque_types, opaque_type_key.def_id, OpaqueHiddenType { span: hidden_type.span, ty }, ); @@ -490,20 +489,20 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> { /// /// It does this by equating the hidden type of each use with the instantiated final /// hidden type of the opaque. -fn apply_computed_concrete_opaque_types<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, +pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, universal_regions: &UniversalRegions<'tcx>, region_bound_pairs: &RegionBoundPairs<'tcx>, known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>], constraints: &mut MirTypeckRegionConstraints<'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec<DeferredOpaqueTypeError<'tcx>> { let tcx = infcx.tcx; let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { - let Some(expected) = root_cx.get_concrete_opaque_type(key.def_id) else { + let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else { assert!(tcx.use_typing_mode_borrowck(), "non-defining use in defining scope"); errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope { span: hidden_type.span, @@ -513,7 +512,12 @@ fn apply_computed_concrete_opaque_types<'tcx>( hidden_type.span, "non-defining use in the defining scope with no defining uses", ); - root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar)); + add_concrete_opaque_type( + tcx, + concrete_opaque_types, + key.def_id, + OpaqueHiddenType::new_error(tcx, guar), + ); continue; }; @@ -553,7 +557,12 @@ fn apply_computed_concrete_opaque_types<'tcx>( "equating opaque types", ), ) { - root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar)); + add_concrete_opaque_type( + tcx, + concrete_opaque_types, + key.def_id, + OpaqueHiddenType::new_error(tcx, guar), + ); } } errors @@ -566,7 +575,7 @@ fn apply_computed_concrete_opaque_types<'tcx>( /// an ICE we can properly handle this, but we haven't encountered any such test yet. /// /// See the related comment in `FnCtxt::detect_opaque_types_added_during_writeback`. -fn detect_opaque_types_added_while_handling_opaque_types<'tcx>( +pub(crate) fn detect_opaque_types_added_while_handling_opaque_types<'tcx>( infcx: &InferCtxt<'tcx>, opaque_types_storage_num_entries: OpaqueTypeStorageEntries, ) { @@ -676,8 +685,8 @@ impl<'tcx> InferCtxt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - ) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> { - check_opaque_type_parameter_valid( + ) -> Result<Ty<'tcx>, NonDefiningUseReason<'tcx>> { + opaque_type_has_defining_use_args( self, opaque_type_key, instantiated_ty.span, diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index f1427218cdb..eb611fa3475 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -37,6 +37,7 @@ pub(crate) enum RegionElement { /// Records the CFG locations where each region is live. When we initially compute liveness, we use /// an interval matrix storing liveness ranges for each region-vid. +#[derive(Clone)] // FIXME(#146079) pub(crate) struct LivenessValues { /// The map from locations to points. location_map: Rc<DenseLocationMap>, @@ -194,6 +195,7 @@ impl LivenessValues { /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. #[derive(Debug, Default)] +#[derive(Clone)] // FIXME(#146079) pub(crate) struct PlaceholderIndices { indices: FxIndexSet<ty::PlaceholderRegion>, } diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index 4e90ae391bb..cd4e9683f2d 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -1,13 +1,26 @@ +use std::mem; +use std::rc::Rc; + use rustc_abi::FieldIdx; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def_id::LocalDefId; -use rustc_middle::bug; -use rustc_middle::ty::{EarlyBinder, OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::ErrorGuaranteed; use smallvec::SmallVec; use crate::consumers::BorrowckConsumer; -use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults}; +use crate::nll::compute_closure_requirements_modulo_opaques; +use crate::region_infer::opaque_types::{ + apply_computed_concrete_opaque_types, clone_and_resolve_opaque_types, + compute_concrete_opaque_types, detect_opaque_types_added_while_handling_opaque_types, +}; +use crate::type_check::{Locations, constraint_conversion}; +use crate::{ + ClosureRegionRequirements, CollectRegionConstraintsResult, ConcreteOpaqueTypes, + PropagatedBorrowCheckResults, borrowck_check_region_constraints, + borrowck_collect_region_constraints, +}; /// The shared context used by both the root as well as all its nested /// items. @@ -15,7 +28,12 @@ pub(super) struct BorrowCheckRootCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, root_def_id: LocalDefId, concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, - nested_bodies: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>, + /// The region constraints computed by [borrowck_collect_region_constraints]. This uses + /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before + /// their parents. + collect_region_constraints_results: + FxIndexMap<LocalDefId, CollectRegionConstraintsResult<'tcx>>, + propagated_borrowck_results: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>, tainted_by_errors: Option<ErrorGuaranteed>, /// This should be `None` during normal compilation. See [`crate::consumers`] for more /// information on how this is used. @@ -32,7 +50,8 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { tcx, root_def_id, concrete_opaque_types: Default::default(), - nested_bodies: Default::default(), + collect_region_constraints_results: Default::default(), + propagated_borrowck_results: Default::default(), tainted_by_errors: None, consumer, } @@ -42,83 +61,232 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { self.root_def_id } - /// Collect all defining uses of opaque types inside of this typeck root. This - /// expects the hidden type to be mapped to the definition parameters of the opaque - /// and errors if we end up with distinct hidden types. - pub(super) fn add_concrete_opaque_type( - &mut self, - def_id: LocalDefId, - hidden_ty: OpaqueHiddenType<'tcx>, - ) { - // Sometimes two opaque types are the same only after we remap the generic parameters - // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to - // `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we - // only know that once we convert the generic parameters to those of the opaque type. - if let Some(prev) = self.concrete_opaque_types.0.get_mut(&def_id) { - if prev.ty != hidden_ty.ty { - let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { - let (Ok(e) | Err(e)) = - prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit()); - e - }); - prev.ty = Ty::new_error(self.tcx, guar); - } - // Pick a better span if there is one. - // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. - prev.span = prev.span.substitute_dummy(hidden_ty.span); - } else { - self.concrete_opaque_types.0.insert(def_id, hidden_ty); - } + pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) { + self.tainted_by_errors = Some(guar); } - pub(super) fn get_concrete_opaque_type( + pub(super) fn used_mut_upvars( &mut self, - def_id: LocalDefId, - ) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> { - self.concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) + nested_body_def_id: LocalDefId, + ) -> &SmallVec<[FieldIdx; 8]> { + &self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars } - pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) { - self.tainted_by_errors = Some(guar); + pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { + if let Some(guar) = self.tainted_by_errors { + Err(guar) + } else { + Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) + } } - pub(super) fn get_or_insert_nested( - &mut self, - def_id: LocalDefId, - ) -> &PropagatedBorrowCheckResults<'tcx> { - debug_assert_eq!( - self.tcx.typeck_root_def_id(def_id.to_def_id()), - self.root_def_id.to_def_id() - ); - if !self.nested_bodies.contains_key(&def_id) { - let result = super::do_mir_borrowck(self, def_id); - if let Some(prev) = self.nested_bodies.insert(def_id, result) { - bug!("unexpected previous nested body: {prev:?}"); + fn handle_opaque_type_uses(&mut self) { + let mut per_body_info = Vec::new(); + for input in self.collect_region_constraints_results.values_mut() { + let (num_entries, opaque_types) = clone_and_resolve_opaque_types( + &input.infcx, + &input.universal_region_relations, + &mut input.constraints, + ); + input.deferred_opaque_type_errors = compute_concrete_opaque_types( + &input.infcx, + &input.universal_region_relations, + &input.constraints, + Rc::clone(&input.location_map), + &mut self.concrete_opaque_types, + &opaque_types, + ); + per_body_info.push((num_entries, opaque_types)); + } + + for (input, (opaque_types_storage_num_entries, opaque_types)) in + self.collect_region_constraints_results.values_mut().zip(per_body_info) + { + if input.deferred_opaque_type_errors.is_empty() { + input.deferred_opaque_type_errors = apply_computed_concrete_opaque_types( + &input.infcx, + &input.body_owned, + &input.universal_region_relations.universal_regions, + &input.region_bound_pairs, + &input.known_type_outlives_obligations, + &mut input.constraints, + &mut self.concrete_opaque_types, + &opaque_types, + ); } + + detect_opaque_types_added_while_handling_opaque_types( + &input.infcx, + opaque_types_storage_num_entries, + ) } + } + + /// Computing defining uses of opaques may depend on the propagated region + /// requirements of nested bodies, while applying defining uses may introduce + /// additional region requirements we need to propagate. + /// + /// This results in cyclic dependency. To compute the defining uses in parent + /// bodies, we need the closure requirements of its nested bodies, but to check + /// non-defining uses in nested bodies, we may rely on the defining uses in the + /// parent. + /// + /// We handle this issue by applying closure requirements twice. Once using the + /// region constraints from before we've handled opaque types in the nested body + /// - which is used by the parent to handle its defining uses - and once after. + /// + /// As a performance optimization, we also eagerly finish borrowck for bodies + /// which don't depend on opaque types. In this case they get removed from + /// `collect_region_constraints_results` and the final result gets put into + /// `propagated_borrowck_results`. + fn apply_closure_requirements_modulo_opaques(&mut self) { + let mut closure_requirements_modulo_opaques = FxHashMap::default(); + // We need to `mem::take` both `self.collect_region_constraints_results` and + // `input.deferred_closure_requirements` as we otherwise can't iterate over + // them while mutably using the containing struct. + let collect_region_constraints_results = + mem::take(&mut self.collect_region_constraints_results); + // We iterate over all bodies here, visiting nested bodies before their parent. + for (def_id, mut input) in collect_region_constraints_results { + // A body depends on opaque types if it either has any opaque type uses itself, + // or it has a nested body which does. + // + // If the current body does not depend on any opaque types, we eagerly compute + // its final result and write it into `self.propagated_borrowck_results`. This + // avoids having to compute its closure requirements modulo regions, as they + // are just the same as its final closure requirements. + let mut depends_on_opaques = input.infcx.has_opaque_types_in_storage(); - self.nested_bodies.get(&def_id).unwrap() + // Iterate over all nested bodies of `input`. If that nested body depends on + // opaque types, we apply its closure requirements modulo opaques. Otherwise + // we use the closure requirements from its final borrowck result. + // + // In case we've only applied the closure requirements modulo opaques, we have + // to later apply its closure requirements considering opaques, so we put that + // nested body back into `deferred_closure_requirements`. + for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) { + let closure_requirements = match self.propagated_borrowck_results.get(&def_id) { + None => { + depends_on_opaques = true; + input.deferred_closure_requirements.push((def_id, args, locations)); + &closure_requirements_modulo_opaques[&def_id] + } + Some(result) => &result.closure_requirements, + }; + + Self::apply_closure_requirements( + &mut input, + closure_requirements, + def_id, + args, + locations, + ); + } + + // In case the current body does depend on opaques and is a nested body, + // we need to compute its closure requirements modulo opaques so that + // we're able to use it when visiting its parent later in this function. + // + // If the current body does not depend on opaque types, we finish borrowck + // and write its result into `propagated_borrowck_results`. + if depends_on_opaques { + if def_id != self.root_def_id { + let req = Self::compute_closure_requirements_modulo_opaques(&input); + closure_requirements_modulo_opaques.insert(def_id, req); + } + self.collect_region_constraints_results.insert(def_id, input); + } else { + assert!(input.deferred_closure_requirements.is_empty()); + let result = borrowck_check_region_constraints(self, input); + self.propagated_borrowck_results.insert(def_id, result); + } + } } - pub(super) fn closure_requirements( - &mut self, - nested_body_def_id: LocalDefId, - ) -> &Option<ClosureRegionRequirements<'tcx>> { - &self.get_or_insert_nested(nested_body_def_id).closure_requirements + fn compute_closure_requirements_modulo_opaques( + input: &CollectRegionConstraintsResult<'tcx>, + ) -> Option<ClosureRegionRequirements<'tcx>> { + compute_closure_requirements_modulo_opaques( + &input.infcx, + &input.body_owned, + Rc::clone(&input.location_map), + &input.universal_region_relations, + &input.constraints, + ) } - pub(super) fn used_mut_upvars( - &mut self, - nested_body_def_id: LocalDefId, - ) -> &SmallVec<[FieldIdx; 8]> { - &self.get_or_insert_nested(nested_body_def_id).used_mut_upvars + fn apply_closure_requirements( + input: &mut CollectRegionConstraintsResult<'tcx>, + closure_requirements: &Option<ClosureRegionRequirements<'tcx>>, + closure_def_id: LocalDefId, + args: ty::GenericArgsRef<'tcx>, + locations: Locations, + ) { + if let Some(closure_requirements) = closure_requirements { + constraint_conversion::ConstraintConversion::new( + &input.infcx, + &input.universal_region_relations.universal_regions, + &input.region_bound_pairs, + &input.known_type_outlives_obligations, + locations, + input.body_owned.span, // irrelevant; will be overridden. + ConstraintCategory::Boring, // same as above. + &mut input.constraints, + ) + .apply_closure_requirements(closure_requirements, closure_def_id, args); + } } - pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { - if let Some(guar) = self.tainted_by_errors { - Err(guar) - } else { - Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) + pub(super) fn do_mir_borrowck(&mut self) { + // The list of all bodies we need to borrowck. This first looks at + // nested bodies, and then their parents. This means accessing e.g. + // `used_mut_upvars` for a closure can assume that we've already + // checked that closure. + let all_bodies = self + .tcx + .nested_bodies_within(self.root_def_id) + .iter() + .chain(std::iter::once(self.root_def_id)); + for def_id in all_bodies { + let result = borrowck_collect_region_constraints(self, def_id); + self.collect_region_constraints_results.insert(def_id, result); + } + + // We now apply the closure requirements of nested bodies modulo + // regions. In case a body does not depend on opaque types, we + // eagerly check its region constraints and use the final closure + // requirements. + // + // We eagerly finish borrowck for bodies which don't depend on + // opaques. + self.apply_closure_requirements_modulo_opaques(); + + // We handle opaque type uses for all bodies together. + self.handle_opaque_type_uses(); + + // Now walk over all bodies which depend on opaque types and finish borrowck. + // + // We first apply the final closure requirements from nested bodies which also + // depend on opaque types and then finish borrow checking the parent. Bodies + // which don't depend on opaques have already been fully borrowchecked in + // `apply_closure_requirements_modulo_opaques` as an optimization. + for (def_id, mut input) in mem::take(&mut self.collect_region_constraints_results) { + for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) { + // We visit nested bodies before their parent, so we're already + // done with nested bodies at this point. + let closure_requirements = + &self.propagated_borrowck_results[&def_id].closure_requirements; + Self::apply_closure_requirements( + &mut input, + closure_requirements, + def_id, + args, + locations, + ); + } + + let result = borrowck_check_region_constraints(self, input); + self.propagated_borrowck_results.insert(def_id, result); } } } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 7bf2df91470..d27a73535ba 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -19,6 +19,7 @@ use crate::type_check::{Locations, MirTypeckRegionConstraints, constraint_conver use crate::universal_regions::UniversalRegions; #[derive(Debug)] +#[derive(Clone)] // FIXME(#146079) pub(crate) struct UniversalRegionRelations<'tcx> { pub(crate) universal_regions: UniversalRegions<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e55f5b7b43e..02be78f90b0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -34,6 +34,7 @@ use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; use rustc_span::{Span, sym}; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument, trace}; @@ -48,7 +49,7 @@ use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderI use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use crate::universal_regions::{DefiningTy, UniversalRegions}; -use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, path_utils}; +use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, DeferredClosureRequirements, path_utils}; macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ @@ -66,7 +67,7 @@ macro_rules! span_mirbug { } pub(crate) mod canonical; -mod constraint_conversion; +pub(crate) mod constraint_conversion; pub(crate) mod free_region_relations; mod input_output; pub(crate) mod liveness; @@ -141,6 +142,7 @@ pub(crate) fn type_check<'tcx>( None }; + let mut deferred_closure_requirements = Default::default(); let mut typeck = TypeChecker { root_cx, infcx, @@ -156,6 +158,7 @@ pub(crate) fn type_check<'tcx>( polonius_facts, borrow_set, constraints: &mut constraints, + deferred_closure_requirements: &mut deferred_closure_requirements, polonius_liveness, }; @@ -190,6 +193,7 @@ pub(crate) fn type_check<'tcx>( universal_region_relations, region_bound_pairs, known_type_outlives_obligations, + deferred_closure_requirements, polonius_context, } } @@ -229,6 +233,7 @@ struct TypeChecker<'a, 'tcx> { polonius_facts: &'a mut Option<PoloniusFacts>, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + deferred_closure_requirements: &'a mut DeferredClosureRequirements<'tcx>, /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints. polonius_liveness: Option<PoloniusLivenessContext>, } @@ -240,11 +245,13 @@ pub(crate) struct MirTypeckResults<'tcx> { pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>, pub(crate) known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>, + pub(crate) deferred_closure_requirements: DeferredClosureRequirements<'tcx>, pub(crate) polonius_context: Option<PoloniusContext>, } /// A collection of region constraints that must be satisfied for the /// program to be considered well-typed. +#[derive(Clone)] // FIXME(#146079) pub(crate) struct MirTypeckRegionConstraints<'tcx> { /// Maps from a `ty::Placeholder` to the corresponding /// `PlaceholderIndex` bit that we will use for it. @@ -1454,68 +1461,79 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } CastKind::PtrToPtr => { let ty_from = op.ty(self.body, tcx); - let cast_ty_from = CastTy::from_ty(ty_from); - let cast_ty_to = CastTy::from_ty(*ty); - match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => { - let src_tail = self.struct_tail(src.ty, location); - let dst_tail = self.struct_tail(dst.ty, location); - - // This checks (lifetime part of) vtable validity for pointer casts, - // which is irrelevant when there are aren't principal traits on - // both sides (aka only auto traits). - // - // Note that other checks (such as denying `dyn Send` -> `dyn - // Debug`) are in `rustc_hir_typeck`. - if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind() - && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind() - && src_tty.principal().is_some() - && dst_tty.principal().is_some() - { - // Remove auto traits. - // Auto trait checks are handled in `rustc_hir_typeck` as FCW. - let src_obj = Ty::new_dynamic( - tcx, - tcx.mk_poly_existential_predicates( - &src_tty.without_auto_traits().collect::<Vec<_>>(), - ), - // FIXME: Once we disallow casting `*const dyn Trait + 'short` - // to `*const dyn Trait + 'long`, then this can just be `src_lt`. - dst_lt, - ty::Dyn, - ); - let dst_obj = Ty::new_dynamic( - tcx, - tcx.mk_poly_existential_predicates( - &dst_tty.without_auto_traits().collect::<Vec<_>>(), - ), - dst_lt, - ty::Dyn, - ); - - debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); - - self.sub_types( - src_obj, - dst_obj, - location.to_locations(), - ConstraintCategory::Cast { - is_implicit_coercion: false, - unsize_to: None, - }, - ) - .unwrap(); - } - } - _ => { - span_mirbug!( - self, - rvalue, - "Invalid PtrToPtr cast {:?} -> {:?}", - ty_from, - ty - ) - } + let Some(CastTy::Ptr(src)) = CastTy::from_ty(ty_from) else { + unreachable!(); + }; + let Some(CastTy::Ptr(dst)) = CastTy::from_ty(*ty) else { + unreachable!(); + }; + + if self.infcx.type_is_sized_modulo_regions(self.infcx.param_env, dst.ty) { + // Wide to thin ptr cast. This may even occur in an env with + // impossible predicates, such as `where dyn Trait: Sized`. + // In this case, we don't want to fall into the case below, + // since the types may not actually be equatable, but it's + // fine to perform this operation in an impossible env. + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Sized, self.last_span), + [dst.ty], + ); + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::Cast { + is_implicit_coercion: true, + unsize_to: None, + }, + ); + } else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = + *self.struct_tail(src.ty, location).kind() + && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = + *self.struct_tail(dst.ty, location).kind() + && src_tty.principal().is_some() + && dst_tty.principal().is_some() + { + // This checks (lifetime part of) vtable validity for pointer casts, + // which is irrelevant when there are aren't principal traits on + // both sides (aka only auto traits). + // + // Note that other checks (such as denying `dyn Send` -> `dyn + // Debug`) are in `rustc_hir_typeck`. + + // Remove auto traits. + // Auto trait checks are handled in `rustc_hir_typeck` as FCW. + let src_obj = Ty::new_dynamic( + tcx, + tcx.mk_poly_existential_predicates( + &src_tty.without_auto_traits().collect::<Vec<_>>(), + ), + // FIXME: Once we disallow casting `*const dyn Trait + 'short` + // to `*const dyn Trait + 'long`, then this can just be `src_lt`. + dst_lt, + ty::Dyn, + ); + let dst_obj = Ty::new_dynamic( + tcx, + tcx.mk_poly_existential_predicates( + &dst_tty.without_auto_traits().collect::<Vec<_>>(), + ), + dst_lt, + ty::Dyn, + ); + + debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); + + self.sub_types( + src_obj, + dst_obj, + location.to_locations(), + ConstraintCategory::Cast { + is_implicit_coercion: false, + unsize_to: None, + }, + ) + .unwrap(); } } CastKind::Transmute => { @@ -2458,21 +2476,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { let root_def_id = self.root_cx.root_def_id(); - if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) { - constraint_conversion::ConstraintConversion::new( - self.infcx, - self.universal_regions, - self.region_bound_pairs, - self.known_type_outlives_obligations, - locations, - self.body.span, // irrelevant; will be overridden. - ConstraintCategory::Boring, // same as above. - self.constraints, - ) - .apply_closure_requirements(closure_requirements, def_id, args); - } + // We will have to handle propagated closure requirements for this closure, + // but need to defer this until the nested body has been fully borrow checked. + self.deferred_closure_requirements.push((def_id, args, locations)); - // Now equate closure args to regions inherited from `root_def_id`. Fixes #98589. + // Equate closure args to regions inherited from `root_def_id`. Fixes #98589. let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id); let parent_args = match tcx.def_kind(def_id) { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 296a2735533..64a7b408434 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -40,6 +40,7 @@ use crate::BorrowckInferCtxt; use crate::renumber::RegionCtxt; #[derive(Debug)] +#[derive(Clone)] // FIXME(#146079) pub(crate) struct UniversalRegions<'tcx> { indices: UniversalRegionIndices<'tcx>, @@ -200,6 +201,7 @@ impl<'tcx> DefiningTy<'tcx> { } #[derive(Debug)] +#[derive(Clone)] // FIXME(#146079) struct UniversalRegionIndices<'tcx> { /// For those regions that may appear in the parameter environment /// ('static and early-bound regions), we maintain a map from the diff --git a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml index 759d0d59e26..e49c62d6c93 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml @@ -82,20 +82,16 @@ jobs: - name: Build sample project with target defined as JSON spec run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json + ./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh clean all - name: Build run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu + ./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu ./y.sh test --mini-tests --target-triple m68k-unknown-linux-gnu - # FIXME: since https://github.com/rust-lang/rust/pull/140809, we cannot run programs for architectures not - # supported by the object crate, since this adds a dependency on symbols.o for the panic runtime. - # And as such, a wrong order of the object files in the linker command now fails with an undefined reference - # to some symbols like __rustc::rust_panic. - #CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu + CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu ./y.sh clean all - name: Prepare dependencies @@ -104,23 +100,21 @@ jobs: git config --global user.name "User" ./y.sh prepare --cross - # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above. - #- name: Run tests - #run: | - #./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler-builtins-no-f16-f128 ${{ matrix.commands }} - - # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above. - #- name: Run Hello World! - #run: | - #./y.sh build --target-triple m68k-unknown-linux-gnu - - #vm_dir=$(pwd)/vm - #cd tests/hello-world - #CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu - #sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/ - #sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout - #expected_output="40" - #test $(cat hello_world_stdout) == $expected_output || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) + - name: Run tests + run: | + ./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot ${{ matrix.commands }} + + - name: Run Hello World! + run: | + ./y.sh build --target-triple m68k-unknown-linux-gnu + + vm_dir=$(pwd)/vm + cd tests/hello-world + CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu + sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/ + sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout + expected_output="40" + test $(cat hello_world_stdout) == $expected_output || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 7f35c1a80bd..a5b972baf98 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -56,18 +56,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "2.7.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99a89184220d967dd300139f2d2ae7d52c1a69d632b24aacc57c54625254ce" +checksum = "4a0e310ef75f396cd11b2443b353d55376656ca92c13cba36f92b7aff346ac1a" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24edb7bfe2b7b27c6d09ed23eebfcab0b359c8fe978433f902943e6f127a0f1b" +checksum = "95ed7572b30cd32430294dde6fb70822d58e67c6846a548647e8739776a0125b" dependencies = [ "libc", ] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 193348d1ef6..6031933bd2d 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -24,7 +24,7 @@ default = ["master"] [dependencies] object = { version = "0.37.0", default-features = false, features = ["std", "read"] } tempfile = "3.20" -gccjit = "2.7" +gccjit = "2.8" #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } # Local copy. diff --git a/compiler/rustc_codegen_gcc/build_system/src/fmt.rs b/compiler/rustc_codegen_gcc/build_system/src/fmt.rs index 7e6594f50f9..91535f217e3 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/fmt.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/fmt.rs @@ -1,7 +1,7 @@ use std::ffi::OsStr; use std::path::Path; -use crate::utils::run_command_with_output; +use crate::utils::{run_command_with_output, walk_dir}; fn show_usage() { println!( @@ -32,5 +32,31 @@ pub fn run() -> Result<(), String> { if check { &[&"cargo", &"fmt", &"--check"] } else { &[&"cargo", &"fmt"] }; run_command_with_output(cmd, Some(Path::new(".")))?; - run_command_with_output(cmd, Some(Path::new("build_system"))) + run_command_with_output(cmd, Some(Path::new("build_system")))?; + + run_rustfmt_recursively("tests/run", check) +} + +fn run_rustfmt_recursively<P>(dir: P, check: bool) -> Result<(), String> +where + P: AsRef<Path>, +{ + walk_dir( + dir, + &mut |dir| run_rustfmt_recursively(dir, check), + &mut |file_path| { + if file_path.extension().filter(|ext| ext == &OsStr::new("rs")).is_some() { + let rustfmt_cmd: &[&dyn AsRef<OsStr>] = if check { + &[&"rustfmt", &"--check", &file_path] + } else { + &[&"rustfmt", &file_path] + }; + + run_command_with_output(rustfmt_cmd, Some(Path::new("."))) + } else { + Ok(()) + } + }, + true, + ) } diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 2c8271c36a9..3dd3fce2eec 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -531,7 +531,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> { r#"change-id = 115898 [rust] -codegen-backends = [] +codegen-backends = ["gcc"] deny-warnings = false verbose-tests = true diff --git a/compiler/rustc_codegen_gcc/libgccjit.version b/compiler/rustc_codegen_gcc/libgccjit.version index f62154968d3..dc9a0012864 100644 --- a/compiler/rustc_codegen_gcc/libgccjit.version +++ b/compiler/rustc_codegen_gcc/libgccjit.version @@ -1 +1 @@ -04ce66d8c918de9273bd7101638ad8724edf5e21 +4e995bd73c4490edfe5080ec6014d63aa9abed5f diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index 058e734be5c..04d33dfb116 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-08-03" +channel = "nightly-2025-08-25" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index d558dfbc1c4..fcee6b6df62 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -29,7 +29,7 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{DiagCtxtHandle, FatalError}; +use rustc_errors::DiagCtxtHandle; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; use rustc_session::config::Lto; @@ -51,12 +51,11 @@ fn prepare_lto( cgcx: &CodegenContext<GccCodegenBackend>, each_linked_rlib_for_lto: &[PathBuf], dcx: DiagCtxtHandle<'_>, -) -> Result<LtoData, FatalError> { +) -> LtoData { let tmp_path = match tempdir() { Ok(tmp_path) => tmp_path, Err(error) => { - eprintln!("Cannot create temporary directory: {}", error); - return Err(FatalError); + dcx.fatal(format!("Cannot create temporary directory: {}", error)); } }; @@ -91,15 +90,14 @@ fn prepare_lto( upstream_modules.push((module, CString::new(name).unwrap())); } Err(e) => { - dcx.emit_err(e); - return Err(FatalError); + dcx.emit_fatal(e); } } } } } - Ok(LtoData { upstream_modules, tmp_path }) + LtoData { upstream_modules, tmp_path } } fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> { @@ -114,10 +112,10 @@ pub(crate) fn run_fat( cgcx: &CodegenContext<GccCodegenBackend>, each_linked_rlib_for_lto: &[PathBuf], modules: Vec<FatLtoInput<GccCodegenBackend>>, -) -> Result<ModuleCodegen<GccContext>, FatalError> { +) -> ModuleCodegen<GccContext> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx)?; + let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); /*let symbols_below_threshold = lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/ fat_lto( @@ -137,7 +135,7 @@ fn fat_lto( mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> Result<ModuleCodegen<GccContext>, FatalError> { +) -> ModuleCodegen<GccContext> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -261,7 +259,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - Ok(module) + module } pub struct ModuleBuffer(PathBuf); @@ -286,10 +284,10 @@ pub(crate) fn run_thin( each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, -) -> Result<(Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> (Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>) { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx)?; + let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); if cgcx.opts.cg.linker_plugin_lto.enabled() { unreachable!( "We should never reach this case if the LTO step \ @@ -355,7 +353,7 @@ fn thin_lto( tmp_path: TempDir, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, //_symbols_below_threshold: &[String], -) -> Result<(Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> (Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>) { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); info!("going for that thin, thin LTO"); @@ -518,13 +516,13 @@ fn thin_lto( // TODO: save the directory so that it gets deleted later. std::mem::forget(tmp_path); - Ok((opt_jobs, copy_jobs)) + (opt_jobs, copy_jobs) } pub fn optimize_thin_module( thin_module: ThinModule<GccCodegenBackend>, _cgcx: &CodegenContext<GccCodegenBackend>, -) -> Result<ModuleCodegen<GccContext>, FatalError> { +) -> ModuleCodegen<GccContext> { //let dcx = cgcx.create_dcx(); //let module_name = &thin_module.shared.module_names[thin_module.idx]; @@ -634,7 +632,8 @@ pub fn optimize_thin_module( save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } }*/ - Ok(module) + #[allow(clippy::let_and_return)] + module } pub struct ThinBuffer { diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index c1231142c65..84bc7016271 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -6,7 +6,6 @@ use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, Mo use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_fs_util::link_or_copy; use rustc_session::config::OutputType; -use rustc_span::fatal_error::FatalError; use rustc_target::spec::SplitDebuginfo; use crate::base::add_pic_option; @@ -17,7 +16,7 @@ pub(crate) fn codegen( cgcx: &CodegenContext<GccCodegenBackend>, module: ModuleCodegen<GccContext>, config: &ModuleConfig, -) -> Result<CompiledModule, FatalError> { +) -> CompiledModule { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); @@ -246,7 +245,7 @@ pub(crate) fn codegen( } } - Ok(module.into_compiled_module( + module.into_compiled_module( config.emit_obj != EmitObj::None, cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked, config.emit_bc, @@ -254,7 +253,7 @@ pub(crate) fn codegen( config.emit_ir, &cgcx.output_filenames, cgcx.invocation_temp.as_deref(), - )) + ) } pub(crate) fn save_temp_bitcode( diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index fdc15d580ef..41363d6313d 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -1497,7 +1497,6 @@ fn simd_funnel_shift<'a, 'gcc, 'tcx>( let index = bx.context.new_rvalue_from_int(bx.int_type, i as i32); let a_val = bx.context.new_vector_access(None, a, index).to_rvalue(); let a_val = bx.context.new_bitcast(None, a_val, unsigned_type); - // TODO: we probably need to use gcc_int_cast instead. let a_val = bx.gcc_int_cast(a_val, new_int_type); let b_val = bx.context.new_vector_access(None, b, index).to_rvalue(); let b_val = bx.context.new_bitcast(None, b_val, unsigned_type); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 4025aba82da..2d7df79ba95 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -110,7 +110,6 @@ use rustc_middle::util::Providers; use rustc_session::Session; use rustc_session::config::{OptLevel, OutputFilenames}; use rustc_span::Symbol; -use rustc_span::fatal_error::FatalError; use rustc_target::spec::RelocModel; use tempfile::TempDir; @@ -362,7 +361,7 @@ impl WriteBackendMethods for GccCodegenBackend { _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<FatLtoInput<Self>>, - ) -> Result<ModuleCodegen<Self::Module>, FatalError> { + ) -> ModuleCodegen<Self::Module> { back::lto::run_fat(cgcx, each_linked_rlib_for_lto, modules) } @@ -373,7 +372,7 @@ impl WriteBackendMethods for GccCodegenBackend { each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError> { + ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) { back::lto::run_thin(cgcx, each_linked_rlib_for_lto, modules, cached_modules) } @@ -390,15 +389,14 @@ impl WriteBackendMethods for GccCodegenBackend { _dcx: DiagCtxtHandle<'_>, module: &mut ModuleCodegen<Self::Module>, config: &ModuleConfig, - ) -> Result<(), FatalError> { + ) { module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); - Ok(()) } fn optimize_thin( cgcx: &CodegenContext<Self>, thin: ThinModule<Self>, - ) -> Result<ModuleCodegen<Self::Module>, FatalError> { + ) -> ModuleCodegen<Self::Module> { back::lto::optimize_thin_module(thin, cgcx) } @@ -406,7 +404,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext<Self>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, - ) -> Result<CompiledModule, FatalError> { + ) -> CompiledModule { back::write::codegen(cgcx, module, config) } diff --git a/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt index 29032b321fa..c5e22970c66 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt @@ -6,7 +6,6 @@ tests/run-make/doctests-keep-binaries/ tests/run-make/doctests-runtool/ tests/run-make/emit-shared-files/ tests/run-make/exit-code/ -tests/run-make/issue-64153/ tests/run-make/llvm-ident/ tests/run-make/native-link-modifier-bundle/ tests/run-make/remap-path-prefix-dwarf/ @@ -34,8 +33,6 @@ tests/run-make/c-link-to-rust-staticlib/ tests/run-make/foreign-double-unwind/ tests/run-make/foreign-exceptions/ tests/run-make/glibc-staticlib-args/ -tests/run-make/issue-36710/ -tests/run-make/issue-68794-textrel-on-minimal-lib/ tests/run-make/lto-smoke-c/ tests/run-make/return-non-c-like-enum/ diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt index 41fb4729c07..e2615bce190 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt @@ -20,7 +20,7 @@ tests/ui/drop/dynamic-drop.rs tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs tests/ui/simd/issue-17170.rs tests/ui/simd/issue-39720.rs -tests/ui/issues/issue-14875.rs +tests/ui/drop/panic-during-drop-14875.rs tests/ui/issues/issue-29948.rs tests/ui/process/println-with-broken-pipe.rs tests/ui/lto/thin-lto-inlines2.rs @@ -86,3 +86,5 @@ tests/ui/panics/unwind-force-no-unwind-tables.rs tests/ui/attributes/fn-align-dyn.rs tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs tests/ui/explicit-tail-calls/recursion-etc.rs +tests/ui/explicit-tail-calls/indexer.rs +tests/ui/explicit-tail-calls/drop-order.rs diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs index e20ecc23679..78675acb544 100644 --- a/compiler/rustc_codegen_gcc/tests/run/int.rs +++ b/compiler/rustc_codegen_gcc/tests/run/int.rs @@ -7,12 +7,10 @@ fn main() { use std::hint::black_box; macro_rules! check { - ($ty:ty, $expr:expr) => { - { - const EXPECTED: $ty = $expr; - assert_eq!($expr, EXPECTED); - } - }; + ($ty:ty, $expr:expr) => {{ + const EXPECTED: $ty = $expr; + assert_eq!($expr, EXPECTED); + }}; } check!(u32, (2220326408_u32 + black_box(1)) >> (32 - 6)); diff --git a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs index 78872159f62..78e1cac57e0 100644 --- a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs +++ b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs @@ -12,7 +12,7 @@ fn main() { let arg_count = std::env::args().count(); let int = isize::MAX; - let _int = int + arg_count as isize; // overflow + let _int = int + arg_count as isize; // overflow // If overflow checking is disabled, we should reach here. #[cfg(not(debug_assertions))] diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs index da73cbed9ae..e08e67837be 100644 --- a/compiler/rustc_codegen_gcc/tests/run/structs.rs +++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs @@ -27,12 +27,8 @@ fn one() -> isize { #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { - let test = Test { - field: one(), - }; - let two = Two { - two: 2, - }; + let test = Test { field: one() }; + let two = Two { two: 2 }; unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); libc::printf(b"%ld\n\0" as *const u8 as *const i8, two.two); diff --git a/compiler/rustc_codegen_gcc/tests/run/volatile.rs b/compiler/rustc_codegen_gcc/tests/run/volatile.rs index 94a7bdc5c06..dc11fbfa600 100644 --- a/compiler/rustc_codegen_gcc/tests/run/volatile.rs +++ b/compiler/rustc_codegen_gcc/tests/run/volatile.rs @@ -12,15 +12,11 @@ struct Struct { func: unsafe fn(*const ()), } -fn func(_ptr: *const ()) { -} +fn func(_ptr: *const ()) {} fn main() { let mut x = MaybeUninit::<&Struct>::uninit(); - x.write(&Struct { - pointer: std::ptr::null(), - func, - }); + x.write(&Struct { pointer: std::ptr::null(), func }); let x = unsafe { x.assume_init() }; let value = unsafe { (x as *const Struct).read_volatile() }; println!("{:?}", value); diff --git a/compiler/rustc_codegen_gcc/tests/run/volatile2.rs b/compiler/rustc_codegen_gcc/tests/run/volatile2.rs index bdcb8259878..ada112687d3 100644 --- a/compiler/rustc_codegen_gcc/tests/run/volatile2.rs +++ b/compiler/rustc_codegen_gcc/tests/run/volatile2.rs @@ -7,7 +7,14 @@ mod libc { #[link(name = "c")] extern "C" { pub fn sigaction(signum: i32, act: *const sigaction, oldact: *mut sigaction) -> i32; - pub fn mmap(addr: *mut (), len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut (); + pub fn mmap( + addr: *mut (), + len: usize, + prot: i32, + flags: i32, + fd: i32, + offset: i64, + ) -> *mut (); pub fn mprotect(addr: *mut (), len: usize, prot: i32) -> i32; } @@ -54,7 +61,8 @@ fn main() { libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, -1, 0, - ).cast(); + ) + .cast(); if STORAGE == libc::MAP_FAILED { panic!("error: mmap failed"); } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 23610aa856c..df3e49279d9 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -12,7 +12,7 @@ use smallvec::SmallVec; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; -use crate::llvm::{self, False, True, Type, Value}; +use crate::llvm::{self, FALSE, TRUE, Type, Value}; use crate::{SimpleCx, attributes, debuginfo, llvm_util}; pub(crate) unsafe fn codegen( @@ -80,7 +80,7 @@ pub(crate) unsafe fn codegen( &cx, &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), &i8, - &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, False), + &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, FALSE), ); // __rust_no_alloc_shim_is_unstable_v2 @@ -201,7 +201,7 @@ fn create_wrapper_function( .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) .collect::<Vec<_>>(); let ret = bx.call(ty, callee, &args, None); - llvm::LLVMSetTailCall(ret, True); + llvm::LLVMSetTailCall(ret, TRUE); if output.is_some() { bx.ret(ret); } else { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a643a91141e..38c1d3b53e8 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -16,6 +16,7 @@ use tracing::debug; use crate::builder::Builder; use crate::common::Funclet; use crate::context::CodegenCx; +use crate::llvm::ToLlvmBool; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -470,10 +471,6 @@ pub(crate) fn inline_asm_call<'ll>( dest: Option<&'ll llvm::BasicBlock>, catch_funclet: Option<(&'ll llvm::BasicBlock, Option<&Funclet<'ll>>)>, ) -> Option<&'ll Value> { - let volatile = if volatile { llvm::True } else { llvm::False }; - let alignstack = if alignstack { llvm::True } else { llvm::False }; - let can_throw = if unwind { llvm::True } else { llvm::False }; - let argtys = inputs .iter() .map(|v| { @@ -500,10 +497,10 @@ pub(crate) fn inline_asm_call<'ll>( asm.len(), cons.as_ptr(), cons.len(), - volatile, - alignstack, + volatile.to_llvm_bool(), + alignstack.to_llvm_bool(), dia, - can_throw, + unwind.to_llvm_bool(), ) }; diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 853d0295238..d85f432702c 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -14,7 +14,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{DiagCtxtHandle, FatalError}; +use rustc_errors::DiagCtxtHandle; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; use rustc_session::config::{self, Lto}; @@ -36,7 +36,7 @@ fn prepare_lto( exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], dcx: DiagCtxtHandle<'_>, -) -> Result<(Vec<CString>, Vec<(SerializedModule<ModuleBuffer>, CString)>), FatalError> { +) -> (Vec<CString>, Vec<(SerializedModule<ModuleBuffer>, CString)>) { let mut symbols_below_threshold = exported_symbols_for_lto .iter() .map(|symbol| CString::new(symbol.to_owned()).unwrap()) @@ -79,16 +79,13 @@ fn prepare_lto( let module = SerializedModule::FromRlib(data.to_vec()); upstream_modules.push((module, CString::new(name).unwrap())); } - Err(e) => { - dcx.emit_err(e); - return Err(FatalError); - } + Err(e) => dcx.emit_fatal(e), } } } } - Ok((symbols_below_threshold, upstream_modules)) + (symbols_below_threshold, upstream_modules) } fn get_bitcode_slice_from_object_data<'a>( @@ -123,11 +120,11 @@ pub(crate) fn run_fat( exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<FatLtoInput<LlvmCodegenBackend>>, -) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { +) -> ModuleCodegen<ModuleLlvm> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = - prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx)?; + prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx); let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>(); fat_lto(cgcx, dcx, modules, upstream_modules, &symbols_below_threshold) @@ -142,11 +139,11 @@ pub(crate) fn run_thin( each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, -) -> Result<(Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> (Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>) { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = - prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx)?; + prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx); let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>(); if cgcx.opts.cg.linker_plugin_lto.enabled() { @@ -173,7 +170,7 @@ fn fat_lto( modules: Vec<FatLtoInput<LlvmCodegenBackend>>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { +) -> ModuleCodegen<ModuleLlvm> { let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -224,7 +221,7 @@ fn fat_lto( assert!(!serialized_modules.is_empty(), "must have at least one serialized module"); let (buffer, name) = serialized_modules.remove(0); info!("no in-memory regular modules to choose from, parsing {:?}", name); - let llvm_module = ModuleLlvm::parse(cgcx, &name, buffer.data(), dcx)?; + let llvm_module = ModuleLlvm::parse(cgcx, &name, buffer.data(), dcx); ModuleCodegen::new_regular(name.into_string().unwrap(), llvm_module) } }; @@ -265,7 +262,9 @@ fn fat_lto( }); info!("linking {:?}", name); let data = bc_decoded.data(); - linker.add(data).map_err(|()| write::llvm_err(dcx, LlvmError::LoadBitcode { name }))?; + linker + .add(data) + .unwrap_or_else(|()| write::llvm_err(dcx, LlvmError::LoadBitcode { name })); } drop(linker); save_temp_bitcode(cgcx, &module, "lto.input"); @@ -282,7 +281,7 @@ fn fat_lto( save_temp_bitcode(cgcx, &module, "lto.after-restriction"); } - Ok(module) + module } pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>); @@ -352,7 +351,7 @@ fn thin_lto( serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result<(Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> (Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>) { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); unsafe { info!("going for that thin, thin LTO"); @@ -422,7 +421,7 @@ fn thin_lto( symbols_below_threshold.as_ptr(), symbols_below_threshold.len(), ) - .ok_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext))?; + .unwrap_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext)); let data = ThinData(data); @@ -492,10 +491,10 @@ fn thin_lto( if let Some(path) = key_map_path && let Err(err) = curr_key_map.save_to_file(&path) { - return Err(write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err })); + write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err }); } - Ok((opt_jobs, copy_jobs)) + (opt_jobs, copy_jobs) } } @@ -550,7 +549,7 @@ pub(crate) fn run_pass_manager( dcx: DiagCtxtHandle<'_>, module: &mut ModuleCodegen<ModuleLlvm>, thin: bool, -) -> Result<(), FatalError> { +) { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_lto_optimize", &*module.name); let config = cgcx.config(module.kind); @@ -582,7 +581,7 @@ pub(crate) fn run_pass_manager( } unsafe { - write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?; + write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage); } if enable_gpu && !thin { @@ -596,7 +595,7 @@ pub(crate) fn run_pass_manager( let stage = write::AutodiffStage::PostAD; if !config.autodiff.contains(&config::AutoDiff::NoPostopt) { unsafe { - write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?; + write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage); } } @@ -608,7 +607,6 @@ pub(crate) fn run_pass_manager( } debug!("lto done"); - Ok(()) } pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer); @@ -701,7 +699,7 @@ impl Drop for ThinBuffer { pub(crate) fn optimize_thin_module( thin_module: ThinModule<LlvmCodegenBackend>, cgcx: &CodegenContext<LlvmCodegenBackend>, -) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { +) -> ModuleCodegen<ModuleLlvm> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); @@ -712,7 +710,7 @@ pub(crate) fn optimize_thin_module( // into that context. One day, however, we may do this for upstream // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. - let module_llvm = ModuleLlvm::parse(cgcx, module_name, thin_module.data(), dcx)?; + let module_llvm = ModuleLlvm::parse(cgcx, module_name, thin_module.data(), dcx); let mut module = ModuleCodegen::new_regular(thin_module.name(), module_llvm); // Given that the newly created module lacks a thinlto buffer for embedding, we need to re-add it here. if cgcx.config(ModuleKind::Regular).embed_bitcode() { @@ -746,7 +744,7 @@ pub(crate) fn optimize_thin_module( .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name()); if unsafe { !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) } { - return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); + write::llvm_err(dcx, LlvmError::PrepareThinLtoModule); } save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); } @@ -757,7 +755,7 @@ pub(crate) fn optimize_thin_module( .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name()); if unsafe { !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) } { - return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); + write::llvm_err(dcx, LlvmError::PrepareThinLtoModule); } save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); } @@ -768,7 +766,7 @@ pub(crate) fn optimize_thin_module( if unsafe { !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target.raw()) } { - return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); + write::llvm_err(dcx, LlvmError::PrepareThinLtoModule); } save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); } @@ -780,11 +778,11 @@ pub(crate) fn optimize_thin_module( // little differently. { info!("running thin lto passes over {}", module.name); - run_pass_manager(cgcx, dcx, &mut module, true)?; + run_pass_manager(cgcx, dcx, &mut module, true); save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } } - Ok(module) + module } /// Maps LLVM module identifiers to their corresponding LLVM LTO cache keys @@ -850,9 +848,9 @@ pub(crate) fn parse_module<'a>( name: &CStr, data: &[u8], dcx: DiagCtxtHandle<'_>, -) -> Result<&'a llvm::Module, FatalError> { +) -> &'a llvm::Module { unsafe { llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr()) - .ok_or_else(|| write::llvm_err(dcx, LlvmError::ParseBitcode)) + .unwrap_or_else(|| write::llvm_err(dcx, LlvmError::ParseBitcode)) } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 62998003ca1..7ea2ae6673b 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -20,7 +20,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{DiagCtxtHandle, FatalError, Level}; +use rustc_errors::{DiagCtxtHandle, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -46,10 +46,10 @@ use crate::llvm::{self, DiagnosticInfo}; use crate::type_::Type; use crate::{LlvmCodegenBackend, ModuleLlvm, base, common, llvm_util}; -pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> FatalError { +pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> ! { match llvm::last_error() { - Some(llvm_err) => dcx.emit_almost_fatal(WithLlvmError(err, llvm_err)), - None => dcx.emit_almost_fatal(err), + Some(llvm_err) => dcx.emit_fatal(WithLlvmError(err, llvm_err)), + None => dcx.emit_fatal(err), } } @@ -63,7 +63,7 @@ fn write_output_file<'ll>( file_type: llvm::FileType, self_profiler_ref: &SelfProfilerRef, verify_llvm_ir: bool, -) -> Result<(), FatalError> { +) { debug!("write_output_file output={:?} dwo_output={:?}", output, dwo_output); let output_c = path_to_c_string(output); let dwo_output_c; @@ -100,7 +100,7 @@ fn write_output_file<'ll>( } } - result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) + result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } pub(crate) fn create_informational_target_machine( @@ -112,7 +112,7 @@ pub(crate) fn create_informational_target_machine( // system/tcx is set up. let features = llvm_util::global_llvm_features(sess, false, only_base_features); target_machine_factory(sess, config::OptLevel::No, &features)(config) - .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise()) + .unwrap_or_else(|err| llvm_err(sess.dcx(), err)) } pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMachine { @@ -139,7 +139,7 @@ pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTar tcx.backend_optimization_level(()), tcx.global_backend_features(()), )(config) - .unwrap_or_else(|err| llvm_err(tcx.dcx(), err).raise()) + .unwrap_or_else(|err| llvm_err(tcx.dcx(), err)) } fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize) { @@ -565,7 +565,7 @@ pub(crate) unsafe fn llvm_optimize( opt_level: config::OptLevel, opt_stage: llvm::OptStage, autodiff_stage: AutodiffStage, -) -> Result<(), FatalError> { +) { // Enzyme: // The whole point of compiler based AD is to differentiate optimized IR instead of unoptimized // source code. However, benchmarks show that optimizations increasing the code size @@ -704,7 +704,7 @@ pub(crate) unsafe fn llvm_optimize( llvm_plugins.len(), ) }; - result.into_result().map_err(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) + result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) } // Unsafe due to LLVM calls. @@ -713,7 +713,7 @@ pub(crate) fn optimize( dcx: DiagCtxtHandle<'_>, module: &mut ModuleCodegen<ModuleLlvm>, config: &ModuleConfig, -) -> Result<(), FatalError> { +) { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name); let llcx = &*module.module_llvm.llcx; @@ -765,7 +765,7 @@ pub(crate) fn optimize( opt_stage, autodiff_stage, ) - }?; + }; if let Some(thin_lto_buffer) = thin_lto_buffer { let thin_lto_buffer = unsafe { ThinBuffer::from_raw_ptr(thin_lto_buffer) }; module.thin_lto_buffer = Some(thin_lto_buffer.data().to_vec()); @@ -793,14 +793,13 @@ pub(crate) fn optimize( } } } - Ok(()) } pub(crate) fn codegen( cgcx: &CodegenContext<LlvmCodegenBackend>, module: ModuleCodegen<ModuleLlvm>, config: &ModuleConfig, -) -> Result<CompiledModule, FatalError> { +) -> CompiledModule { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); @@ -909,7 +908,9 @@ pub(crate) fn codegen( record_artifact_size(&cgcx.prof, "llvm_ir", &out); } - result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteIr { path: &out }))?; + result + .into_result() + .unwrap_or_else(|()| llvm_err(dcx, LlvmError::WriteIr { path: &out })); } if config.emit_asm { @@ -940,7 +941,7 @@ pub(crate) fn codegen( llvm::FileType::AssemblyFile, &cgcx.prof, config.verify_llvm_ir, - )?; + ); } match config.emit_obj { @@ -976,7 +977,7 @@ pub(crate) fn codegen( llvm::FileType::ObjectFile, &cgcx.prof, config.verify_llvm_ir, - )?; + ); } EmitObj::Bitcode => { @@ -1009,7 +1010,7 @@ pub(crate) fn codegen( && cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo != SplitDebuginfo::Off && cgcx.split_dwarf_kind == SplitDwarfKind::Split; - Ok(module.into_compiled_module( + module.into_compiled_module( config.emit_obj != EmitObj::None, dwarf_object_emitted, config.emit_bc, @@ -1017,7 +1018,7 @@ pub(crate) fn codegen( config.emit_ir, &cgcx.output_filenames, cgcx.invocation_temp.as_deref(), - )) + ) } fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: &[u8]) -> Vec<u8> { @@ -1110,7 +1111,7 @@ fn embed_bitcode( llvm::set_section(llglobal, bitcode_section_name(cgcx)); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + llvm::LLVMSetGlobalConstant(llglobal, llvm::TRUE); let llconst = common::bytes_in_context(llcx, &[]); let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 427c75d40e9..37379586d58 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -35,7 +35,7 @@ use crate::attributes; use crate::common::Funclet; use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; use crate::llvm::{ - self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True, + self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, GEPNoWrapFlags, Metadata, TRUE, ToLlvmBool, }; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -493,8 +493,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let add = llvm::LLVMBuildAdd(self.llbuilder, a, b, UNNAMED); if llvm::LLVMIsAInstruction(add).is_some() { - llvm::LLVMSetNUW(add, True); - llvm::LLVMSetNSW(add, True); + llvm::LLVMSetNUW(add, TRUE); + llvm::LLVMSetNSW(add, TRUE); } add } @@ -503,8 +503,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let sub = llvm::LLVMBuildSub(self.llbuilder, a, b, UNNAMED); if llvm::LLVMIsAInstruction(sub).is_some() { - llvm::LLVMSetNUW(sub, True); - llvm::LLVMSetNSW(sub, True); + llvm::LLVMSetNUW(sub, TRUE); + llvm::LLVMSetNSW(sub, TRUE); } sub } @@ -513,8 +513,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let mul = llvm::LLVMBuildMul(self.llbuilder, a, b, UNNAMED); if llvm::LLVMIsAInstruction(mul).is_some() { - llvm::LLVMSetNUW(mul, True); - llvm::LLVMSetNSW(mul, True); + llvm::LLVMSetNUW(mul, TRUE); + llvm::LLVMSetNSW(mul, TRUE); } mul } @@ -528,7 +528,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // an instruction, so we need to check before setting the flag. // (See also `LLVMBuildNUWNeg` which also needs a check.) if llvm::LLVMIsAInstruction(or).is_some() { - llvm::LLVMSetIsDisjoint(or, True); + llvm::LLVMSetIsDisjoint(or, TRUE); } or } @@ -629,7 +629,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn volatile_load(&mut self, ty: &'ll Type, ptr: &'ll Value) -> &'ll Value { unsafe { let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); - llvm::LLVMSetVolatile(load, llvm::True); + llvm::LLVMSetVolatile(load, llvm::TRUE); load } } @@ -717,7 +717,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let mut const_llval = None; let llty = place.layout.llvm_type(self); if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { - if llvm::LLVMIsGlobalConstant(global) == llvm::True { + if llvm::LLVMIsGlobalConstant(global).is_true() { if let Some(init) = llvm::LLVMGetInitializer(global) { if self.val_ty(init) == llty { const_llval = Some(init); @@ -838,7 +838,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint }; llvm::LLVMSetAlignment(store, align); if flags.contains(MemFlags::VOLATILE) { - llvm::LLVMSetVolatile(store, llvm::True); + llvm::LLVMSetVolatile(store, llvm::TRUE); } if flags.contains(MemFlags::NONTEMPORAL) { // Make sure that the current target architectures supports "sane" non-temporal @@ -956,7 +956,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let trunc = self.trunc(val, dest_ty); unsafe { if llvm::LLVMIsAInstruction(trunc).is_some() { - llvm::LLVMSetNUW(trunc, True); + llvm::LLVMSetNUW(trunc, TRUE); } } trunc @@ -968,7 +968,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let trunc = self.trunc(val, dest_ty); unsafe { if llvm::LLVMIsAInstruction(trunc).is_some() { - llvm::LLVMSetNSW(trunc, True); + llvm::LLVMSetNSW(trunc, TRUE); } } trunc @@ -1067,13 +1067,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn intcast(&mut self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value { unsafe { - llvm::LLVMBuildIntCast2( - self.llbuilder, - val, - dest_ty, - if is_signed { True } else { False }, - UNNAMED, - ) + llvm::LLVMBuildIntCast2(self.llbuilder, val, dest_ty, is_signed.to_llvm_bool(), UNNAMED) } } @@ -1229,7 +1223,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); let landing_pad = self.landing_pad(ty, pers_fn, 0); unsafe { - llvm::LLVMSetCleanup(landing_pad, llvm::True); + llvm::LLVMSetCleanup(landing_pad, llvm::TRUE); } (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } @@ -1317,7 +1311,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { failure_order: rustc_middle::ty::AtomicOrdering, weak: bool, ) -> (&'ll Value, &'ll Value) { - let weak = if weak { llvm::True } else { llvm::False }; unsafe { let value = llvm::LLVMBuildAtomicCmpXchg( self.llbuilder, @@ -1326,9 +1319,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src, AtomicOrdering::from_generic(order), AtomicOrdering::from_generic(failure_order), - llvm::False, // SingleThreaded + llvm::FALSE, // SingleThreaded ); - llvm::LLVMSetWeak(value, weak); + llvm::LLVMSetWeak(value, weak.to_llvm_bool()); let val = self.extract_value(value, 0); let success = self.extract_value(value, 1); (val, success) @@ -1353,7 +1346,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { dst, src, AtomicOrdering::from_generic(order), - llvm::False, // SingleThreaded + llvm::FALSE, // SingleThreaded ) }; if ret_ptr && self.val_ty(res) != self.type_ptr() { @@ -1368,14 +1361,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { scope: SynchronizationScope, ) { let single_threaded = match scope { - SynchronizationScope::SingleThread => llvm::True, - SynchronizationScope::CrossThread => llvm::False, + SynchronizationScope::SingleThread => true, + SynchronizationScope::CrossThread => false, }; unsafe { llvm::LLVMBuildFence( self.llbuilder, AtomicOrdering::from_generic(order), - single_threaded, + single_threaded.to_llvm_bool(), UNNAMED, ); } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index e2df3265f6f..6ddf53cdc87 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -11,7 +11,7 @@ use crate::builder::{Builder, PlaceRef, UNNAMED}; use crate::context::SimpleCx; use crate::declare::declare_simple_fn; use crate::llvm; -use crate::llvm::{Metadata, True, Type}; +use crate::llvm::{Metadata, TRUE, Type}; use crate::value::Value; pub(crate) fn adjust_activity_to_abi<'tcx>( @@ -293,7 +293,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( // ret double %0 // } // ``` - let enzyme_ty = unsafe { llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, True) }; + let enzyme_ty = unsafe { llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, TRUE) }; // FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and // think a bit more about what should go here. diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index f29fefb66f0..11b79a7fe68 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -20,7 +20,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; use crate::context::{GenericCx, SCx}; -use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; +use crate::llvm::{self, BasicBlock, ConstantInt, FALSE, Metadata, TRUE, ToLlvmBool}; use crate::type_::Type; use crate::value::Value; @@ -158,7 +158,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.type_kind(t) == TypeKind::Integer, "only allows integer types in const_int" ); - unsafe { llvm::LLVMConstInt(t, i as u64, True) } + unsafe { llvm::LLVMConstInt(t, i as u64, TRUE) } } fn const_u8(&self, i: u8) -> &'ll Value { @@ -192,7 +192,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.type_kind(t) == TypeKind::Integer, "only allows integer types in const_uint" ); - unsafe { llvm::LLVMConstInt(t, i, False) } + unsafe { llvm::LLVMConstInt(t, i, FALSE) } } fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value { @@ -377,7 +377,7 @@ pub(crate) fn val_ty(v: &Value) -> &Type { pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value { unsafe { let ptr = bytes.as_ptr() as *const c_char; - llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), True) + llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), TRUE) } } @@ -392,7 +392,7 @@ fn struct_in_context<'ll>( packed: bool, ) -> &'ll Value { let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow"); - unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed as Bool) } + unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed.to_llvm_bool()) } } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4a7de7d2e69..4fd6110ac4a 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -701,7 +701,7 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { } pub(crate) fn get_const_int(&self, ty: &'ll Type, val: u64) -> &'ll Value { - unsafe { llvm::LLVMConstInt(ty, val, llvm::False) } + unsafe { llvm::LLVMConstInt(ty, val, llvm::FALSE) } } pub(crate) fn get_const_i64(&self, n: u64) -> &'ll Value { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 6eb7042da61..7a6dc008c7b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -72,7 +72,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::set_initializer(section_var, cx.const_bytes(section_contents)); - llvm::LLVMSetGlobalConstant(section_var, llvm::True); + llvm::LLVMSetGlobalConstant(section_var, llvm::TRUE); llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index b4d639368b0..1dcf4ff3062 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -38,7 +38,7 @@ pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'l parent_scope, namespace_name_string.as_ptr(), namespace_name_string.len(), - llvm::False, // ExportSymbols (only relevant for C++ anonymous namespaces) + llvm::FALSE, // ExportSymbols (only relevant for C++ anonymous namespaces) ) }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 0fcf31d7993..628cb34fd9e 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -37,7 +37,7 @@ use rustc_codegen_ssa::back::write::{ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{DiagCtxtHandle, FatalError}; +use rustc_errors::DiagCtxtHandle; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -165,15 +165,15 @@ impl WriteBackendMethods for LlvmCodegenBackend { exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<FatLtoInput<Self>>, - ) -> Result<ModuleCodegen<Self::Module>, FatalError> { + ) -> ModuleCodegen<Self::Module> { let mut module = - back::lto::run_fat(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, modules)?; + back::lto::run_fat(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, modules); let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - back::lto::run_pass_manager(cgcx, dcx, &mut module, false)?; + back::lto::run_pass_manager(cgcx, dcx, &mut module, false); - Ok(module) + module } fn run_thin_lto( cgcx: &CodegenContext<Self>, @@ -181,7 +181,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError> { + ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) { back::lto::run_thin( cgcx, exported_symbols_for_lto, @@ -195,20 +195,20 @@ impl WriteBackendMethods for LlvmCodegenBackend { dcx: DiagCtxtHandle<'_>, module: &mut ModuleCodegen<Self::Module>, config: &ModuleConfig, - ) -> Result<(), FatalError> { + ) { back::write::optimize(cgcx, dcx, module, config) } fn optimize_thin( cgcx: &CodegenContext<Self>, thin: ThinModule<Self>, - ) -> Result<ModuleCodegen<Self::Module>, FatalError> { + ) -> ModuleCodegen<Self::Module> { back::lto::optimize_thin_module(thin, cgcx) } fn codegen( cgcx: &CodegenContext<Self>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, - ) -> Result<CompiledModule, FatalError> { + ) -> CompiledModule { back::write::codegen(cgcx, module, config) } fn prepare_thin( @@ -407,12 +407,12 @@ impl ModuleLlvm { cgcx: &CodegenContext<LlvmCodegenBackend>, name: &str, dcx: DiagCtxtHandle<'_>, - ) -> Result<OwnedTargetMachine, FatalError> { + ) -> OwnedTargetMachine { let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, name); match (cgcx.tm_factory)(tm_factory_config) { - Ok(m) => Ok(m), + Ok(m) => m, Err(e) => { - return Err(dcx.emit_almost_fatal(ParseTargetMachineConfig(e))); + dcx.emit_fatal(ParseTargetMachineConfig(e)); } } } @@ -422,13 +422,13 @@ impl ModuleLlvm { name: &CStr, buffer: &[u8], dcx: DiagCtxtHandle<'_>, - ) -> Result<Self, FatalError> { + ) -> Self { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = back::lto::parse_module(llcx, name, buffer, dcx)?; - let tm = ModuleLlvm::tm_from_cgcx(cgcx, name.to_str().unwrap(), dcx)?; + let llmod_raw = back::lto::parse_module(llcx, name, buffer, dcx); + let tm = ModuleLlvm::tm_from_cgcx(cgcx, name.to_str().unwrap(), dcx); - Ok(ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }) + ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2461f70a86e..7c79cba2273 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -11,9 +11,8 @@ //! the need for an extra cast from `*const u8` on the Rust side. #![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] -use std::fmt::Debug; +use std::fmt::{self, Debug}; use std::marker::PhantomData; use std::num::NonZero; use std::ptr; @@ -33,10 +32,59 @@ use crate::llvm; /// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, /// which has a different ABI from Rust or C++ `bool`. -pub(crate) type Bool = c_int; +/// +/// This wrapper does not implement `PartialEq`. +/// To test the underlying boolean value, use [`Self::is_true`]. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub(crate) struct Bool { + value: c_int, +} + +pub(crate) const TRUE: Bool = Bool::TRUE; +pub(crate) const FALSE: Bool = Bool::FALSE; + +impl Bool { + pub(crate) const TRUE: Self = Self { value: 1 }; + pub(crate) const FALSE: Self = Self { value: 0 }; + + pub(crate) const fn from_bool(rust_bool: bool) -> Self { + if rust_bool { Self::TRUE } else { Self::FALSE } + } + + /// Converts this LLVM-C boolean to a Rust `bool` + pub(crate) fn is_true(self) -> bool { + // Since we're interacting with a C API, follow the C convention of + // treating any nonzero value as true. + self.value != Self::FALSE.value + } +} -pub(crate) const True: Bool = 1 as Bool; -pub(crate) const False: Bool = 0 as Bool; +impl Debug for Bool { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + 0 => f.write_str("FALSE"), + 1 => f.write_str("TRUE"), + // As with `Self::is_true`, treat any nonzero value as true. + v => write!(f, "TRUE ({v})"), + } + } +} + +/// Convenience trait to convert `bool` to `llvm::Bool` with an explicit method call. +/// +/// Being able to write `b.to_llvm_bool()` is less noisy than `llvm::Bool::from(b)`, +/// while being more explicit and less mistake-prone than something like `b.into()`. +pub(crate) trait ToLlvmBool: Copy { + fn to_llvm_bool(self) -> llvm::Bool; +} + +impl ToLlvmBool for bool { + #[inline(always)] + fn to_llvm_bool(self) -> llvm::Bool { + llvm::Bool::from_bool(self) + } +} /// Wrapper for a raw enum value returned from LLVM's C APIs. /// @@ -1881,11 +1929,17 @@ unsafe extern "C" { C: &Context, effects: MemoryEffects, ) -> &Attribute; + /// ## Safety + /// - Each of `LowerWords` and `UpperWords` must point to an array that is + /// long enough to fully define an integer of size `NumBits`, i.e. each + /// pointer must point to `NumBits.div_ceil(64)` elements or more. + /// - The implementation will make its own copy of the pointed-to `u64` + /// values, so the pointers only need to outlive this function call. pub(crate) fn LLVMRustCreateRangeAttribute( C: &Context, - num_bits: c_uint, - lower_words: *const u64, - upper_words: *const u64, + NumBits: c_uint, + LowerWords: *const u64, + UpperWords: *const u64, ) -> &Attribute; // Operations on functions diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 7fea7b79a8c..d6974e22c85 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -112,16 +112,26 @@ pub(crate) fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> & pub(crate) fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute { let lower = range.start; + // LLVM treats the upper bound as exclusive, but allows wrapping. let upper = range.end.wrapping_add(1); - let lower_words = [lower as u64, (lower >> 64) as u64]; - let upper_words = [upper as u64, (upper >> 64) as u64]; + + // Pass each `u128` endpoint value as a `[u64; 2]` array, least-significant part first. + let as_u64_array = |x: u128| [x as u64, (x >> 64) as u64]; + let lower_words: [u64; 2] = as_u64_array(lower); + let upper_words: [u64; 2] = as_u64_array(upper); + + // To ensure that LLVM doesn't try to read beyond the `[u64; 2]` arrays, + // we must explicitly check that `size_bits` does not exceed 128. + let size_bits = size.bits(); + assert!(size_bits <= 128); + // More robust assertions that are redundant with `size_bits <= 128` and + // should be optimized away. + assert!(size_bits.div_ceil(64) <= u64::try_from(lower_words.len()).unwrap()); + assert!(size_bits.div_ceil(64) <= u64::try_from(upper_words.len()).unwrap()); + let size_bits = c_uint::try_from(size_bits).unwrap(); + unsafe { - LLVMRustCreateRangeAttribute( - llcx, - size.bits().try_into().unwrap(), - lower_words.as_ptr(), - upper_words.as_ptr(), - ) + LLVMRustCreateRangeAttribute(llcx, size_bits, lower_words.as_ptr(), upper_words.as_ptr()) } } @@ -215,7 +225,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { } pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) { - LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); + LLVMSetGlobalConstant(llglobal, is_constant.to_llvm_bool()); } pub(crate) fn get_linkage(llglobal: &Value) -> Linkage { @@ -229,7 +239,7 @@ pub(crate) fn set_linkage(llglobal: &Value, linkage: Linkage) { } pub(crate) fn is_declaration(llglobal: &Value) -> bool { - unsafe { LLVMIsDeclaration(llglobal) == ffi::True } + unsafe { LLVMIsDeclaration(llglobal) }.is_true() } pub(crate) fn get_visibility(llglobal: &Value) -> Visibility { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 90f7cd43268..d927ffd78c2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -26,7 +26,7 @@ static INIT: Once = Once::new(); pub(crate) fn init(sess: &Session) { unsafe { // Before we touch LLVM, make sure that multithreading is enabled. - if llvm::LLVMIsMultithreaded() != 1 { + if !llvm::LLVMIsMultithreaded().is_true() { bug!("LLVM compiled without support for threads"); } INIT.call_once(|| { @@ -279,7 +279,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea } ("loongarch32" | "loongarch64", "32s") if get_version().0 < 21 => None, // Filter out features that are not supported by the current LLVM version - ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None, + ("riscv32" | "riscv64", "zacas" | "rva23u64" | "supm") if get_version().0 < 20 => None, ( "s390x", "message-security-assist-extension12" diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 5075befae8a..52eefe2d4d2 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -133,7 +133,7 @@ impl CodegenCx<'_, '_> { // Thread-local variables generally don't support copy relocations. let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) - .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); + .is_some_and(|v| llvm::LLVMIsThreadLocal(v).is_true()); if is_thread_local_var { return false; } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index f02d16baf94..9ecaf5f24fe 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -15,7 +15,7 @@ use rustc_target::callconv::{CastTarget, FnAbi}; use crate::abi::{FnAbiLlvmExt, LlvmType}; use crate::context::{CodegenCx, GenericCx, SCx}; pub(crate) use crate::llvm::Type; -use crate::llvm::{Bool, False, Metadata, True}; +use crate::llvm::{FALSE, Metadata, TRUE, ToLlvmBool}; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use crate::{common, llvm}; @@ -53,7 +53,9 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { } pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) { - unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) } + unsafe { + llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed.to_llvm_bool()) + } } pub(crate) fn type_void(&self) -> &'ll Type { unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } @@ -139,7 +141,7 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { } pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { - unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } + unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, TRUE) } } pub(crate) fn type_i1(&self) -> &'ll Type { @@ -152,7 +154,7 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { self.llcx(), els.as_ptr(), els.len() as c_uint, - packed as Bool, + packed.to_llvm_bool(), ) } } @@ -200,7 +202,7 @@ impl<'ll, CX: Borrow<SCx<'ll>>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { } fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { - unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, False) } + unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, FALSE) } } fn type_kind(&self, ty: &'ll Type) -> TypeKind { diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index 2274450e20e..b1d646d9265 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -164,7 +164,7 @@ pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> { // // Note that when cross-compiling from e.g. Linux, the `xcrun` binary may sometimes be provided // as a shim by a cross-compilation helper tool. It usually isn't, but we still try nonetheless. - match xcrun_show_sdk_path(sdk_name, sess.verbose_internals()) { + match xcrun_show_sdk_path(sdk_name, false) { Ok((path, stderr)) => { // Emit extra stderr, such as if `-verbose` was passed, or if `xcrun` emitted a warning. if !stderr.is_empty() { diff --git a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs index b9e0c957363..509168b2cd2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs +++ b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs @@ -307,11 +307,14 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] stub.reserve_section_headers(); stub.reserve_dynsym(); stub.reserve_dynstr(); + let verdef_count = 1 + vers.len(); + let mut dynamic_entries = 2; // DT_SONAME, DT_NULL if !vers.is_empty() { stub.reserve_gnu_versym(); - stub.reserve_gnu_verdef(1 + vers.len(), 1 + vers.len()); + stub.reserve_gnu_verdef(verdef_count, verdef_count); + dynamic_entries += 1; // DT_VERDEFNUM } - stub.reserve_dynamic(2); // DT_SONAME, DT_NULL + stub.reserve_dynamic(dynamic_entries); // First write the ELF header with the arch information. let e_machine = match (arch, sub_arch) { @@ -443,9 +446,13 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] // .dynamic // the DT_SONAME will be used by the linker to populate DT_NEEDED // which the loader uses to find the library. - // DT_NULL terminates the .dynamic table. stub.write_align_dynamic(); stub.write_dynamic_string(elf::DT_SONAME, soname); + // LSB section "2.7. Symbol Versioning" requires `DT_VERDEFNUM` to be reliable. + if verdef_count > 1 { + stub.write_dynamic(elf::DT_VERDEFNUM, verdef_count as u64); + } + // DT_NULL terminates the .dynamic table. stub.write_dynamic(elf::DT_NULL, 0); stub_buf diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index bf38c02e908..10aaadd5688 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -329,12 +329,18 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc let mut e_flags: u32 = 0x0; - // Check if compressed is enabled - // `unstable_target_features` is used here because "c" is gated behind riscv_target_feature. - if sess.unstable_target_features.contains(&sym::c) { + // Check if compression is enabled + // `unstable_target_features` is used here because "zca" is gated behind riscv_target_feature. + if sess.unstable_target_features.contains(&sym::zca) { e_flags |= elf::EF_RISCV_RVC; } + // Check if RVTSO is enabled + // `unstable_target_features` is used here because "ztso" is gated behind riscv_target_feature. + if sess.unstable_target_features.contains(&sym::ztso) { + e_flags |= elf::EF_RISCV_TSO; + } + // Set the appropriate flag based on ABI // This needs to match LLVM `RISCVELFStreamer.cpp` match &*sess.target.llvm_abiname { diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 77096822fdc..13419bcb22c 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -570,7 +570,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel // core/std/allocators/etc. For example symbols used to hook up allocation // are not considered for export let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); - let is_extern = codegen_fn_attrs.contains_extern_indicator(tcx, sym_def_id); + let is_extern = codegen_fn_attrs.contains_extern_indicator(); let std_internal = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 26d089a1171..9f22859ba81 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1,5 +1,6 @@ use std::assert_matches::assert_matches; use std::marker::PhantomData; +use std::panic::AssertUnwindSafe; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; @@ -14,7 +15,7 @@ use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_errors::emitter::Emitter; use rustc_errors::translation::Translator; use rustc_errors::{ - Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, Level, MultiSpan, Style, + Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalErrorMarker, Level, MultiSpan, Style, Suggestions, }; use rustc_fs_util::link_or_copy; @@ -395,8 +396,7 @@ fn generate_thin_lto_work<B: ExtraBackendMethods>( each_linked_rlib_for_lto, needs_thin_lto, import_only_modules, - ) - .unwrap_or_else(|e| e.raise()); + ); lto_modules .into_iter() .map(|module| { @@ -844,11 +844,11 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, mut module: ModuleCodegen<B::Module>, module_config: &ModuleConfig, -) -> Result<WorkItemResult<B>, FatalError> { +) -> WorkItemResult<B> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - B::optimize(cgcx, dcx, &mut module, module_config)?; + B::optimize(cgcx, dcx, &mut module, module_config); // After we've done the initial round of optimizations we need to // decide whether to synchronously codegen this module or ship it @@ -868,8 +868,8 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( match lto_type { ComputedLtoType::No => { - let module = B::codegen(cgcx, module, module_config)?; - Ok(WorkItemResult::Finished(module)) + let module = B::codegen(cgcx, module, module_config); + WorkItemResult::Finished(module) } ComputedLtoType::Thin => { let (name, thin_buffer) = B::prepare_thin(module, false); @@ -878,7 +878,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); } - Ok(WorkItemResult::NeedsThinLto(name, thin_buffer)) + WorkItemResult::NeedsThinLto(name, thin_buffer) } ComputedLtoType::Fat => match bitcode { Some(path) => { @@ -886,12 +886,12 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( fs::write(&path, buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); - Ok(WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { + WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { name, buffer: SerializedModule::Local(buffer), - })) + }) } - None => Ok(WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module))), + None => WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module)), }, } } @@ -987,7 +987,7 @@ fn execute_fat_lto_work_item<B: ExtraBackendMethods>( mut needs_fat_lto: Vec<FatLtoInput<B>>, import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>, module_config: &ModuleConfig, -) -> Result<WorkItemResult<B>, FatalError> { +) -> WorkItemResult<B> { for (module, wp) in import_only_modules { needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) } @@ -997,19 +997,19 @@ fn execute_fat_lto_work_item<B: ExtraBackendMethods>( exported_symbols_for_lto, each_linked_rlib_for_lto, needs_fat_lto, - )?; - let module = B::codegen(cgcx, module, module_config)?; - Ok(WorkItemResult::Finished(module)) + ); + let module = B::codegen(cgcx, module, module_config); + WorkItemResult::Finished(module) } fn execute_thin_lto_work_item<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, module: lto::ThinModule<B>, module_config: &ModuleConfig, -) -> Result<WorkItemResult<B>, FatalError> { - let module = B::optimize_thin(cgcx, module)?; - let module = B::codegen(cgcx, module, module_config)?; - Ok(WorkItemResult::Finished(module)) +) -> WorkItemResult<B> { + let module = B::optimize_thin(cgcx, module); + let module = B::codegen(cgcx, module, module_config); + WorkItemResult::Finished(module) } /// Messages sent to the coordinator. @@ -1722,37 +1722,10 @@ fn spawn_work<'a, B: ExtraBackendMethods>( let cgcx = cgcx.clone(); B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { - // Set up a destructor which will fire off a message that we're done as - // we exit. - struct Bomb<B: ExtraBackendMethods> { - coordinator_send: Sender<Message<B>>, - result: Option<Result<WorkItemResult<B>, FatalError>>, - } - impl<B: ExtraBackendMethods> Drop for Bomb<B> { - fn drop(&mut self) { - let msg = match self.result.take() { - Some(Ok(result)) => Message::WorkItem::<B> { result: Ok(result) }, - Some(Err(FatalError)) => { - Message::WorkItem::<B> { result: Err(Some(WorkerFatalError)) } - } - None => Message::WorkItem::<B> { result: Err(None) }, - }; - drop(self.coordinator_send.send(msg)); - } - } - - let mut bomb = Bomb::<B> { coordinator_send, result: None }; - - // Execute the work itself, and if it finishes successfully then flag - // ourselves as a success as well. - // - // Note that we ignore any `FatalError` coming out of `execute_work_item`, - // as a diagnostic was already sent off to the main thread - just - // surface that there was an error in this worker. - bomb.result = { + let result = std::panic::catch_unwind(AssertUnwindSafe(|| { let module_config = cgcx.config(work.module_kind()); - Some(match work { + match work { WorkItem::Optimize(m) => { let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name); @@ -1763,7 +1736,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( "codegen_copy_artifacts_from_incr_cache", &*m.name, ); - Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) + execute_copy_from_cache_work_item(&cgcx, m, module_config) } WorkItem::FatLto { exported_symbols_for_lto, @@ -1788,8 +1761,22 @@ fn spawn_work<'a, B: ExtraBackendMethods>( cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); execute_thin_lto_work_item(&cgcx, m, module_config) } - }) + } + })); + + let msg = match result { + Ok(result) => Message::WorkItem::<B> { result: Ok(result) }, + + // We ignore any `FatalError` coming out of `execute_work_item`, as a + // diagnostic was already sent off to the main thread - just surface + // that there was an error in this worker. + Err(err) if err.is::<FatalErrorMarker>() => { + Message::WorkItem::<B> { result: Err(Some(WorkerFatalError)) } + } + + Err(_) => Message::WorkItem::<B> { result: Err(None) }, }; + drop(coordinator_send.send(msg)); }) .expect("failed to spawn work thread"); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 6b0bd64102c..961bb788149 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -385,6 +385,8 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // Foreign items by default use no mangling for their symbol name. if tcx.is_foreign_item(did) { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FOREIGN_ITEM; + // There's a few exceptions to this rule though: if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index c29ad90735b..cc7c4e46d7b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use rustc_errors::{DiagCtxtHandle, FatalError}; +use rustc_errors::DiagCtxtHandle; use rustc_middle::dep_graph::WorkProduct; use crate::back::lto::{SerializedModule, ThinModule}; @@ -22,7 +22,7 @@ pub trait WriteBackendMethods: Clone + 'static { exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<FatLtoInput<Self>>, - ) -> Result<ModuleCodegen<Self::Module>, FatalError>; + ) -> ModuleCodegen<Self::Module>; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that /// can simply be copied over from the incr. comp. cache. @@ -32,7 +32,7 @@ pub trait WriteBackendMethods: Clone + 'static { each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError>; + ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>); fn print_pass_timings(&self); fn print_statistics(&self); fn optimize( @@ -40,16 +40,16 @@ pub trait WriteBackendMethods: Clone + 'static { dcx: DiagCtxtHandle<'_>, module: &mut ModuleCodegen<Self::Module>, config: &ModuleConfig, - ) -> Result<(), FatalError>; + ); fn optimize_thin( cgcx: &CodegenContext<Self>, thin: ThinModule<Self>, - ) -> Result<ModuleCodegen<Self::Module>, FatalError>; + ) -> ModuleCodegen<Self::Module>; fn codegen( cgcx: &CodegenContext<Self>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, - ) -> Result<CompiledModule, FatalError>; + ) -> CompiledModule; fn prepare_thin( module: ModuleCodegen<Self::Module>, want_summary: bool, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index da954cf4ed7..fccb6b171b1 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -280,22 +280,110 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { interp_ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int(a), Scalar::Int(b)) => (a == b) as u8, - // Comparisons of null with an arbitrary scalar can be known if `scalar_may_be_null` - // indicates that the scalar can definitely *not* be null. - (Scalar::Int(int), ptr) | (ptr, Scalar::Int(int)) - if int.is_null() && !self.scalar_may_be_null(ptr)? => - { - 0 + // Comparing a pointer `ptr` with an integer `int` is equivalent to comparing + // `ptr-int` with null, so we can reduce this case to a `scalar_may_be_null` test. + (Scalar::Int(int), Scalar::Ptr(ptr, _)) | (Scalar::Ptr(ptr, _), Scalar::Int(int)) => { + let int = int.to_target_usize(*self.tcx); + // The `wrapping_neg` here may produce a value that is not + // a valid target usize any more... but `wrapping_offset` handles that correctly. + let offset_ptr = ptr.wrapping_offset(Size::from_bytes(int.wrapping_neg()), self); + if !self.scalar_may_be_null(Scalar::from_pointer(offset_ptr, self))? { + // `ptr.wrapping_sub(int)` is definitely not equal to `0`, so `ptr != int` + 0 + } else { + // `ptr.wrapping_sub(int)` could be equal to `0`, but might not be, + // so we cannot know for sure if `ptr == int` or not + 2 + } + } + (Scalar::Ptr(a, _), Scalar::Ptr(b, _)) => { + let (a_prov, a_offset) = a.prov_and_relative_offset(); + let (b_prov, b_offset) = b.prov_and_relative_offset(); + let a_allocid = a_prov.alloc_id(); + let b_allocid = b_prov.alloc_id(); + let a_info = self.get_alloc_info(a_allocid); + let b_info = self.get_alloc_info(b_allocid); + + // Check if the pointers cannot be equal due to alignment + if a_info.align > Align::ONE && b_info.align > Align::ONE { + let min_align = Ord::min(a_info.align.bytes(), b_info.align.bytes()); + let a_residue = a_offset.bytes() % min_align; + let b_residue = b_offset.bytes() % min_align; + if a_residue != b_residue { + // If the two pointers have a different residue modulo their + // common alignment, they cannot be equal. + return interp_ok(0); + } + // The pointers have the same residue modulo their common alignment, + // so they could be equal. Try the other checks. + } + + if let (Some(GlobalAlloc::Static(a_did)), Some(GlobalAlloc::Static(b_did))) = ( + self.tcx.try_get_global_alloc(a_allocid), + self.tcx.try_get_global_alloc(b_allocid), + ) { + if a_allocid == b_allocid { + debug_assert_eq!( + a_did, b_did, + "different static item DefIds had same AllocId? {a_allocid:?} == {b_allocid:?}, {a_did:?} != {b_did:?}" + ); + // Comparing two pointers into the same static. As per + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.intro + // a static cannot be duplicated, so if two pointers are into the same + // static, they are equal if and only if their offsets are equal. + (a_offset == b_offset) as u8 + } else { + debug_assert_ne!( + a_did, b_did, + "same static item DefId had two different AllocIds? {a_allocid:?} != {b_allocid:?}, {a_did:?} == {b_did:?}" + ); + // Comparing two pointers into the different statics. + // We can never determine for sure that two pointers into different statics + // are *equal*, but we can know that they are *inequal* if they are both + // strictly in-bounds (i.e. in-bounds and not one-past-the-end) of + // their respective static, as different non-zero-sized statics cannot + // overlap or be deduplicated as per + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.intro + // (non-deduplication), and + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness + // (non-overlapping). + if a_offset < a_info.size && b_offset < b_info.size { + 0 + } else { + // Otherwise, conservatively say we don't know. + // There are some cases we could still return `0` for, e.g. + // if the pointers being equal would require their statics to overlap + // one or more bytes, but for simplicity we currently only check + // strictly in-bounds pointers. + 2 + } + } + } else { + // All other cases we conservatively say we don't know. + // + // For comparing statics to non-statics, as per https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness + // immutable statics can overlap with other kinds of allocations sometimes. + // + // FIXME: We could be more decisive for (non-zero-sized) mutable statics, + // which cannot overlap with other kinds of allocations. + // + // Functions and vtables can be duplicated and deduplicated, so we + // cannot be sure of runtime equality of pointers to the same one, or the + // runtime inequality of pointers to different ones (see e.g. #73722), + // so comparing those should return 2, whether they are the same allocation + // or not. + // + // `GlobalAlloc::TypeId` exists mostly to prevent consteval from comparing + // `TypeId`s, so comparing those should always return 2, whether they are the + // same allocation or not. + // + // FIXME: We could revisit comparing pointers into the same + // `GlobalAlloc::Memory` once https://github.com/rust-lang/rust/issues/128775 + // is fixed (but they can be deduplicated, so comparing pointers into different + // ones should return 2). + 2 + } } - // Other ways of comparing integers and pointers can never be known for sure. - (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2, - // FIXME: return a `1` for when both sides are the same pointer, *except* that - // some things (like functions and vtables) do not have stable addresses - // so we need to be careful around them (see e.g. #73722). - // FIXME: return `0` for at least some comparisons where we can reliably - // determine the result of runtime inequality tests at compile-time. - // Examples include comparison of addresses in different static items. - (Scalar::Ptr(..), Scalar::Ptr(..)) => 2, }) } } diff --git a/compiler/rustc_data_structures/src/frozen.rs b/compiler/rustc_data_structures/src/frozen.rs index 73190574667..4a60d17de2a 100644 --- a/compiler/rustc_data_structures/src/frozen.rs +++ b/compiler/rustc_data_structures/src/frozen.rs @@ -46,7 +46,7 @@ //! Frozen::freeze(new_bar)`). /// An owned immutable value. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Frozen<T>(T); impl<T> Frozen<T> { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 012bfe226f2..dbb4a9de9e0 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -7,12 +7,12 @@ use rustc_ast::mut_visit::*; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ - self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, CRATE_NODE_ID, - DUMMY_NODE_ID, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, - MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, + self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID, + ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, + MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeParser, EvalConfigResult, ShouldEmit, validate_attr}; +use rustc_attr_parsing::{AttributeParser, Early, EvalConfigResult, ShouldEmit, validate_attr}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::PResult; @@ -2165,7 +2165,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { None, Target::MacroCall, call.span(), - CRATE_NODE_ID, + self.cx.current_expansion.lint_node_id, Some(self.cx.ecfg.features), ShouldEmit::ErrorsAndLints, ); @@ -2184,7 +2184,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.cx.current_expansion.lint_node_id, BuiltinLintDiag::UnusedDocComment(attr.span), ); - } else if rustc_attr_parsing::is_builtin_attr(attr) { + } else if rustc_attr_parsing::is_builtin_attr(attr) + && !AttributeParser::<Early>::is_parsed_attribute(&attr.path()) + { let attr_name = attr.ident().unwrap().name; // `#[cfg]` and `#[cfg_attr]` are special - they are // eagerly evaluated. diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 061ec786dc8..0b24052b453 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -35,4 +35,5 @@ pub enum AttributeLintKind { IllFormedAttributeInput { suggestions: Vec<String> }, EmptyAttribute { first_span: Span }, InvalidTarget { name: AttrPath, target: Target, applied: Vec<String>, only: &'static str }, + InvalidStyle { name: AttrPath, is_used_as_inner: bool, target: Target, target_span: Span }, } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 2428c1aa29f..06f2ec512ab 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -509,10 +509,6 @@ hir_analysis_supertrait_item_shadowee = item from `{$supertrait}` is shadowed by hir_analysis_supertrait_item_shadowing = trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait -hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}` - .note = consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` - .opaque = this opaque type is supposed to be constrained - hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` hir_analysis_too_large_static = extern static is too large for the target architecture diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 50e20a19eda..b6d898886ac 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -4,9 +4,10 @@ use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravi use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, DefiningScopeKind, Ty, TyCtxt, TypeVisitableExt}; +use rustc_trait_selection::opaque_types::report_item_does_not_constrain_error; use tracing::{debug, instrument, trace}; -use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType}; +use crate::errors::UnconstrainedOpaqueType; /// Checks "defining uses" of opaque `impl Trait` in associated types. /// These can only be defined by associated items of the same trait. @@ -127,14 +128,11 @@ impl<'tcx> TaitConstraintLocator<'tcx> { } fn non_defining_use_in_defining_scope(&mut self, item_def_id: LocalDefId) { - let guar = self.tcx.dcx().emit_err(TaitForwardCompat2 { - span: self - .tcx - .def_ident_span(item_def_id) - .unwrap_or_else(|| self.tcx.def_span(item_def_id)), - opaque_type_span: self.tcx.def_span(self.def_id), - opaque_type: self.tcx.def_path_str(self.def_id), - }); + // We make sure that all opaque types get defined while + // type checking the defining scope, so this error is unreachable + // with the new solver. + assert!(!self.tcx.next_trait_solver_globally()); + let guar = report_item_does_not_constrain_error(self.tcx, item_def_id, self.def_id, None); self.insert_found(ty::OpaqueHiddenType::new_error(self.tcx, guar)); } @@ -252,9 +250,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( } else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) { hidden_ty.ty } else { - // FIXME(-Znext-solver): This should not be necessary and we should - // instead rely on inference variable fallback inside of typeck itself. - + assert!(!tcx.next_trait_solver_globally()); // We failed to resolve the opaque type or it // resolves to itself. We interpret this as the // no values of the hidden type ever being constructed, @@ -273,6 +269,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( if let Err(guar) = hir_ty.error_reported() { Ty::new_error(tcx, guar) } else { + assert!(!tcx.next_trait_solver_globally()); hir_ty } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 26a98722b34..6565ad7cf53 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -410,17 +410,6 @@ pub(crate) struct UnconstrainedOpaqueType { pub what: &'static str, } -#[derive(Diagnostic)] -#[diag(hir_analysis_tait_forward_compat2)] -#[note] -pub(crate) struct TaitForwardCompat2 { - #[primary_span] - pub span: Span, - #[note(hir_analysis_opaque)] - pub opaque_type_span: Span, - pub opaque_type: String, -} - pub(crate) struct MissingTypeParams { pub span: Span, pub def_span: Span, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3a153ab089a..44a5ceed469 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -82,7 +82,7 @@ mod coherence; mod collect; mod constrained_generic_params; mod delegation; -mod errors; +pub mod errors; pub mod hir_ty_lowering; pub mod hir_wf_check; mod impl_wf_check; diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 7afc555b598..4200afb74e6 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -511,7 +511,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Untranslatable diagnostics are okay for rustc internals #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { + if self.has_rustc_attrs + && self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) + { let predicates = self.tcx.predicates_of(def_id); let predicates = predicates.instantiate(self.tcx, args); for (predicate, predicate_span) in predicates { @@ -894,7 +896,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If we have `rustc_do_not_const_check`, do not check `[const]` bounds. - if self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) { + if self.has_rustc_attrs && self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) { return; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 0c6226ce71e..74f27e85cba 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -126,6 +126,10 @@ pub(crate) struct FnCtxt<'a, 'tcx> { /// These are stored here so we may collect them when canonicalizing user /// type ascriptions later. pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>, + + /// Whether the current crate enables the `rustc_attrs` feature. + /// This allows to skip processing attributes in many places. + pub(super) has_rustc_attrs: bool, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -154,6 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diverging_fallback_behavior, diverging_block_behavior, trait_ascriptions: Default::default(), + has_rustc_attrs: root_ctxt.tcx.features().rustc_attrs(), } } @@ -525,10 +530,13 @@ fn parse_never_type_options_attr( let mut fallback = None; let mut block = None; - let items = tcx - .get_attr(CRATE_DEF_ID, sym::rustc_never_type_options) - .map(|attr| attr.meta_item_list().unwrap()) - .unwrap_or_default(); + let items = if tcx.features().rustc_attrs() { + tcx.get_attr(CRATE_DEF_ID, sym::rustc_never_type_options) + .map(|attr| attr.meta_item_list().unwrap()) + } else { + None + }; + let items = items.unwrap_or_default(); for item in items { if item.has_name(sym::fallback) && fallback.is_none() { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 634647a595a..129de32fd4a 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -46,12 +46,12 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir as hir; -use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{HirId, HirIdMap, Node, find_attr}; +use rustc_hir::{HirId, HirIdMap, Node}; use rustc_hir_analysis::check::{check_abi, check_custom_abi}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -174,7 +174,7 @@ fn typeck_with_inspect<'tcx>( .map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)), ); - if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Naked(..)) { + if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) { naked_functions::typeck_naked_fn(tcx, def_id, body); } @@ -247,6 +247,13 @@ fn typeck_with_inspect<'tcx>( debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); + // We need to handle opaque types before emitting ambiguity errors as applying + // defining uses may guide type inference. + if fcx.next_trait_solver() { + fcx.handle_opaque_type_uses_next(); + } + + fcx.select_obligations_where_possible(|_| {}); if let None = fcx.infcx.tainted_by_errors() { fcx.report_ambiguity_errors(); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index f5c3ebd8375..bb4748b0565 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -777,31 +777,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_impl_candidates_for_type(p.def_id(), receiver_steps); - if self.tcx.has_attr(p.def_id(), sym::rustc_has_incoherent_inherent_impls) { - self.assemble_inherent_candidates_for_incoherent_ty( - raw_self_ty, - receiver_steps, - ); - } + self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps); } ty::Adt(def, _) => { let def_id = def.did(); self.assemble_inherent_impl_candidates_for_type(def_id, receiver_steps); - if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) { - self.assemble_inherent_candidates_for_incoherent_ty( - raw_self_ty, - receiver_steps, - ); - } + self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps); } ty::Foreign(did) => { self.assemble_inherent_impl_candidates_for_type(did, receiver_steps); - if self.tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { - self.assemble_inherent_candidates_for_incoherent_ty( - raw_self_ty, - receiver_steps, - ); - } + self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps); } ty::Param(_) => { self.assemble_inherent_candidates_from_param(raw_self_ty); @@ -2400,17 +2385,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if !self.is_relevant_kind_for_mode(x.kind) { return false; } - if self.matches_by_doc_alias(x.def_id) { - return true; - } - match edit_distance_with_substrings( + if let Some(d) = edit_distance_with_substrings( name.as_str(), x.name().as_str(), max_dist, ) { - Some(d) => d > 0, - None => false, + return d > 0; } + self.matches_by_doc_alias(x.def_id) }) .copied() .collect() diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index e0224f8c6e1..97feac3d009 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -1,5 +1,218 @@ -use super::FnCtxt; +use rustc_hir::def::DefKind; +use rustc_infer::traits::ObligationCause; +use rustc_middle::ty::{ + self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, TypeVisitableExt, + TypingMode, +}; +use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; +use rustc_trait_selection::opaque_types::{ + NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error, +}; +use rustc_trait_selection::solve; +use tracing::{debug, instrument}; + +use crate::FnCtxt; + impl<'tcx> FnCtxt<'_, 'tcx> { + /// This takes all the opaque type uses during HIR typeck. It first computes + /// the concrete hidden type by iterating over all defining uses. + /// + /// A use during HIR typeck is defining if all non-lifetime arguments are + /// unique generic parameters and the hidden type does not reference any + /// inference variables. + /// + /// It then uses these defining uses to guide inference for all other uses. + #[instrument(level = "debug", skip(self))] + pub(super) fn handle_opaque_type_uses_next(&mut self) { + // We clone the opaques instead of stealing them here as they are still used for + // normalization in the next generation trait solver. + let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types(); + let num_entries = self.inner.borrow_mut().opaque_types().num_entries(); + let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries)); + debug_assert_eq!(prev, None); + for entry in &mut opaque_types { + *entry = self.resolve_vars_if_possible(*entry); + } + debug!(?opaque_types); + + self.compute_concrete_opaque_types(&opaque_types); + self.apply_computed_concrete_opaque_types(&opaque_types); + } +} + +enum UsageKind<'tcx> { + None, + NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>), + UnconstrainedHiddenType(OpaqueHiddenType<'tcx>), + HasDefiningUse, +} + +impl<'tcx> UsageKind<'tcx> { + fn merge(&mut self, other: UsageKind<'tcx>) { + match (&*self, &other) { + (UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(), + (UsageKind::None, _) => *self = other, + // When mergining non-defining uses, prefer earlier ones. This means + // the error happens as early as possible. + ( + UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..), + UsageKind::NonDefiningUse(..), + ) => {} + // When merging unconstrained hidden types, we prefer later ones. This is + // used as in most cases, the defining use is the final return statement + // of our function, and other uses with defining arguments are likely not + // intended to be defining. + ( + UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..), + UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse, + ) => *self = other, + } + } +} + +impl<'tcx> FnCtxt<'_, 'tcx> { + fn compute_concrete_opaque_types( + &mut self, + opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], + ) { + let tcx = self.tcx; + let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() + else { + unreachable!(); + }; + + for def_id in defining_opaque_types_and_generators { + match tcx.def_kind(def_id) { + DefKind::OpaqueTy => {} + DefKind::Closure => continue, + _ => unreachable!("not opaque or generator: {def_id:?}"), + } + + let mut usage_kind = UsageKind::None; + for &(opaque_type_key, hidden_type) in opaque_types { + if opaque_type_key.def_id != def_id { + continue; + } + + usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type)); + if let UsageKind::HasDefiningUse = usage_kind { + break; + } + } + + let guar = match usage_kind { + UsageKind::None => { + if let Some(guar) = self.tainted_by_errors() { + guar + } else { + report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None) + } + } + UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => { + report_item_does_not_constrain_error( + self.tcx, + self.body_id, + def_id, + Some((opaque_type_key, hidden_type.span)), + ) + } + UsageKind::UnconstrainedHiddenType(hidden_type) => { + let infer_var = hidden_type + .ty + .walk() + .filter_map(ty::GenericArg::as_term) + .find(|term| term.is_infer()) + .unwrap_or_else(|| hidden_type.ty.into()); + self.err_ctxt() + .emit_inference_failure_err( + self.body_id, + hidden_type.span, + infer_var, + TypeAnnotationNeeded::E0282, + false, + ) + .emit() + } + UsageKind::HasDefiningUse => continue, + }; + + self.typeck_results + .borrow_mut() + .concrete_opaque_types + .insert(def_id, OpaqueHiddenType::new_error(tcx, guar)); + self.set_tainted_by_errors(guar); + } + } + + fn consider_opaque_type_use( + &mut self, + opaque_type_key: OpaqueTypeKey<'tcx>, + hidden_type: OpaqueHiddenType<'tcx>, + ) -> UsageKind<'tcx> { + if let Err(err) = opaque_type_has_defining_use_args( + &self, + opaque_type_key, + hidden_type.span, + DefiningScopeKind::HirTypeck, + ) { + match err { + NonDefiningUseReason::Tainted(guar) => { + self.typeck_results.borrow_mut().concrete_opaque_types.insert( + opaque_type_key.def_id, + OpaqueHiddenType::new_error(self.tcx, guar), + ); + return UsageKind::HasDefiningUse; + } + _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type), + }; + } + + // We ignore uses of the opaque if they have any inference variables + // as this can frequently happen with recursive calls. + // + // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`. + if hidden_type.ty.has_non_region_infer() { + return UsageKind::UnconstrainedHiddenType(hidden_type); + } + + let cause = ObligationCause::misc(hidden_type.span, self.body_id); + let at = self.at(&cause, self.param_env); + let hidden_type = match solve::deeply_normalize(at, hidden_type) { + Ok(hidden_type) => hidden_type, + Err(errors) => { + let guar = self.err_ctxt().report_fulfillment_errors(errors); + OpaqueHiddenType::new_error(self.tcx, guar) + } + }; + let hidden_type = hidden_type.remap_generic_params_to_declaration_params( + opaque_type_key, + self.tcx, + DefiningScopeKind::HirTypeck, + ); + + let prev = self + .typeck_results + .borrow_mut() + .concrete_opaque_types + .insert(opaque_type_key.def_id, hidden_type); + assert!(prev.is_none()); + UsageKind::HasDefiningUse + } + + fn apply_computed_concrete_opaque_types( + &mut self, + opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], + ) { + let tcx = self.tcx; + for &(key, hidden_type) in opaque_types { + let expected = + *self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap(); + + let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); + self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); + } + } + /// We may in theory add further uses of an opaque after cloning the opaque /// types storage during writeback when computing the defining uses. /// diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 50fa3f2cc9d..06acff06a51 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool { - self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis) + self.has_rustc_attrs && self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis) } fn log_capture_analysis_first_pass( diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 131c687bddc..d75bc9edab2 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::{ }; use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; -use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid; +use rustc_trait_selection::opaque_types::opaque_type_has_defining_use_args; use rustc_trait_selection::solve; use tracing::{debug, instrument}; @@ -45,7 +45,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. - let rustc_dump_user_args = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args); + let rustc_dump_user_args = + self.has_rustc_attrs && self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_args); for param in body.params { @@ -546,8 +547,24 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_opaque_types_next(&mut self) { + let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut(); + assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); + for hidden_ty in fcx_typeck_results.concrete_opaque_types.values() { + assert!(!hidden_ty.has_infer()); + } + + assert_eq!(self.typeck_results.concrete_opaque_types.len(), 0); + self.typeck_results.concrete_opaque_types = + mem::take(&mut fcx_typeck_results.concrete_opaque_types); + } + #[instrument(skip(self), level = "debug")] fn visit_opaque_types(&mut self) { + if self.fcx.next_trait_solver() { + return self.visit_opaque_types_next(); + } + let tcx = self.tcx(); // We clone the opaques instead of stealing them here as they are still used for // normalization in the next generation trait solver. @@ -558,17 +575,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { for (opaque_type_key, hidden_type) in opaque_types { let hidden_type = self.resolve(hidden_type, &hidden_type.span); let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span); - - if !self.fcx.next_trait_solver() { - if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() - && alias_ty.def_id == opaque_type_key.def_id.to_def_id() - && alias_ty.args == opaque_type_key.args - { - continue; - } + if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() + && alias_ty.def_id == opaque_type_key.def_id.to_def_id() + && alias_ty.args == opaque_type_key.args + { + continue; } - if let Err(err) = check_opaque_type_parameter_valid( + if let Err(err) = opaque_type_has_defining_use_args( &self.fcx, opaque_type_key, hidden_type.span, @@ -923,6 +937,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { } } + #[instrument(level = "debug", skip(self, outer_exclusive_binder, new_err))] fn handle_term<T>( &mut self, value: T, diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 645d95b1dba..684bd34f909 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -491,19 +491,15 @@ pub struct ChunkedBitSet<T> { marker: PhantomData<T>, } -// Note: the chunk domain size is duplicated in each variant. This is a bit -// inconvenient, but it allows the type size to be smaller than if we had an -// outer struct containing a chunk domain size plus the `Chunk`, because the -// compiler can place the chunk domain size after the tag. +// NOTE: The chunk size is computed on-the-fly on each manipulation of a chunk. +// This avoids storing it, as it's almost always CHUNK_BITS except for the last one. #[derive(Clone, Debug, PartialEq, Eq)] enum Chunk { /// A chunk that is all zeros; we don't represent the zeros explicitly. - /// The `ChunkSize` is always non-zero. - Zeros(ChunkSize), + Zeros, /// A chunk that is all ones; we don't represent the ones explicitly. - /// `ChunkSize` is always non-zero. - Ones(ChunkSize), + Ones, /// A chunk that has a mix of zeros and ones, which are represented /// explicitly and densely. It never has all zeros or all ones. @@ -514,16 +510,14 @@ enum Chunk { /// to store the length, which would make this type larger. These excess /// words are always zero, as are any excess bits in the final in-use word. /// - /// The first `ChunkSize` field is always non-zero. - /// - /// The second `ChunkSize` field is the count of 1s set in the chunk, and + /// The `ChunkSize` field is the count of 1s set in the chunk, and /// must satisfy `0 < count < chunk_domain_size`. /// /// The words are within an `Rc` because it's surprisingly common to /// duplicate an entire chunk, e.g. in `ChunkedBitSet::clone_from()`, or /// when a `Mixed` chunk is union'd into a `Zeros` chunk. When we do need /// to modify a chunk we use `Rc::make_mut`. - Mixed(ChunkSize, ChunkSize, Rc<[Word; CHUNK_WORDS]>), + Mixed(ChunkSize, Rc<[Word; CHUNK_WORDS]>), } // This type is used a lot. Make sure it doesn't unintentionally get bigger. @@ -535,6 +529,22 @@ impl<T> ChunkedBitSet<T> { self.domain_size } + #[inline] + fn last_chunk_size(&self) -> ChunkSize { + let n = self.domain_size % CHUNK_BITS; + if n == 0 { CHUNK_BITS as ChunkSize } else { n as ChunkSize } + } + + /// All the chunks have a chunk_domain_size of `CHUNK_BITS` except the final one. + #[inline] + fn chunk_domain_size(&self, chunk: usize) -> ChunkSize { + if chunk == self.chunks.len() - 1 { + self.last_chunk_size() + } else { + CHUNK_BITS as ChunkSize + } + } + #[cfg(test)] fn assert_valid(&self) { if self.domain_size == 0 { @@ -544,8 +554,9 @@ impl<T> ChunkedBitSet<T> { assert!((self.chunks.len() - 1) * CHUNK_BITS <= self.domain_size); assert!(self.chunks.len() * CHUNK_BITS >= self.domain_size); - for chunk in self.chunks.iter() { - chunk.assert_valid(); + for (chunk_index, chunk) in self.chunks.iter().enumerate() { + let chunk_domain_size = self.chunk_domain_size(chunk_index); + chunk.assert_valid(chunk_domain_size); } } } @@ -556,16 +567,7 @@ impl<T: Idx> ChunkedBitSet<T> { let chunks = if domain_size == 0 { Box::new([]) } else { - // All the chunks have a chunk_domain_size of `CHUNK_BITS` except - // the final one. - let final_chunk_domain_size = { - let n = domain_size % CHUNK_BITS; - if n == 0 { CHUNK_BITS } else { n } - }; - let mut chunks = - vec![Chunk::new(CHUNK_BITS, is_empty); num_chunks(domain_size)].into_boxed_slice(); - *chunks.last_mut().unwrap() = Chunk::new(final_chunk_domain_size, is_empty); - chunks + vec![if is_empty { Zeros } else { Ones }; num_chunks(domain_size)].into_boxed_slice() }; ChunkedBitSet { domain_size, chunks, marker: PhantomData } } @@ -594,11 +596,15 @@ impl<T: Idx> ChunkedBitSet<T> { /// Count the number of bits in the set. pub fn count(&self) -> usize { - self.chunks.iter().map(|chunk| chunk.count()).sum() + self.chunks + .iter() + .enumerate() + .map(|(index, chunk)| chunk.count(self.chunk_domain_size(index))) + .sum() } pub fn is_empty(&self) -> bool { - self.chunks.iter().all(|chunk| matches!(chunk, Zeros(..))) + self.chunks.iter().all(|chunk| matches!(chunk, Zeros)) } /// Returns `true` if `self` contains `elem`. @@ -607,9 +613,9 @@ impl<T: Idx> ChunkedBitSet<T> { assert!(elem.index() < self.domain_size); let chunk = &self.chunks[chunk_index(elem)]; match &chunk { - Zeros(_) => false, - Ones(_) => true, - Mixed(_, _, words) => { + Zeros => false, + Ones => true, + Mixed(_, words) => { let (word_index, mask) = chunk_word_index_and_mask(elem); (words[word_index] & mask) != 0 } @@ -625,9 +631,10 @@ impl<T: Idx> ChunkedBitSet<T> { pub fn insert(&mut self, elem: T) -> bool { assert!(elem.index() < self.domain_size); let chunk_index = chunk_index(elem); + let chunk_domain_size = self.chunk_domain_size(chunk_index); let chunk = &mut self.chunks[chunk_index]; match *chunk { - Zeros(chunk_domain_size) => { + Zeros => { if chunk_domain_size > 1 { #[cfg(feature = "nightly")] let mut words = { @@ -649,14 +656,14 @@ impl<T: Idx> ChunkedBitSet<T> { let (word_index, mask) = chunk_word_index_and_mask(elem); words_ref[word_index] |= mask; - *chunk = Mixed(chunk_domain_size, 1, words); + *chunk = Mixed(1, words); } else { - *chunk = Ones(chunk_domain_size); + *chunk = Ones; } true } - Ones(_) => false, - Mixed(chunk_domain_size, ref mut count, ref mut words) => { + Ones => false, + Mixed(ref mut count, ref mut words) => { // We skip all the work if the bit is already set. let (word_index, mask) = chunk_word_index_and_mask(elem); if (words[word_index] & mask) == 0 { @@ -665,7 +672,7 @@ impl<T: Idx> ChunkedBitSet<T> { let words = Rc::make_mut(words); words[word_index] |= mask; } else { - *chunk = Ones(chunk_domain_size); + *chunk = Ones; } true } else { @@ -678,11 +685,7 @@ impl<T: Idx> ChunkedBitSet<T> { /// Sets all bits to true. pub fn insert_all(&mut self) { for chunk in self.chunks.iter_mut() { - *chunk = match *chunk { - Zeros(chunk_domain_size) - | Ones(chunk_domain_size) - | Mixed(chunk_domain_size, ..) => Ones(chunk_domain_size), - } + *chunk = Ones; } } @@ -690,10 +693,11 @@ impl<T: Idx> ChunkedBitSet<T> { pub fn remove(&mut self, elem: T) -> bool { assert!(elem.index() < self.domain_size); let chunk_index = chunk_index(elem); + let chunk_domain_size = self.chunk_domain_size(chunk_index); let chunk = &mut self.chunks[chunk_index]; match *chunk { - Zeros(_) => false, - Ones(chunk_domain_size) => { + Zeros => false, + Ones => { if chunk_domain_size > 1 { #[cfg(feature = "nightly")] let mut words = { @@ -722,13 +726,13 @@ impl<T: Idx> ChunkedBitSet<T> { ); let (word_index, mask) = chunk_word_index_and_mask(elem); words_ref[word_index] &= !mask; - *chunk = Mixed(chunk_domain_size, chunk_domain_size - 1, words); + *chunk = Mixed(chunk_domain_size - 1, words); } else { - *chunk = Zeros(chunk_domain_size); + *chunk = Zeros; } true } - Mixed(chunk_domain_size, ref mut count, ref mut words) => { + Mixed(ref mut count, ref mut words) => { // We skip all the work if the bit is already clear. let (word_index, mask) = chunk_word_index_and_mask(elem); if (words[word_index] & mask) != 0 { @@ -737,7 +741,7 @@ impl<T: Idx> ChunkedBitSet<T> { let words = Rc::make_mut(words); words[word_index] &= !mask; } else { - *chunk = Zeros(chunk_domain_size); + *chunk = Zeros } true } else { @@ -748,11 +752,12 @@ impl<T: Idx> ChunkedBitSet<T> { } fn chunk_iter(&self, chunk_index: usize) -> ChunkIter<'_> { + let chunk_domain_size = self.chunk_domain_size(chunk_index); match self.chunks.get(chunk_index) { - Some(Zeros(_chunk_domain_size)) => ChunkIter::Zeros, - Some(Ones(chunk_domain_size)) => ChunkIter::Ones(0..*chunk_domain_size as usize), - Some(Mixed(chunk_domain_size, _, words)) => { - let num_words = num_words(*chunk_domain_size as usize); + Some(Zeros) => ChunkIter::Zeros, + Some(Ones) => ChunkIter::Ones(0..chunk_domain_size as usize), + Some(Mixed(_, words)) => { + let num_words = num_words(chunk_domain_size as usize); ChunkIter::Mixed(BitIter::new(&words[0..num_words])) } None => ChunkIter::Finished, @@ -765,23 +770,33 @@ impl<T: Idx> ChunkedBitSet<T> { impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { fn union(&mut self, other: &ChunkedBitSet<T>) -> bool { assert_eq!(self.domain_size, other.domain_size); - debug_assert_eq!(self.chunks.len(), other.chunks.len()); + + let num_chunks = self.chunks.len(); + debug_assert_eq!(num_chunks, other.chunks.len()); + + let last_chunk_size = self.last_chunk_size(); + debug_assert_eq!(last_chunk_size, other.last_chunk_size()); let mut changed = false; - for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) { + for (chunk_index, (mut self_chunk, other_chunk)) in + self.chunks.iter_mut().zip(other.chunks.iter()).enumerate() + { + let chunk_domain_size = if chunk_index + 1 == num_chunks { + last_chunk_size + } else { + CHUNK_BITS as ChunkSize + }; + match (&mut self_chunk, &other_chunk) { - (_, Zeros(_)) | (Ones(_), _) => {} - (Zeros(self_chunk_domain_size), Ones(other_chunk_domain_size)) - | (Mixed(self_chunk_domain_size, ..), Ones(other_chunk_domain_size)) - | (Zeros(self_chunk_domain_size), Mixed(other_chunk_domain_size, ..)) => { + (_, Zeros) | (Ones, _) => {} + (Zeros, Ones) | (Mixed(..), Ones) | (Zeros, Mixed(..)) => { // `other_chunk` fully overwrites `self_chunk` - debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); *self_chunk = other_chunk.clone(); changed = true; } ( - Mixed(self_chunk_domain_size, self_chunk_count, self_chunk_words), - Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), + Mixed(self_chunk_count, self_chunk_words), + Mixed(_other_chunk_count, other_chunk_words), ) => { // First check if the operation would change // `self_chunk.words`. If not, we can avoid allocating some @@ -789,7 +804,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { // performance win. Also, we only need to operate on the // in-use words, hence the slicing. let op = |a, b| a | b; - let num_words = num_words(*self_chunk_domain_size as usize); + let num_words = num_words(chunk_domain_size as usize); if bitwise_changes( &self_chunk_words[0..num_words], &other_chunk_words[0..num_words], @@ -806,8 +821,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { .iter() .map(|w| w.count_ones() as ChunkSize) .sum(); - if *self_chunk_count == *self_chunk_domain_size { - *self_chunk = Ones(*self_chunk_domain_size); + if *self_chunk_count == chunk_domain_size { + *self_chunk = Ones; } changed = true; } @@ -819,36 +834,41 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool { assert_eq!(self.domain_size, other.domain_size); - debug_assert_eq!(self.chunks.len(), other.chunks.len()); + + let num_chunks = self.chunks.len(); + debug_assert_eq!(num_chunks, other.chunks.len()); + + let last_chunk_size = self.last_chunk_size(); + debug_assert_eq!(last_chunk_size, other.last_chunk_size()); let mut changed = false; - for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) { + for (chunk_index, (mut self_chunk, other_chunk)) in + self.chunks.iter_mut().zip(other.chunks.iter()).enumerate() + { + let chunk_domain_size = if chunk_index + 1 == num_chunks { + last_chunk_size + } else { + CHUNK_BITS as ChunkSize + }; + match (&mut self_chunk, &other_chunk) { - (Zeros(..), _) | (_, Zeros(..)) => {} - ( - Ones(self_chunk_domain_size) | Mixed(self_chunk_domain_size, _, _), - Ones(other_chunk_domain_size), - ) => { - debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + (Zeros, _) | (_, Zeros) => {} + (Ones | Mixed(_, _), Ones) => { changed = true; - *self_chunk = Zeros(*self_chunk_domain_size); + *self_chunk = Zeros; } - ( - Ones(self_chunk_domain_size), - Mixed(other_chunk_domain_size, other_chunk_count, other_chunk_words), - ) => { - debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + (Ones, Mixed(other_chunk_count, other_chunk_words)) => { changed = true; - let num_words = num_words(*self_chunk_domain_size as usize); + let num_words = num_words(chunk_domain_size as usize); debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS); let mut tail_mask = - 1 << (*other_chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1; + 1 << (chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1; let mut self_chunk_words = **other_chunk_words; for word in self_chunk_words[0..num_words].iter_mut().rev() { *word = !*word & tail_mask; tail_mask = u64::MAX; } - let self_chunk_count = *self_chunk_domain_size - *other_chunk_count; + let self_chunk_count = chunk_domain_size - *other_chunk_count; debug_assert_eq!( self_chunk_count, self_chunk_words[0..num_words] @@ -856,16 +876,15 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { .map(|w| w.count_ones() as ChunkSize) .sum() ); - *self_chunk = - Mixed(*self_chunk_domain_size, self_chunk_count, Rc::new(self_chunk_words)); + *self_chunk = Mixed(self_chunk_count, Rc::new(self_chunk_words)); } ( - Mixed(self_chunk_domain_size, self_chunk_count, self_chunk_words), - Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), + Mixed(self_chunk_count, self_chunk_words), + Mixed(_other_chunk_count, other_chunk_words), ) => { // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation let op = |a: u64, b: u64| a & !b; - let num_words = num_words(*self_chunk_domain_size as usize); + let num_words = num_words(chunk_domain_size as usize); if bitwise_changes( &self_chunk_words[0..num_words], &other_chunk_words[0..num_words], @@ -883,7 +902,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { .map(|w| w.count_ones() as ChunkSize) .sum(); if *self_chunk_count == 0 { - *self_chunk = Zeros(*self_chunk_domain_size); + *self_chunk = Zeros; } changed = true; } @@ -895,28 +914,36 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool { assert_eq!(self.domain_size, other.domain_size); - debug_assert_eq!(self.chunks.len(), other.chunks.len()); + + let num_chunks = self.chunks.len(); + debug_assert_eq!(num_chunks, other.chunks.len()); + + let last_chunk_size = self.last_chunk_size(); + debug_assert_eq!(last_chunk_size, other.last_chunk_size()); let mut changed = false; - for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) { + for (chunk_index, (mut self_chunk, other_chunk)) in + self.chunks.iter_mut().zip(other.chunks.iter()).enumerate() + { + let chunk_domain_size = if chunk_index + 1 == num_chunks { + last_chunk_size + } else { + CHUNK_BITS as ChunkSize + }; + match (&mut self_chunk, &other_chunk) { - (Zeros(..), _) | (_, Ones(..)) => {} - ( - Ones(self_chunk_domain_size), - Zeros(other_chunk_domain_size) | Mixed(other_chunk_domain_size, ..), - ) - | (Mixed(self_chunk_domain_size, ..), Zeros(other_chunk_domain_size)) => { - debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + (Zeros, _) | (_, Ones) => {} + (Ones, Zeros | Mixed(..)) | (Mixed(..), Zeros) => { changed = true; *self_chunk = other_chunk.clone(); } ( - Mixed(self_chunk_domain_size, self_chunk_count, self_chunk_words), - Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), + Mixed(self_chunk_count, self_chunk_words), + Mixed(_other_chunk_count, other_chunk_words), ) => { // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation let op = |a, b| a & b; - let num_words = num_words(*self_chunk_domain_size as usize); + let num_words = num_words(chunk_domain_size as usize); if bitwise_changes( &self_chunk_words[0..num_words], &other_chunk_words[0..num_words], @@ -934,7 +961,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { .map(|w| w.count_ones() as ChunkSize) .sum(); if *self_chunk_count == 0 { - *self_chunk = Zeros(*self_chunk_domain_size); + *self_chunk = Zeros; } changed = true; } @@ -964,7 +991,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for DenseBitSet<T> { words = &mut words[..CHUNK_WORDS]; } match chunk { - Zeros(..) => { + Zeros => { for word in words { if *word != 0 { changed = true; @@ -972,8 +999,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for DenseBitSet<T> { } } } - Ones(..) => (), - Mixed(_, _, data) => { + Ones => (), + Mixed(_, data) => { for (i, word) in words.iter_mut().enumerate() { let new_val = *word & data[i]; if new_val != *word { @@ -1053,13 +1080,11 @@ impl<'a, T: Idx> Iterator for ChunkedBitIter<'a, T> { impl Chunk { #[cfg(test)] - fn assert_valid(&self) { + fn assert_valid(&self, chunk_domain_size: ChunkSize) { + assert!(chunk_domain_size as usize <= CHUNK_BITS); match *self { - Zeros(chunk_domain_size) | Ones(chunk_domain_size) => { - assert!(chunk_domain_size as usize <= CHUNK_BITS); - } - Mixed(chunk_domain_size, count, ref words) => { - assert!(chunk_domain_size as usize <= CHUNK_BITS); + Zeros | Ones => {} + Mixed(count, ref words) => { assert!(0 < count && count < chunk_domain_size); // Check the number of set bits matches `count`. @@ -1083,18 +1108,12 @@ impl Chunk { } } - fn new(chunk_domain_size: usize, is_empty: bool) -> Self { - debug_assert!(0 < chunk_domain_size && chunk_domain_size <= CHUNK_BITS); - let chunk_domain_size = chunk_domain_size as ChunkSize; - if is_empty { Zeros(chunk_domain_size) } else { Ones(chunk_domain_size) } - } - /// Count the number of 1s in the chunk. - fn count(&self) -> usize { + fn count(&self, chunk_domain_size: ChunkSize) -> usize { match *self { - Zeros(_) => 0, - Ones(chunk_domain_size) => chunk_domain_size as usize, - Mixed(_, count, _) => count as usize, + Zeros => 0, + Ones => chunk_domain_size as usize, + Mixed(count, _) => count as usize, } } } diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 9ce4cf4293f..deddc872614 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -120,8 +120,9 @@ fn chunked_bitset() { let mut b1 = ChunkedBitSet::<usize>::new_empty(1); assert_eq!( b1, - ChunkedBitSet { domain_size: 1, chunks: Box::new([Zeros(1)]), marker: PhantomData } + ChunkedBitSet { domain_size: 1, chunks: Box::new([Zeros]), marker: PhantomData } ); + assert_eq!(b1.chunk_domain_size(0), 1); b1.assert_valid(); assert!(!b1.contains(0)); @@ -129,12 +130,12 @@ fn chunked_bitset() { assert!(b1.insert(0)); assert!(b1.contains(0)); assert_eq!(b1.count(), 1); - assert_eq!(b1.chunks(), [Ones(1)]); + assert_eq!(b1.chunks(), [Ones]); assert!(!b1.insert(0)); assert!(b1.remove(0)); assert!(!b1.contains(0)); assert_eq!(b1.count(), 0); - assert_eq!(b1.chunks(), [Zeros(1)]); + assert_eq!(b1.chunks(), [Zeros]); b1.assert_valid(); //----------------------------------------------------------------------- @@ -142,8 +143,9 @@ fn chunked_bitset() { let mut b100 = ChunkedBitSet::<usize>::new_filled(100); assert_eq!( b100, - ChunkedBitSet { domain_size: 100, chunks: Box::new([Ones(100)]), marker: PhantomData } + ChunkedBitSet { domain_size: 100, chunks: Box::new([Ones]), marker: PhantomData } ); + assert_eq!(b100.chunk_domain_size(0), 100); b100.assert_valid(); for i in 0..100 { @@ -152,7 +154,7 @@ fn chunked_bitset() { assert_eq!(b100.count(), 100); assert!(b100.remove(3)); assert!(b100.insert(3)); - assert_eq!(b100.chunks(), vec![Ones(100)]); + assert_eq!(b100.chunks(), vec![Ones]); assert!( b100.remove(20) && b100.remove(30) && b100.remove(40) && b100.remove(99) && b100.insert(30) ); @@ -161,7 +163,6 @@ fn chunked_bitset() { assert_eq!( b100.chunks(), vec![Mixed( - 100, 97, #[rustfmt::skip] Rc::new([ @@ -180,7 +181,7 @@ fn chunked_bitset() { } } assert_eq!(num_removed, 97); - assert_eq!(b100.chunks(), vec![Zeros(100)]); + assert_eq!(b100.chunks(), vec![Zeros]); b100.assert_valid(); //----------------------------------------------------------------------- @@ -188,23 +189,21 @@ fn chunked_bitset() { let mut b2548 = ChunkedBitSet::<usize>::new_empty(2548); assert_eq!( b2548, - ChunkedBitSet { - domain_size: 2548, - chunks: Box::new([Zeros(2048), Zeros(500)]), - marker: PhantomData, - } + ChunkedBitSet { domain_size: 2548, chunks: Box::new([Zeros, Zeros]), marker: PhantomData } ); + assert_eq!(b2548.chunk_domain_size(0), 2048); + assert_eq!(b2548.chunk_domain_size(1), 500); b2548.assert_valid(); b2548.insert(14); b2548.remove(14); - assert_eq!(b2548.chunks(), vec![Zeros(2048), Zeros(500)]); + assert_eq!(b2548.chunks(), vec![Zeros, Zeros]); b2548.insert_all(); for i in 0..2548 { assert!(b2548.contains(i)); } assert_eq!(b2548.count(), 2548); - assert_eq!(b2548.chunks(), vec![Ones(2048), Ones(500)]); + assert_eq!(b2548.chunks(), vec![Ones, Ones]); b2548.assert_valid(); //----------------------------------------------------------------------- @@ -212,12 +211,10 @@ fn chunked_bitset() { let mut b4096 = ChunkedBitSet::<usize>::new_empty(4096); assert_eq!( b4096, - ChunkedBitSet { - domain_size: 4096, - chunks: Box::new([Zeros(2048), Zeros(2048)]), - marker: PhantomData, - } + ChunkedBitSet { domain_size: 4096, chunks: Box::new([Zeros, Zeros]), marker: PhantomData } ); + assert_eq!(b4096.chunk_domain_size(0), 2048); + assert_eq!(b4096.chunk_domain_size(1), 2048); b4096.assert_valid(); for i in 0..4096 { @@ -231,11 +228,11 @@ fn chunked_bitset() { b4096.chunks(), #[rustfmt::skip] vec![ - Mixed(2048, 1, Rc::new([ + Mixed(1, Rc::new([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])), - Mixed(2048, 1, Rc::new([ + Mixed(1, Rc::new([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8000_0000_0000_0000 ])), @@ -251,10 +248,15 @@ fn chunked_bitset() { b10000, ChunkedBitSet { domain_size: 10000, - chunks: Box::new([Zeros(2048), Zeros(2048), Zeros(2048), Zeros(2048), Zeros(1808),]), + chunks: Box::new([Zeros, Zeros, Zeros, Zeros, Zeros,]), marker: PhantomData, } ); + assert_eq!(b10000.chunk_domain_size(0), 2048); + assert_eq!(b10000.chunk_domain_size(1), 2048); + assert_eq!(b10000.chunk_domain_size(2), 2048); + assert_eq!(b10000.chunk_domain_size(3), 2048); + assert_eq!(b10000.chunk_domain_size(4), 1808); b10000.assert_valid(); assert!(b10000.insert(3000) && b10000.insert(5000)); @@ -262,17 +264,17 @@ fn chunked_bitset() { b10000.chunks(), #[rustfmt::skip] vec![ - Zeros(2048), - Mixed(2048, 1, Rc::new([ + Zeros, + Mixed(1, Rc::new([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100_0000_0000_0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ])), - Mixed(2048, 1, Rc::new([ + Mixed(1, Rc::new([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ])), - Zeros(2048), - Zeros(1808), + Zeros, + Zeros, ], ); let mut b10000b = ChunkedBitSet::<usize>::new_empty(10000); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d1507f08c06..d105d24bed7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -989,6 +989,10 @@ impl<'tcx> InferCtxt<'tcx> { storage.var_infos.clone() } + pub fn has_opaque_types_in_storage(&self) -> bool { + !self.inner.borrow().opaque_type_storage.is_empty() + } + #[instrument(level = "debug", skip(self), ret)] pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> { self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index e699e4b9c13..cce40da354d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -488,6 +488,9 @@ extern "C" LLVMAttributeRef LLVMRustCreateRangeAttribute(LLVMContextRef C, unsigned NumBits, const uint64_t LowerWords[], const uint64_t UpperWords[]) { + // FIXME(Zalathar): There appears to be no stable guarantee that C++ + // `AttrKind` values correspond directly to the `unsigned KindID` values + // accepted by LLVM-C API functions, though in practice they currently do. return LLVMCreateConstantRangeAttribute(C, Attribute::Range, NumBits, LowerWords, UpperWords); } diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 78cafe8566b..866736f74a0 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use rustc_abi::Align; use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, Linkage, OptimizeAttr}; -use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; @@ -161,6 +160,8 @@ bitflags::bitflags! { const ALLOCATOR_ZEROED = 1 << 14; /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function. const NO_BUILTINS = 1 << 15; + /// Marks foreign items, to make `contains_extern_indicator` cheaper. + const FOREIGN_ITEM = 1 << 16; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } @@ -194,8 +195,8 @@ impl CodegenFnAttrs { /// * `#[linkage]` is present /// /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint. - pub fn contains_extern_indicator(&self, tcx: TyCtxt<'_>, did: DefId) -> bool { - if tcx.is_foreign_item(did) { + pub fn contains_extern_indicator(&self) -> bool { + if self.flags.contains(CodegenFnAttrFlags::FOREIGN_ITEM) { return false; } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 533066bdef9..6b45b2dc3ff 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -149,7 +149,7 @@ impl<'tcx> MonoItem<'tcx> { // instantiation: // We emit an unused_attributes lint for this case, which should be kept in sync if possible. let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def); - if codegen_fn_attrs.contains_extern_indicator(tcx, instance.def.def_id()) + if codegen_fn_attrs.contains_extern_indicator() || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return InstantiationMode::GloballyShared { may_conflict: false }; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7bd8a0525a2..8ce70f75c67 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -450,6 +450,8 @@ rustc_queries! { } } + /// A list of all bodies inside of `key`, nested bodies are always stored + /// before their parent. query nested_bodies_within( key: LocalDefId ) -> &'tcx ty::List<LocalDefId> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a7298af502e..e567ba05f61 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -829,14 +829,15 @@ impl<'tcx> OpaqueHiddenType<'tcx> { // Convert the type from the function into a type valid outside by mapping generic // parameters to into the context of the opaque. // - // We erase regions when doing this during HIR typeck. + // We erase regions when doing this during HIR typeck. We manually use `fold_regions` + // here as we do not want to anonymize bound variables. let this = match defining_scope_kind { - DefiningScopeKind::HirTypeck => tcx.erase_regions(self), + DefiningScopeKind::HirTypeck => fold_regions(tcx, self, |_, _| tcx.lifetimes.re_erased), DefiningScopeKind::MirBorrowck => self, }; let result = this.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span)); if cfg!(debug_assertions) && matches!(defining_scope_kind, DefiningScopeKind::HirTypeck) { - assert_eq!(result.ty, tcx.erase_regions(result.ty)); + assert_eq!(result.ty, fold_regions(tcx, result.ty, |_, _| tcx.lifetimes.re_erased)); } result } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 59e2b2a034d..4e38d969192 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -6,6 +6,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_macros::{Decodable, Encodable, HashStable}; +use rustc_span::symbol::sym; use tracing::debug; use crate::query::LocalCrate; @@ -239,6 +240,12 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait /// Query provider for `incoherent_impls`. pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { + if let Some(def_id) = simp.def() + && !tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) + { + return &[]; + } + let mut impls = Vec::new(); for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) { for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) { diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 03fdf9fbac5..b186c2bd775 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -18,7 +18,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); // If this has an extern indicator, then this function is globally shared and thus will not // generate cgu-internal copies which would make it cross-crate inlinable. - if codegen_fn_attrs.contains_extern_indicator(tcx, def_id.into()) { + if codegen_fn_attrs.contains_extern_indicator() { return false; } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 0230f784e46..4f87902e46e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -4,7 +4,6 @@ use std::ops::ControlFlow; #[cfg(feature = "nightly")] use rustc_macros::HashStable_NoContext; use rustc_type_ir::data_structures::{HashMap, HashSet}; -use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; @@ -1128,6 +1127,7 @@ where self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id) } + #[instrument(level = "debug", skip(self), ret)] pub(super) fn register_hidden_type_in_storage( &mut self, opaque_type_key: ty::OpaqueTypeKey<I>, @@ -1154,29 +1154,6 @@ where self.add_goals(GoalSource::AliasWellFormed, goals); } - // Do something for each opaque/hidden pair defined with `def_id` in the - // current inference context. - pub(super) fn probe_existing_opaque_ty( - &mut self, - key: ty::OpaqueTypeKey<I>, - ) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> { - // We shouldn't have any duplicate entries when using - // this function during `TypingMode::Analysis`. - let duplicate_entries = self.delegate.clone_duplicate_opaque_types(); - assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}"); - let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter( - |(candidate_key, _)| { - candidate_key.def_id == key.def_id - && DeepRejectCtxt::relate_rigid_rigid(self.cx()) - .args_may_unify(candidate_key.args, key.args) - }, - ); - let first = matching.next(); - let second = matching.next(); - assert_eq!(second, None); - first - } - // Try to evaluate a const, or return `None` if the const is too generic. // This doesn't mean the const isn't evaluatable, though, and should be treated // as an ambiguity rather than no-solution. diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index df3ad1e468b..a5f857a1dd8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -1,13 +1,12 @@ //! Computes a normalizes-to (projection) goal for opaque types. This goal //! behaves differently depending on the current `TypingMode`. -use rustc_index::bit_set::GrowableBitSet; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::GoalSource; use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions}; use crate::delegate::SolverDelegate; -use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect}; +use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; impl<D, I> EvalCtxt<'_, D> where @@ -39,100 +38,68 @@ where self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous)); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - TypingMode::Analysis { defining_opaque_types_and_generators } => { + TypingMode::Analysis { + defining_opaque_types_and_generators: defining_opaque_types, + } + | TypingMode::Borrowck { defining_opaque_types } => { let Some(def_id) = opaque_ty .def_id .as_local() - .filter(|&def_id| defining_opaque_types_and_generators.contains(&def_id)) + .filter(|&def_id| defining_opaque_types.contains(&def_id)) else { + // If we're not in the defining scope, treat the alias as rigid. self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); }; - // FIXME: This may have issues when the args contain aliases... - match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) { - Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { - return self.evaluate_added_goals_and_make_canonical_response( - Certainty::AMBIGUOUS, - ); - } - Err(_) => { - return Err(NoSolution); - } - Ok(()) => {} - } - // Prefer opaques registered already. - let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args }; - // FIXME: This also unifies the previous hidden type with the expected. + // We structurally normalize the args so that we're able to detect defining uses + // later on. // - // If that fails, we insert `expected` as a new hidden type instead of - // eagerly emitting an error. - let existing = self.probe_existing_opaque_ty(opaque_type_key); - if let Some((candidate_key, candidate_ty)) = existing { - return self - .probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup { - result: *result, - }) - .enter(|ecx| { - for (a, b) in std::iter::zip( - candidate_key.args.iter(), - opaque_type_key.args.iter(), - ) { - ecx.eq(goal.param_env, a, b)?; - } - ecx.eq(goal.param_env, candidate_ty, expected)?; - ecx.add_item_bounds_for_hidden_type( - def_id.into(), - candidate_key.args, - goal.param_env, - candidate_ty, - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }); - } + // This reduces the amount of duplicate definitions in the `opaque_type_storage` and + // strengthens inference. This causes us to subtly depend on the normalization behavior + // when inferring the hidden type of opaques. + // + // E.g. it's observable that we don't normalize nested aliases with bound vars in + // `structurally_normalize` and because we use structural lookup, we also don't + // reuse an entry for `Tait<for<'a> fn(&'a ())>` for `Tait<for<'b> fn(&'b ())>`. + let normalized_args = + cx.mk_args_from_iter(opaque_ty.args.iter().map(|arg| match arg.kind() { + ty::GenericArgKind::Lifetime(lt) => Ok(lt.into()), + ty::GenericArgKind::Type(ty) => { + self.structurally_normalize_ty(goal.param_env, ty).map(Into::into) + } + ty::GenericArgKind::Const(ct) => { + self.structurally_normalize_const(goal.param_env, ct).map(Into::into) + } + }))?; - // Otherwise, define a new opaque type - let prev = self.register_hidden_type_in_storage(opaque_type_key, expected); - assert_eq!(prev, None); - self.add_item_bounds_for_hidden_type( - def_id.into(), - opaque_ty.args, - goal.param_env, - expected, - ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // Very similar to `TypingMode::Analysis` with some notably differences: - // - we accept opaque types even if they have non-universal arguments - // - we do a structural lookup instead of semantically unifying regions - // - the hidden type starts out as the type from HIR typeck with fresh region - // variables instead of a fully unconstrained inference variable - TypingMode::Borrowck { defining_opaque_types } => { - let Some(def_id) = opaque_ty - .def_id - .as_local() - .filter(|&def_id| defining_opaque_types.contains(&def_id)) - else { - self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); - return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - }; + let opaque_type_key = ty::OpaqueTypeKey { def_id, args: normalized_args }; + if let Some(prev) = self.register_hidden_type_in_storage(opaque_type_key, expected) + { + self.eq(goal.param_env, expected, prev)?; + } else { + // During HIR typeck, opaque types start out as unconstrained + // inference variables. In borrowck we instead use the type + // computed in HIR typeck as the initial value. + match self.typing_mode() { + TypingMode::Analysis { .. } => {} + TypingMode::Borrowck { .. } => { + let actual = cx + .type_of_opaque_hir_typeck(def_id) + .instantiate(cx, opaque_ty.args); + let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() { + ty::ReErased => self.next_region_var(), + _ => re, + }); + self.eq(goal.param_env, expected, actual)?; + } + _ => unreachable!(), + } + } - let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args }; - let actual = self - .register_hidden_type_in_storage(opaque_type_key, expected) - .unwrap_or_else(|| { - let actual = - cx.type_of_opaque_hir_typeck(def_id).instantiate(cx, opaque_ty.args); - let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() { - ty::ReErased => self.next_region_var(), - _ => re, - }); - actual - }); - self.eq(goal.param_env, expected, actual)?; self.add_item_bounds_for_hidden_type( def_id.into(), - opaque_ty.args, + normalized_args, goal.param_env, expected, ); @@ -168,44 +135,3 @@ where } } } - -/// Checks whether each generic argument is simply a unique generic placeholder. -/// -/// FIXME: Interner argument is needed to constrain the `I` parameter. -fn uses_unique_placeholders_ignoring_regions<I: Interner>( - _cx: I, - args: I::GenericArgs, -) -> Result<(), NotUniqueParam<I>> { - let mut seen = GrowableBitSet::default(); - for arg in args.iter() { - match arg.kind() { - // Ignore regions, since we can't resolve those in a canonicalized - // query in the trait solver. - ty::GenericArgKind::Lifetime(_) => {} - ty::GenericArgKind::Type(t) => match t.kind() { - ty::Placeholder(p) => { - if !seen.insert(p.var()) { - return Err(NotUniqueParam::DuplicateParam(t.into())); - } - } - _ => return Err(NotUniqueParam::NotParam(t.into())), - }, - ty::GenericArgKind::Const(c) => match c.kind() { - ty::ConstKind::Placeholder(p) => { - if !seen.insert(p.var()) { - return Err(NotUniqueParam::DuplicateParam(c.into())); - } - } - _ => return Err(NotUniqueParam::NotParam(c.into())), - }, - } - } - - Ok(()) -} - -// FIXME: This should check for dupes and non-params first, then infer vars. -enum NotUniqueParam<I: Interner> { - DuplicateParam(I::GenericArg), - NotParam(I::GenericArg), -} diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 220e4ac18fc..a28af7833c3 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -463,8 +463,8 @@ impl<'a> Parser<'a> { pub(super) fn expected_one_of_not_found( &mut self, - edible: &[ExpTokenPair<'_>], - inedible: &[ExpTokenPair<'_>], + edible: &[ExpTokenPair], + inedible: &[ExpTokenPair], ) -> PResult<'a, ErrorGuaranteed> { debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible); fn tokens_to_string(tokens: &[TokenType]) -> String { @@ -1092,7 +1092,7 @@ impl<'a> Parser<'a> { /// Eats and discards tokens until one of `closes` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. - pub(super) fn eat_to_tokens(&mut self, closes: &[ExpTokenPair<'_>]) { + pub(super) fn eat_to_tokens(&mut self, closes: &[ExpTokenPair]) { if let Err(err) = self .parse_seq_to_before_tokens(closes, &[], SeqSep::none(), |p| Ok(p.parse_token_tree())) { @@ -1113,7 +1113,7 @@ impl<'a> Parser<'a> { pub(super) fn check_trailing_angle_brackets( &mut self, segment: &PathSegment, - end: &[ExpTokenPair<'_>], + end: &[ExpTokenPair], ) -> Option<ErrorGuaranteed> { if !self.may_recover() { return None; @@ -1196,7 +1196,7 @@ impl<'a> Parser<'a> { // second case. if self.look_ahead(position, |t| { trace!("check_trailing_angle_brackets: t={:?}", t); - end.iter().any(|exp| exp.tok == &t.kind) + end.iter().any(|exp| exp.tok == t.kind) }) { // Eat from where we started until the end token so that parsing can continue // as if we didn't have those extra angle brackets. @@ -2120,8 +2120,8 @@ impl<'a> Parser<'a> { pub(super) fn recover_seq_parse_error( &mut self, - open: ExpTokenPair<'_>, - close: ExpTokenPair<'_>, + open: ExpTokenPair, + close: ExpTokenPair, lo: Span, err: Diag<'a>, ) -> Box<Expr> { @@ -2386,8 +2386,8 @@ impl<'a> Parser<'a> { pub(super) fn consume_block( &mut self, - open: ExpTokenPair<'_>, - close: ExpTokenPair<'_>, + open: ExpTokenPair, + close: ExpTokenPair, consume_close: ConsumeClosingDelim, ) { let mut brace_depth = 0; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1499808966c..f0f58e901a9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1598,7 +1598,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } - fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair<'_>) -> PResult<'a, Box<Expr>> { + fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> { let lo = self.token.span; self.bump(); // `[` or other open delim @@ -3661,7 +3661,7 @@ impl<'a> Parser<'a> { &mut self, pth: ast::Path, recover: bool, - close: ExpTokenPair<'_>, + close: ExpTokenPair, ) -> PResult< 'a, ( @@ -3680,8 +3680,8 @@ impl<'a> Parser<'a> { errors::HelpUseLatestEdition::new().add_to_diag(e); }; - while self.token != *close.tok { - if self.eat(exp!(DotDot)) || self.recover_struct_field_dots(close.tok) { + while self.token != close.tok { + if self.eat(exp!(DotDot)) || self.recover_struct_field_dots(&close.tok) { let exp_span = self.prev_token.span; // We permit `.. }` on the left-hand side of a destructuring assignment. if self.check(close) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index fd9fb65417c..eb264f59fed 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -54,7 +54,7 @@ impl<'a> Parser<'a> { /// - `}` for mod items pub fn parse_mod( &mut self, - term: ExpTokenPair<'_>, + term: ExpTokenPair, ) -> PResult<'a, (AttrVec, ThinVec<Box<Item>>, ModSpans)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; @@ -1201,7 +1201,7 @@ impl<'a> Parser<'a> { }?; let dash = exp!(Minus); - if self.token != *dash.tok { + if self.token != dash.tok { return Ok(ident); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d19114df812..15598f32429 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -261,19 +261,19 @@ struct CaptureState { /// A sequence separator. #[derive(Debug)] -struct SeqSep<'a> { +struct SeqSep { /// The separator token. - sep: Option<ExpTokenPair<'a>>, + sep: Option<ExpTokenPair>, /// `true` if a trailing separator is allowed. trailing_sep_allowed: bool, } -impl<'a> SeqSep<'a> { - fn trailing_allowed(sep: ExpTokenPair<'a>) -> SeqSep<'a> { +impl SeqSep { + fn trailing_allowed(sep: ExpTokenPair) -> SeqSep { SeqSep { sep: Some(sep), trailing_sep_allowed: true } } - fn none() -> SeqSep<'a> { + fn none() -> SeqSep { SeqSep { sep: None, trailing_sep_allowed: false } } } @@ -425,13 +425,13 @@ impl<'a> Parser<'a> { } /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. - pub fn expect(&mut self, exp: ExpTokenPair<'_>) -> PResult<'a, Recovered> { + pub fn expect(&mut self, exp: ExpTokenPair) -> PResult<'a, Recovered> { if self.expected_token_types.is_empty() { - if self.token == *exp.tok { + if self.token == exp.tok { self.bump(); Ok(Recovered::No) } else { - self.unexpected_try_recover(exp.tok) + self.unexpected_try_recover(&exp.tok) } } else { self.expect_one_of(slice::from_ref(&exp), &[]) @@ -443,13 +443,13 @@ impl<'a> Parser<'a> { /// anything. Signal a fatal error if next token is unexpected. fn expect_one_of( &mut self, - edible: &[ExpTokenPair<'_>], - inedible: &[ExpTokenPair<'_>], + edible: &[ExpTokenPair], + inedible: &[ExpTokenPair], ) -> PResult<'a, Recovered> { - if edible.iter().any(|exp| exp.tok == &self.token.kind) { + if edible.iter().any(|exp| exp.tok == self.token.kind) { self.bump(); Ok(Recovered::No) - } else if inedible.iter().any(|exp| exp.tok == &self.token.kind) { + } else if inedible.iter().any(|exp| exp.tok == self.token.kind) { // leave it in the input Ok(Recovered::No) } else if self.token != token::Eof @@ -494,8 +494,8 @@ impl<'a> Parser<'a> { /// This method will automatically add `tok` to `expected_token_types` if `tok` is not /// encountered. #[inline] - pub fn check(&mut self, exp: ExpTokenPair<'_>) -> bool { - let is_present = self.token == *exp.tok; + pub fn check(&mut self, exp: ExpTokenPair) -> bool { + let is_present = self.token == exp.tok; if !is_present { self.expected_token_types.insert(exp.token_type); } @@ -542,7 +542,7 @@ impl<'a> Parser<'a> { /// Consumes a token 'tok' if it exists. Returns whether the given token was present. #[inline] #[must_use] - pub fn eat(&mut self, exp: ExpTokenPair<'_>) -> bool { + pub fn eat(&mut self, exp: ExpTokenPair) -> bool { let is_present = self.check(exp); if is_present { self.bump() @@ -745,13 +745,13 @@ impl<'a> Parser<'a> { /// Eats the expected token if it's present possibly breaking /// compound tokens like multi-character operators in process. /// Returns `true` if the token was eaten. - fn break_and_eat(&mut self, exp: ExpTokenPair<'_>) -> bool { - if self.token == *exp.tok { + fn break_and_eat(&mut self, exp: ExpTokenPair) -> bool { + if self.token == exp.tok { self.bump(); return true; } match self.token.kind.break_two_token_op(1) { - Some((first, second)) if first == *exp.tok => { + Some((first, second)) if first == exp.tok => { let first_span = self.psess.source_map().start_point(self.token.span); let second_span = self.token.span.with_lo(first_span.hi()); self.token = Token::new(first, first_span); @@ -826,7 +826,7 @@ impl<'a> Parser<'a> { /// Checks if the next token is contained within `closes`, and returns `true` if so. fn expect_any_with_type( &mut self, - closes_expected: &[ExpTokenPair<'_>], + closes_expected: &[ExpTokenPair], closes_not_expected: &[&TokenKind], ) -> bool { closes_expected.iter().any(|&close| self.check(close)) @@ -838,9 +838,9 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_seq_to_before_tokens<T>( &mut self, - closes_expected: &[ExpTokenPair<'_>], + closes_expected: &[ExpTokenPair], closes_not_expected: &[&TokenKind], - sep: SeqSep<'_>, + sep: SeqSep, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> { let mut first = true; @@ -869,7 +869,7 @@ impl<'a> Parser<'a> { } Err(mut expect_err) => { let sp = self.prev_token.span.shrink_to_hi(); - let token_str = pprust::token_kind_to_string(exp.tok); + let token_str = pprust::token_kind_to_string(&exp.tok); match self.current_closure.take() { Some(closure_spans) if self.token == TokenKind::Semi => { @@ -1039,8 +1039,8 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_seq_to_before_end<T>( &mut self, - close: ExpTokenPair<'_>, - sep: SeqSep<'_>, + close: ExpTokenPair, + sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> { self.parse_seq_to_before_tokens(&[close], &[], sep, f) @@ -1051,8 +1051,8 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_seq_to_end<T>( &mut self, - close: ExpTokenPair<'_>, - sep: SeqSep<'_>, + close: ExpTokenPair, + sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing)> { let (val, trailing, recovered) = self.parse_seq_to_before_end(close, sep, f)?; @@ -1070,9 +1070,9 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_unspanned_seq<T>( &mut self, - open: ExpTokenPair<'_>, - close: ExpTokenPair<'_>, - sep: SeqSep<'_>, + open: ExpTokenPair, + close: ExpTokenPair, + sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing)> { self.expect(open)?; @@ -1084,8 +1084,8 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_delim_comma_seq<T>( &mut self, - open: ExpTokenPair<'_>, - close: ExpTokenPair<'_>, + open: ExpTokenPair, + close: ExpTokenPair, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing)> { self.parse_unspanned_seq(open, close, SeqSep::trailing_allowed(exp!(Comma)), f) diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index b91548196a3..bd4bb368df0 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -416,8 +416,8 @@ impl TokenType { /// is always by used those methods. The second field is only used when the /// first field doesn't match. #[derive(Clone, Copy, Debug)] -pub struct ExpTokenPair<'a> { - pub tok: &'a TokenKind, +pub struct ExpTokenPair { + pub tok: TokenKind, pub token_type: TokenType, } @@ -444,7 +444,7 @@ macro_rules! exp { // `ExpTokenPair` helper rules. (@tok, $tok:ident) => { $crate::parser::token_type::ExpTokenPair { - tok: &rustc_ast::token::$tok, + tok: rustc_ast::token::$tok, token_type: $crate::parser::token_type::TokenType::$tok } }; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 00a41e31a02..3be06a3704c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -462,8 +462,10 @@ passes_object_lifetime_err = {$repr} passes_outer_crate_level_attr = - crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + crate-level attribute should be an inner attribute +passes_outer_crate_level_attr_suggestion = + add a `!` passes_panic_unwind_without_std = unwinding panics are not supported without std diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7aef60b7b91..3a79176f914 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -369,24 +369,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if hir_id != CRATE_HIR_ID { match attr { - // FIXME(jdonszelmann) move to attribute parsing when validation gets better there - &Attribute::Parsed(AttributeKind::CrateName { - attr_span: span, style, .. - }) => match style { - ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - span, - errors::OuterCrateLevelAttr, - ), - ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - span, - errors::InnerCrateLevelAttr, - ), - }, - Attribute::Parsed(_) => { /* not crate-level */ } + Attribute::Parsed(_) => { /* Already validated. */ } Attribute::Unparsed(attr) => { // FIXME(jdonszelmann): remove once all crate-level attrs are parsed and caught by // the above @@ -397,12 +380,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { match attr.style { - ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::OuterCrateLevelAttr, - ), + ast::AttrStyle::Outer => { + let attr_span = attr.span; + let bang_position = self + .tcx + .sess + .source_map() + .span_until_char(attr_span, '[') + .shrink_to_hi(); + + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::OuterCrateLevelAttr { + suggestion: errors::OuterCrateLevelAttrSuggestion { + bang_position, + }, + }, + ) + } ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, @@ -495,7 +492,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { { let attrs = self.tcx.codegen_fn_attrs(did); // Not checking naked as `#[inline]` is forbidden for naked functions anyways. - if attrs.contains_extern_indicator(self.tcx, did.into()) { + if attrs.contains_extern_indicator() { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, @@ -1851,12 +1848,24 @@ impl<'tcx> CheckAttrVisitor<'tcx> { { if hir_id != CRATE_HIR_ID { match style { - Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::OuterCrateLevelAttr, - ), + Some(ast::AttrStyle::Outer) => { + let attr_span = attr.span(); + let bang_position = self + .tcx + .sess + .source_map() + .span_until_char(attr_span, '[') + .shrink_to_hi(); + + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::OuterCrateLevelAttr { + suggestion: errors::OuterCrateLevelAttrSuggestion { bang_position }, + }, + ) + } Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 10cd9df4816..fc33405d455 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -706,7 +706,7 @@ fn has_allow_dead_code_or_lang_attr( // #[used], #[no_mangle], #[export_name], etc also keeps the item alive // forcefully, e.g., for placing it in a specific section. - cg_attrs.contains_extern_indicator(tcx, def_id.into()) + cg_attrs.contains_extern_indicator() || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4fec6b0798a..01972067978 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -64,7 +64,17 @@ pub(crate) struct MixedExportNameAndNoMangle { #[derive(LintDiagnostic)] #[diag(passes_outer_crate_level_attr)] -pub(crate) struct OuterCrateLevelAttr; +pub(crate) struct OuterCrateLevelAttr { + #[subdiagnostic] + pub suggestion: OuterCrateLevelAttrSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(passes_outer_crate_level_attr_suggestion, style = "verbose")] +pub(crate) struct OuterCrateLevelAttrSuggestion { + #[suggestion_part(code = "!")] + pub bang_position: Span, +} #[derive(LintDiagnostic)] #[diag(passes_inner_crate_level_attr)] diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 6cd8a54ecf4..d1a703fc5d8 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -183,7 +183,7 @@ impl<'tcx> ReachableContext<'tcx> { } else { CodegenFnAttrs::EMPTY }; - let is_extern = codegen_attrs.contains_extern_indicator(self.tcx, search_item.into()); + let is_extern = codegen_attrs.contains_extern_indicator(); if is_extern { self.reachable_symbols.insert(search_item); } @@ -425,7 +425,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { } let codegen_attrs = tcx.codegen_fn_attrs(def_id); - codegen_attrs.contains_extern_indicator(tcx, def_id.into()) + codegen_attrs.contains_extern_indicator() // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 8270de1e917..166842e374b 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -9,6 +9,7 @@ //! within the `SourceMap`, which upon request can be converted to line and column //! information, source code snippets, etc. +use std::fs::File; use std::io::{self, BorrowedBuf, Read}; use std::{fs, path}; @@ -115,13 +116,18 @@ impl FileLoader for RealFileLoader { } fn read_file(&self, path: &Path) -> io::Result<String> { - if path.metadata().is_ok_and(|metadata| metadata.len() > SourceFile::MAX_FILE_SIZE.into()) { + let mut file = File::open(path)?; + let size = file.metadata().map(|metadata| metadata.len()).ok().unwrap_or(0); + + if size > SourceFile::MAX_FILE_SIZE.into() { return Err(io::Error::other(format!( "text files larger than {} bytes are unsupported", SourceFile::MAX_FILE_SIZE ))); } - fs::read_to_string(path) + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + Ok(contents) } fn read_binary_file(&self, path: &Path) -> io::Result<Arc<[u8]>> { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5d140cc6117..585968044bf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2419,9 +2419,11 @@ symbols! { yield_expr, ymm_reg, yreg, + zca, zfh, zfhmin, zmm_reg, + ztso, // tidy-alphabetical-end } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a67795e3e93..c53d92bee9d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1954,6 +1954,7 @@ supported_targets! { ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), ("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl), + ("aarch64_be-unknown-linux-musl", aarch64_be_unknown_linux_musl), ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), ("i686-unknown-linux-musl", i686_unknown_linux_musl), ("i586-unknown-linux-musl", i586_unknown_linux_musl), @@ -2149,6 +2150,7 @@ supported_targets! { ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu), ("riscv64gc-unknown-linux-musl", riscv64gc_unknown_linux_musl), + ("riscv64a23-unknown-linux-gnu", riscv64a23_unknown_linux_gnu), ("sparc-unknown-none-elf", sparc_unknown_none_elf), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_musl.rs new file mode 100644 index 00000000000..be5ac4a843b --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_musl.rs @@ -0,0 +1,40 @@ +use rustc_abi::Endian; + +use crate::spec::{ + FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base, +}; + +pub(crate) fn target() -> Target { + let mut base = base::linux_musl::opts(); + base.max_atomic_width = Some(128); + base.supports_xray = true; + base.features = "+v8a,+outline-atomics".into(); + base.stack_probes = StackProbeType::Inline; + base.supported_sanitizers = SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::LEAK + | SanitizerSet::MEMORY + | SanitizerSet::THREAD; + + Target { + llvm_target: "aarch64_be-unknown-linux-musl".into(), + metadata: TargetMetadata { + description: Some("ARM64 Linux (big-endian) with musl-libc 1.2.5".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 64, + data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + arch: "aarch64".into(), + options: TargetOptions { + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, + mcount: "\u{1}_mcount".into(), + endian: Endian::Big, + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs new file mode 100644 index 00000000000..60f2e7da042 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs @@ -0,0 +1,27 @@ +use std::borrow::Cow; + +use crate::spec::{CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "riscv64-unknown-linux-gnu".into(), + metadata: TargetMetadata { + description: Some("RISC-V Linux (kernel 6.8.0, glibc 2.39)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), + }, + pointer_width: 64, + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), + arch: "riscv64".into(), + options: TargetOptions { + code_model: Some(CodeModel::Medium), + cpu: "generic-rv64".into(), + features: "+rva23u64".into(), + llvm_abiname: "lp64d".into(), + max_atomic_width: Some(64), + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + ..base::linux_gnu::opts() + }, + } +} diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index e45300b59cc..4c1b8c99426 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -601,6 +601,49 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ), ("m", Stable, &[]), ("relax", Unstable(sym::riscv_target_feature), &[]), + ( + "rva23u64", + Unstable(sym::riscv_target_feature), + &[ + "m", + "a", + "f", + "d", + "c", + "b", + "v", + "zicsr", + "zicntr", + "zihpm", + "ziccif", + "ziccrse", + "ziccamoa", + "zicclsm", + "zic64b", + "za64rs", + "zihintpause", + "zba", + "zbb", + "zbs", + "zicbom", + "zicbop", + "zicboz", + "zfhmin", + "zkt", + "zvfhmin", + "zvbb", + "zvkt", + "zihintntl", + "zicond", + "zimop", + "zcmop", + "zcb", + "zfa", + "zawrs", + "supm", + ], + ), + ("supm", Unstable(sym::riscv_target_feature), &[]), ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), diff --git a/compiler/rustc_thread_pool/src/lib.rs b/compiler/rustc_thread_pool/src/lib.rs index 34252d919e3..7ce7fbc27ea 100644 --- a/compiler/rustc_thread_pool/src/lib.rs +++ b/compiler/rustc_thread_pool/src/lib.rs @@ -787,18 +787,7 @@ impl ThreadPoolBuildError { } } -const GLOBAL_POOL_ALREADY_INITIALIZED: &str = - "The global thread pool has already been initialized."; - impl Error for ThreadPoolBuildError { - #[allow(deprecated)] - fn description(&self) -> &str { - match self.kind { - ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED, - ErrorKind::IOError(ref e) => e.description(), - } - } - fn source(&self) -> Option<&(dyn Error + 'static)> { match &self.kind { ErrorKind::GlobalPoolAlreadyInitialized => None, @@ -810,7 +799,9 @@ impl Error for ThreadPoolBuildError { impl fmt::Display for ThreadPoolBuildError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.kind { - ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED.fmt(f), + ErrorKind::GlobalPoolAlreadyInitialized => { + "The global thread pool has already been initialized.".fmt(f) + } ErrorKind::IOError(e) => e.fmt(f), } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index e31ff8b8729..aa153d3607b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -820,16 +820,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. }) && obligation.cause.span.can_be_used_for_suggestions() { + let (span, sugg) = if let Some(snippet) = + self.tcx.sess.source_map().span_to_snippet(obligation.cause.span).ok() + && snippet.starts_with("|") + { + (obligation.cause.span, format!("({snippet})({args})")) + } else { + (obligation.cause.span.shrink_to_hi(), format!("({args})")) + }; + // When the obligation error has been ensured to have been caused by // an argument, the `obligation.cause.span` points at the expression // of the argument, so we can provide a suggestion. Otherwise, we give // a more general note. - err.span_suggestion_verbose( - obligation.cause.span.shrink_to_hi(), - msg, - format!("({args})"), - Applicability::HasPlaceholders, - ); + err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders); } else if let DefIdOrName::DefId(def_id) = def_id_or_name { let name = match self.tcx.hir_get_if_local(def_id) { Some(hir::Node::Expr(hir::Expr { diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 70a08f34f33..bc7bdd372ba 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -4,8 +4,8 @@ use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::ty::{ - self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, TyCtxt, TypeVisitableExt, - TypingMode, fold_regions, + self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, Ty, TyCtxt, + TypeVisitableExt, TypingMode, fold_regions, }; use rustc_span::{ErrorGuaranteed, Span}; @@ -14,22 +14,22 @@ use crate::regions::OutlivesEnvironmentBuildExt; use crate::traits::ObligationCtxt; #[derive(Debug)] -pub enum InvalidOpaqueTypeArgs<'tcx> { - AlreadyReported(ErrorGuaranteed), +pub enum NonDefiningUseReason<'tcx> { + Tainted(ErrorGuaranteed), NotAParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_index: usize, span: Span }, DuplicateParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_indices: Vec<usize>, span: Span }, } -impl From<ErrorGuaranteed> for InvalidOpaqueTypeArgs<'_> { +impl From<ErrorGuaranteed> for NonDefiningUseReason<'_> { fn from(guar: ErrorGuaranteed) -> Self { - InvalidOpaqueTypeArgs::AlreadyReported(guar) + NonDefiningUseReason::Tainted(guar) } } -impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { +impl<'tcx> NonDefiningUseReason<'tcx> { pub fn report(self, infcx: &InferCtxt<'tcx>) -> ErrorGuaranteed { let tcx = infcx.tcx; match self { - InvalidOpaqueTypeArgs::AlreadyReported(guar) => guar, - InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index, span } => { + NonDefiningUseReason::Tainted(guar) => guar, + NonDefiningUseReason::NotAParam { opaque_type_key, param_index, span } => { let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_param = opaque_generics.param_at(param_index, tcx); let kind = opaque_param.kind.descr(); @@ -40,7 +40,7 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { param_span: tcx.def_span(opaque_param.def_id), }) } - InvalidOpaqueTypeArgs::DuplicateParam { opaque_type_key, param_indices, span } => { + NonDefiningUseReason::DuplicateParam { opaque_type_key, param_indices, span } => { let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let descr = opaque_generics.param_at(param_indices[0], tcx).kind.descr(); let spans: Vec<_> = param_indices @@ -58,15 +58,17 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { } /// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter]. +/// With the new solver, uses which fail this check are simply treated as non-defining +/// and we only emit an error if no defining use exists. /// /// [rustc-dev-guide chapter]: /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html -pub fn check_opaque_type_parameter_valid<'tcx>( +pub fn opaque_type_has_defining_use_args<'tcx>( infcx: &InferCtxt<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, defining_scope_kind: DefiningScopeKind, -) -> Result<(), InvalidOpaqueTypeArgs<'tcx>> { +) -> Result<(), NonDefiningUseReason<'tcx>> { let tcx = infcx.tcx; let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); @@ -105,13 +107,13 @@ pub fn check_opaque_type_parameter_valid<'tcx>( } else { // Prevent `fn foo() -> Foo<u32>` from being defining. opaque_env.param_is_error(i)?; - return Err(InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index: i, span }); + return Err(NonDefiningUseReason::NotAParam { opaque_type_key, param_index: i, span }); } } for (_, param_indices) in seen_params { if param_indices.len() > 1 { - return Err(InvalidOpaqueTypeArgs::DuplicateParam { + return Err(NonDefiningUseReason::DuplicateParam { opaque_type_key, param_indices, span, @@ -206,3 +208,27 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { canonical_args } } + +pub fn report_item_does_not_constrain_error<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: LocalDefId, + def_id: LocalDefId, + non_defining_use: Option<(OpaqueTypeKey<'tcx>, Span)>, +) -> ErrorGuaranteed { + let span = tcx.def_ident_span(item_def_id).unwrap_or_else(|| tcx.def_span(item_def_id)); + let opaque_type_span = tcx.def_span(def_id); + let opaque_type_name = tcx.def_path_str(def_id); + + let mut err = + tcx.dcx().struct_span_err(span, format!("item does not constrain `{opaque_type_name}`")); + err.note("consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`"); + err.span_note(opaque_type_span, "this opaque type is supposed to be constrained"); + if let Some((key, span)) = non_defining_use { + let opaque_ty = Ty::new_opaque(tcx, key.def_id.into(), key.args); + err.span_note( + span, + format!("this use of `{opaque_ty}` does not have unique universal generic arguments"), + ); + } + err.emit() +} diff --git a/compiler/rustc_ty_utils/src/nested_bodies.rs b/compiler/rustc_ty_utils/src/nested_bodies.rs index 7c74d8eb635..11dfbad7dbb 100644 --- a/compiler/rustc_ty_utils/src/nested_bodies.rs +++ b/compiler/rustc_ty_utils/src/nested_bodies.rs @@ -22,9 +22,11 @@ impl<'tcx> Visitor<'tcx> for NestedBodiesVisitor<'tcx> { fn visit_nested_body(&mut self, id: hir::BodyId) { let body_def_id = self.tcx.hir_body_owner_def_id(id); if self.tcx.typeck_root_def_id(body_def_id.to_def_id()) == self.root_def_id { - self.nested_bodies.push(body_def_id); + // We visit nested bodies before adding the current body. This + // means that nested bodies are always stored before their parent. let body = self.tcx.hir_body(id); self.visit_body(body); + self.nested_bodies.push(body_def_id); } } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index fa12d379c8c..98c9f6b51ab 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2128,11 +2128,6 @@ impl<F: ?Sized + Future + Unpin, A: Allocator> Future for Box<F, A> { #[stable(feature = "box_error", since = "1.8.0")] impl<E: Error> Error for Box<E> { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - Error::description(&**self) - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs index 80626580202..45c46fb5263 100644 --- a/library/alloc/src/boxed/convert.rs +++ b/library/alloc/src/boxed/convert.rs @@ -608,12 +608,7 @@ impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> { fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> { struct StringError(String); - impl Error for StringError { - #[allow(deprecated)] - fn description(&self) -> &str { - &self.0 - } - } + impl Error for StringError {} impl fmt::Display for StringError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index c4e599222e5..8b6d86a2888 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -40,30 +40,15 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// An ordered map based on a [B-Tree]. /// -/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing -/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal -/// choice for a sorted map, as a perfectly balanced BST performs the theoretical minimum amount of -/// comparisons necessary to find an element (log<sub>2</sub>n). However, in practice the way this -/// is done is *very* inefficient for modern computer architectures. In particular, every element -/// is stored in its own individually heap-allocated node. This means that every single insertion -/// triggers a heap-allocation, and every single comparison should be a cache-miss. Since these -/// are both notably expensive things to do in practice, we are forced to, at the very least, -/// reconsider the BST strategy. -/// -/// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing -/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in -/// searches. However, this does mean that searches will have to do *more* comparisons on average. -/// The precise number of comparisons depends on the node search strategy used. For optimal cache -/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search -/// the node using binary search. As a compromise, one could also perform a linear search -/// that initially only checks every i<sup>th</sup> element for some choice of i. +/// Given a key type with a [total order], an ordered map stores its entries in key order. +/// That means that keys must be of a type that implements the [`Ord`] trait, +/// such that two keys can always be compared to determine their [`Ordering`]. +/// Examples of keys with a total order are strings with lexicographical order, +/// and numbers with their natural order. /// -/// Currently, our implementation simply performs naive linear search. This provides excellent -/// performance on *small* nodes of elements which are cheap to compare. However in the future we -/// would like to further explore choosing the optimal search strategy based on the choice of B, -/// and possibly other factors. Using linear search, searching for a random element is expected -/// to take B * log(n) comparisons, which is generally worse than a BST. In practice, -/// however, performance is excellent. +/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::into_iter`], [`BTreeMap::values`], or +/// [`BTreeMap::keys`] produce their items in key order, and take worst-case logarithmic and +/// amortized constant time per item returned. /// /// It is a logic error for a key to be modified in such a way that the key's ordering relative to /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is @@ -72,14 +57,6 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// `BTreeMap` that observed the logic error and not result in undefined behavior. This could /// include panics, incorrect results, aborts, memory leaks, and non-termination. /// -/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::into_iter`], [`BTreeMap::values`], or -/// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and -/// amortized constant time per item returned. -/// -/// [B-Tree]: https://en.wikipedia.org/wiki/B-tree -/// [`Cell`]: core::cell::Cell -/// [`RefCell`]: core::cell::RefCell -/// /// # Examples /// /// ``` @@ -169,6 +146,43 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// // modify an entry before an insert with in-place mutation /// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); /// ``` +/// +/// # Background +/// +/// A B-tree is (like) a [binary search tree], but adapted to the natural granularity that modern +/// machines like to consume data at. This means that each node contains an entire array of elements, +/// instead of just a single element. +/// +/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing +/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal +/// choice for a sorted map, as a perfectly balanced BST performs the theoretical minimum number of +/// comparisons necessary to find an element (log<sub>2</sub>n). However, in practice the way this +/// is done is *very* inefficient for modern computer architectures. In particular, every element +/// is stored in its own individually heap-allocated node. This means that every single insertion +/// triggers a heap-allocation, and every comparison is a potential cache-miss due to the indirection. +/// Since both heap-allocations and cache-misses are notably expensive in practice, we are forced to, +/// at the very least, reconsider the BST strategy. +/// +/// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing +/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in +/// searches. However, this does mean that searches will have to do *more* comparisons on average. +/// The precise number of comparisons depends on the node search strategy used. For optimal cache +/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search +/// the node using binary search. As a compromise, one could also perform a linear search +/// that initially only checks every i<sup>th</sup> element for some choice of i. +/// +/// Currently, our implementation simply performs naive linear search. This provides excellent +/// performance on *small* nodes of elements which are cheap to compare. However in the future we +/// would like to further explore choosing the optimal search strategy based on the choice of B, +/// and possibly other factors. Using linear search, searching for a random element is expected +/// to take B * log(n) comparisons, which is generally worse than a BST. In practice, +/// however, performance is excellent. +/// +/// [B-Tree]: https://en.wikipedia.org/wiki/B-tree +/// [binary search tree]: https://en.wikipedia.org/wiki/Binary_search_tree +/// [total order]: https://en.wikipedia.org/wiki/Total_order +/// [`Cell`]: core::cell::Cell +/// [`RefCell`]: core::cell::RefCell #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] #[rustc_insignificant_dtor] diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index ea8fa363c38..ec9b774c308 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -136,10 +136,6 @@ impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error for crate::collections::btree_map::OccupiedError<'a, K, V> { - #[allow(deprecated)] - fn description(&self) -> &str { - "key already exists" - } } impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index fe6c89a3094..b0c8c4b1ca4 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1061,17 +1061,10 @@ impl IntoStringError { } } -impl IntoStringError { - fn description(&self) -> &str { - "C string contained non-utf8 bytes" - } -} - #[stable(feature = "cstring_into", since = "1.7.0")] impl fmt::Display for IntoStringError { - #[allow(deprecated, deprecated_in_future)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.description().fmt(f) + "C string contained non-utf8 bytes".fmt(f) } } @@ -1291,23 +1284,13 @@ impl PartialEq<CString> for Cow<'_, CStr> { } #[stable(feature = "rust1", since = "1.0.0")] -impl core::error::Error for NulError { - #[allow(deprecated)] - fn description(&self) -> &str { - "nul byte found in data" - } -} +impl core::error::Error for NulError {} #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl core::error::Error for FromVecWithNulError {} #[stable(feature = "cstring_into", since = "1.7.0")] impl core::error::Error for IntoStringError { - #[allow(deprecated)] - fn description(&self) -> &str { - "C string contained non-utf8 bytes" - } - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { Some(&self.error) } diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 40716755aad..fd05f9ca464 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -155,7 +155,7 @@ impl RawVecInner<Global> { } // Tiny Vecs are dumb. Skip to: -// - 8 if the element size is 1, because any heap allocators is likely +// - 8 if the element size is 1, because any heap allocator is likely // to round up a request of less than 8 bytes to at least 8 bytes. // - 4 if elements are moderate-sized (<= 1 KiB). // - 1 otherwise, to avoid wasting too much space for very short Vecs. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9eacbf00e42..11fd4346ff5 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2285,20 +2285,10 @@ impl fmt::Display for FromUtf16Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf8Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "invalid utf-8" - } -} +impl Error for FromUtf8Error {} #[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf16Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "invalid utf-16" - } -} +impl Error for FromUtf16Error {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 29caa7bc539..a21b6880674 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4113,11 +4113,6 @@ impl<T: ?Sized, A: Allocator> Drop for UniqueArcUninit<T, A> { #[stable(feature = "arc_error", since = "1.52.0")] impl<T: core::error::Error + ?Sized> core::error::Error for Arc<T> { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - core::error::Error::description(&**self) - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn core::error::Error> { core::error::Error::cause(&**self) diff --git a/library/compiler-builtins/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md index 387b70c0499..2d92b7651f9 100644 --- a/library/compiler-builtins/compiler-builtins/README.md +++ b/library/compiler-builtins/compiler-builtins/README.md @@ -10,6 +10,16 @@ to be added as an explicit dependency in `Cargo.toml`. [`compiler-rt`]: https://github.com/llvm/llvm-project/tree/1b1dc505057322f4fa1110ef4f53c44347f52986/compiler-rt +## Configuration + +`compiler-builtins` can be configured with the following environment variables when the `c` feature +is enabled: + +- `LLVM_COMPILER_RT_LIB` +- `RUST_COMPILER_RT_ROOT` + +See `build.rs` for details. + ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 43b978606e5..6e1d230e3cd 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -540,12 +540,20 @@ mod c { sources.extend(&[("__emutls_get_address", "emutls.c")]); } + // Optionally, link against a prebuilt llvm compiler-rt containing the builtins + // library. Only the builtins library is required. On many platforms, this is + // available as a library named libclang_rt.builtins.a. + let link_against_prebuilt_rt = env::var_os("LLVM_COMPILER_RT_LIB").is_some(); + // When compiling the C code we require the user to tell us where the // source code is, and this is largely done so when we're compiling as // part of rust-lang/rust we can use the same llvm-project repository as // rust-lang/rust. let root = match env::var_os("RUST_COMPILER_RT_ROOT") { Some(s) => PathBuf::from(s), + // If a prebuild libcompiler-rt is provided, set a valid + // path to simplify later logic. Nothing should be compiled. + None if link_against_prebuilt_rt => PathBuf::new(), None => { panic!( "RUST_COMPILER_RT_ROOT is not set. You may need to run \ @@ -553,7 +561,7 @@ mod c { ); } }; - if !root.exists() { + if !link_against_prebuilt_rt && !root.exists() { panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); } @@ -569,7 +577,7 @@ mod c { let src_dir = root.join("lib/builtins"); if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" { // See below for why we're building these as separate libraries. - build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); + build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg, link_against_prebuilt_rt); // Some run-time CPU feature detection is necessary, as well. let cpu_model_src = if src_dir.join("cpu_model.c").exists() { @@ -583,20 +591,45 @@ mod c { let mut added_sources = HashSet::new(); for (sym, src) in sources.map.iter() { let src = src_dir.join(src); - if added_sources.insert(src.clone()) { + if !link_against_prebuilt_rt && added_sources.insert(src.clone()) { cfg.file(&src); println!("cargo:rerun-if-changed={}", src.display()); } println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } - cfg.compile("libcompiler-rt.a"); + if link_against_prebuilt_rt { + let rt_builtins_ext = PathBuf::from(env::var_os("LLVM_COMPILER_RT_LIB").unwrap()); + if !rt_builtins_ext.exists() { + panic!( + "LLVM_COMPILER_RT_LIB={} does not exist", + rt_builtins_ext.display() + ); + } + if let Some(dir) = rt_builtins_ext.parent() { + println!("cargo::rustc-link-search=native={}", dir.display()); + } + if let Some(lib) = rt_builtins_ext.file_name() { + println!( + "cargo::rustc-link-lib=static:+verbatim={}", + lib.to_str().unwrap() + ); + } + } else { + cfg.compile("libcompiler-rt.a"); + } } - fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { + fn build_aarch64_out_of_line_atomics_libraries( + builtins_dir: &Path, + cfg: &mut cc::Build, + link_against_prebuilt_rt: bool, + ) { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let outlined_atomics_file = builtins_dir.join("aarch64").join("lse.S"); - println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + if !link_against_prebuilt_rt { + println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + } cfg.include(&builtins_dir); @@ -609,6 +642,13 @@ mod c { for (model_number, model_name) in &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] { + let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); + + if link_against_prebuilt_rt { + continue; + } + // The original compiler-rt build system compiles the same // source file multiple times with different compiler // options. Here we do something slightly different: we @@ -632,9 +672,6 @@ mod c { .unwrap(); drop(file); cfg.file(path); - - let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); - println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index bb75ec74c81..835ee57ce23 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -184,18 +184,12 @@ pub struct TryFromSliceError(()); impl fmt::Display for TryFromSliceError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) + "could not convert slice to array".fmt(f) } } #[stable(feature = "try_from", since = "1.34.0")] -impl Error for TryFromSliceError { - #[allow(deprecated)] - fn description(&self) -> &str { - "could not convert slice to array" - } -} +impl Error for TryFromSliceError {} #[stable(feature = "try_from_slice_error", since = "1.36.0")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 23061cb663b..cf5a91bf8dd 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -193,21 +193,16 @@ enum CharErrorKind { } #[stable(feature = "char_from_str", since = "1.20.0")] -impl Error for ParseCharError { - #[allow(deprecated)] - fn description(&self) -> &str { - match self.kind { - CharErrorKind::EmptyString => "cannot parse char from empty string", - CharErrorKind::TooManyChars => "too many characters in string", - } - } -} +impl Error for ParseCharError {} #[stable(feature = "char_from_str", since = "1.20.0")] impl fmt::Display for ParseCharError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) + match self.kind { + CharErrorKind::EmptyString => "cannot parse char from empty string", + CharErrorKind::TooManyChars => "too many characters in string", + } + .fmt(f) } } diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 23319fbe5dd..d7c5f45ae4e 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -126,9 +126,4 @@ impl fmt::Display for DecodeUtf16Error { } #[stable(feature = "decode_utf16", since = "1.9.0")] -impl Error for DecodeUtf16Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "unpaired surrogate found" - } -} +impl Error for DecodeUtf16Error {} diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 0c3034c3d4c..a0a7b7928d1 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -958,11 +958,7 @@ impl fmt::Display for Infallible { } #[stable(feature = "str_parse_error2", since = "1.8.0")] -impl Error for Infallible { - fn description(&self) -> &str { - match *self {} - } -} +impl Error for Infallible {} #[stable(feature = "convert_infallible", since = "1.34.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 88e633c9eef..92b3c83d1bf 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1042,11 +1042,6 @@ impl<'a> crate::iter::FusedIterator for Source<'a> {} #[stable(feature = "error_by_ref", since = "1.51.0")] impl<'a, T: Error + ?Sized> Error for &'a T { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - Error::description(&**self) - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) @@ -1062,36 +1057,16 @@ impl<'a, T: Error + ?Sized> Error for &'a T { } #[stable(feature = "fmt_error", since = "1.11.0")] -impl Error for crate::fmt::Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "an error occurred when formatting an argument" - } -} +impl Error for crate::fmt::Error {} #[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for crate::cell::BorrowError { - #[allow(deprecated)] - fn description(&self) -> &str { - "already mutably borrowed" - } -} +impl Error for crate::cell::BorrowError {} #[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for crate::cell::BorrowMutError { - #[allow(deprecated)] - fn description(&self) -> &str { - "already borrowed" - } -} +impl Error for crate::cell::BorrowMutError {} #[stable(feature = "try_from", since = "1.34.0")] -impl Error for crate::char::CharTryFromError { - #[allow(deprecated)] - fn description(&self) -> &str { - "converted integer out of range for `char`" - } -} +impl Error for crate::char::CharTryFromError {} #[stable(feature = "duration_checked_float", since = "1.66.0")] impl Error for crate::time::TryFromFloatSecsError {} diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 8ac29e5b076..b6de8925308 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -359,7 +359,7 @@ impl FormattingOptions { /// always be printed. /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self { + pub const fn sign(&mut self, sign: Option<Sign>) -> &mut Self { let sign = match sign { None => 0, Some(Sign::Plus) => flags::SIGN_PLUS_FLAG, @@ -372,7 +372,7 @@ impl FormattingOptions { /// /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { + pub const fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { if sign_aware_zero_pad { self.flags |= flags::SIGN_AWARE_ZERO_PAD_FLAG; } else { @@ -389,7 +389,7 @@ impl FormattingOptions { /// - [`Octal`] - precedes the argument with a `0b` /// - [`Binary`] - precedes the argument with a `0o` #[unstable(feature = "formatting_options", issue = "118117")] - pub fn alternate(&mut self, alternate: bool) -> &mut Self { + pub const fn alternate(&mut self, alternate: bool) -> &mut Self { if alternate { self.flags |= flags::ALTERNATE_FLAG; } else { @@ -404,7 +404,7 @@ impl FormattingOptions { /// being formatted is smaller than width some extra characters will be /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn fill(&mut self, fill: char) -> &mut Self { + pub const fn fill(&mut self, fill: char) -> &mut Self { self.flags = self.flags & (u32::MAX << 21) | fill as u32; self } @@ -413,7 +413,7 @@ impl FormattingOptions { /// The alignment specifies how the value being formatted should be /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn align(&mut self, align: Option<Alignment>) -> &mut Self { + pub const fn align(&mut self, align: Option<Alignment>) -> &mut Self { let align: u32 = match align { Some(Alignment::Left) => flags::ALIGN_LEFT, Some(Alignment::Right) => flags::ALIGN_RIGHT, @@ -430,7 +430,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn width(&mut self, width: Option<u16>) -> &mut Self { + pub const fn width(&mut self, width: Option<u16>) -> &mut Self { if let Some(width) = width { self.flags |= flags::WIDTH_FLAG; self.width = width; @@ -450,7 +450,7 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn precision(&mut self, precision: Option<u16>) -> &mut Self { + pub const fn precision(&mut self, precision: Option<u16>) -> &mut Self { if let Some(precision) = precision { self.flags |= flags::PRECISION_FLAG; self.precision = precision; @@ -463,7 +463,7 @@ impl FormattingOptions { /// Specifies whether the [`Debug`] trait should use lower-/upper-case /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] - pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self { + pub const fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self { let debug_as_hex = match debug_as_hex { None => 0, Some(DebugAsHex::Lower) => flags::DEBUG_LOWER_HEX_FLAG, @@ -537,7 +537,7 @@ impl FormattingOptions { /// /// You may alternatively use [`Formatter::new()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + pub const fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } } @@ -578,13 +578,13 @@ impl<'a> Formatter<'a> { /// /// You may alternatively use [`FormattingOptions::create_formatter()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { + pub const fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { Formatter { options, buf: write } } /// Creates a new formatter based on this one with given [`FormattingOptions`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { + pub const fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { Formatter { options, buf: self.buf } } } diff --git a/library/core/src/net/parser.rs b/library/core/src/net/parser.rs index 73230f6ee5b..3aab24a90d8 100644 --- a/library/core/src/net/parser.rs +++ b/library/core/src/net/parser.rs @@ -497,16 +497,7 @@ pub struct AddrParseError(AddrKind); #[stable(feature = "addr_parse_error_error", since = "1.4.0")] impl fmt::Display for AddrParseError { - #[allow(deprecated, deprecated_in_future)] - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.write_str(self.description()) - } -} - -#[stable(feature = "addr_parse_error_error", since = "1.4.0")] -impl Error for AddrParseError { - #[allow(deprecated)] - fn description(&self) -> &str { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { AddrKind::Ip => "invalid IP address syntax", AddrKind::Ipv4 => "invalid IPv4 address syntax", @@ -515,5 +506,9 @@ impl Error for AddrParseError { AddrKind::SocketV4 => "invalid IPv4 socket address syntax", AddrKind::SocketV6 => "invalid IPv6 socket address syntax", } + .fmt(f) } } + +#[stable(feature = "addr_parse_error_error", since = "1.4.0")] +impl Error for AddrParseError {} diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index 3118a6e5ca6..dd4eccd24de 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -219,21 +219,16 @@ enum FloatErrorKind { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseFloatError { - #[allow(deprecated)] - fn description(&self) -> &str { - match self.kind { - FloatErrorKind::Empty => "cannot parse float from empty string", - FloatErrorKind::Invalid => "invalid float literal", - } - } -} +impl Error for ParseFloatError {} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseFloatError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) + match self.kind { + FloatErrorKind::Empty => "cannot parse float from empty string", + FloatErrorKind::Invalid => "invalid float literal", + } + .fmt(f) } } diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index cfedd465cab..faa52329827 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -11,19 +11,13 @@ pub struct TryFromIntError(pub(crate) ()); #[stable(feature = "try_from", since = "1.34.0")] impl fmt::Display for TryFromIntError { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(fmt) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "out of range integral type conversion attempted".fmt(f) } } #[stable(feature = "try_from", since = "1.34.0")] -impl Error for TryFromIntError { - #[allow(deprecated)] - fn description(&self) -> &str { - "out of range integral type conversion attempted" - } -} +impl Error for TryFromIntError {} #[stable(feature = "try_from", since = "1.34.0")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] @@ -128,15 +122,6 @@ impl ParseIntError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseIntError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseIntError { - #[allow(deprecated)] - fn description(&self) -> &str { match self.kind { IntErrorKind::Empty => "cannot parse integer from empty string", IntErrorKind::InvalidDigit => "invalid digit found in string", @@ -144,5 +129,9 @@ impl Error for ParseIntError { IntErrorKind::NegOverflow => "number too small to fit in target type", IntErrorKind::Zero => "number would be zero for non-zero type", } + .fmt(f) } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseIntError {} diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index 4c8231a2286..1677c849ae4 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -124,12 +124,7 @@ impl fmt::Display for Utf8Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for Utf8Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "invalid utf-8: corrupt contents" - } -} +impl Error for Utf8Error {} /// An error returned when parsing a `bool` using [`from_str`] fails /// @@ -147,9 +142,4 @@ impl fmt::Display for ParseBoolError { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseBoolError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to parse bool" - } -} +impl Error for ParseBoolError {} diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 0cc570f4b73..f37e47f132d 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -927,7 +927,7 @@ impl Duration { pub fn from_secs_f64(secs: f64) -> Duration { match Duration::try_from_secs_f64(secs) { Ok(v) => v, - Err(e) => panic!("{}", e.description()), + Err(e) => panic!("{e}"), } } @@ -964,7 +964,7 @@ impl Duration { pub fn from_secs_f32(secs: f32) -> Duration { match Duration::try_from_secs_f32(secs) { Ok(v) => v, - Err(e) => panic!("{}", e.description()), + Err(e) => panic!("{e}"), } } @@ -1445,8 +1445,9 @@ pub struct TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind, } -impl TryFromFloatSecsError { - const fn description(&self) -> &'static str { +#[stable(feature = "duration_checked_float", since = "1.66.0")] +impl fmt::Display for TryFromFloatSecsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { TryFromFloatSecsErrorKind::Negative => { "cannot convert float seconds to Duration: value is negative" @@ -1455,13 +1456,7 @@ impl TryFromFloatSecsError { "cannot convert float seconds to Duration: value is either too big or NaN" } } - } -} - -#[stable(feature = "duration_checked_float", since = "1.66.0")] -impl fmt::Display for TryFromFloatSecsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.description().fmt(f) + .fmt(f) } } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 15a7a770d1a..fc0fef620e3 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1875,12 +1875,7 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { } #[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: fmt::Debug, V: fmt::Debug> Error for OccupiedError<'a, K, V> { - #[allow(deprecated)] - fn description(&self) -> &str { - "key already exists" - } -} +impl<'a, K: Debug, V: Debug> Error for OccupiedError<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> { diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 9f17ff76445..e457cd61c75 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -296,15 +296,7 @@ impl fmt::Display for VarError { } #[stable(feature = "env", since = "1.0.0")] -impl Error for VarError { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - VarError::NotPresent => "environment variable not found", - VarError::NotUnicode(..) => "environment variable was not valid unicode", - } - } -} +impl Error for VarError {} /// Sets the environment variable `key` to the value `value` for the currently running /// process. diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 574eb83dc56..d569fed24c5 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -492,23 +492,15 @@ impl WriterPanicked { pub fn into_inner(self) -> Vec<u8> { self.buf } - - const DESCRIPTION: &'static str = - "BufWriter inner writer panicked, what data remains unwritten is not known"; } #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] -impl error::Error for WriterPanicked { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - Self::DESCRIPTION - } -} +impl error::Error for WriterPanicked {} #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] impl fmt::Display for WriterPanicked { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", Self::DESCRIPTION) + "BufWriter inner writer panicked, what data remains unwritten is not known".fmt(f) } } diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index 475d877528f..e36f2d92108 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -179,12 +179,7 @@ impl<W> From<IntoInnerError<W>> for Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - error::Error::description(self.error()) - } -} +impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {} #[stable(feature = "rust1", since = "1.0.0")] impl<W> fmt::Display for IntoInnerError<W> { diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index dcfa189823f..57a980d6acd 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -1049,15 +1049,6 @@ impl fmt::Display for Error { #[stable(feature = "rust1", since = "1.0.0")] impl error::Error for Error { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - match self.repr.data() { - ErrorData::Os(..) | ErrorData::Simple(..) => self.kind().as_str(), - ErrorData::SimpleMessage(msg) => msg.message, - ErrorData::Custom(c) => c.error.description(), - } - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn error::Error> { match self.repr.data() { diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 1c228914de9..28e972925e6 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -54,7 +54,7 @@ impl BorrowedSocket<'_> { /// /// # Safety /// - /// The resource pointed to by `raw` must remain open for the duration of + /// The resource pointed to by `socket` must remain open for the duration of /// the returned `BorrowedSocket`, and it must not have the value /// `INVALID_SOCKET`. #[inline] diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 3899fbf86db..470d300d2d9 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3677,19 +3677,13 @@ impl_cmp_os_str!(<'a> Cow<'a, Path>, OsString); #[stable(since = "1.7.0", feature = "strip_prefix")] impl fmt::Display for StripPrefixError { - #[allow(deprecated, deprecated_in_future)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.description().fmt(f) + "prefix not found".fmt(f) } } #[stable(since = "1.7.0", feature = "strip_prefix")] -impl Error for StripPrefixError { - #[allow(deprecated)] - fn description(&self) -> &str { - "prefix not found" - } -} +impl Error for StripPrefixError {} #[unstable(feature = "normalize_lexically", issue = "134694")] impl fmt::Display for NormalizeError { diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index 03d7fddc2fa..f91c26aa22c 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -1108,12 +1108,7 @@ impl<T> fmt::Display for SendError<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> error::Error for SendError<T> { - #[allow(deprecated)] - fn description(&self) -> &str { - "sending on a closed channel" - } -} +impl<T> error::Error for SendError<T> {} #[stable(feature = "rust1", since = "1.0.0")] impl<T> fmt::Debug for TrySendError<T> { @@ -1136,15 +1131,7 @@ impl<T> fmt::Display for TrySendError<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> error::Error for TrySendError<T> { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - TrySendError::Full(..) => "sending on a full channel", - TrySendError::Disconnected(..) => "sending on a closed channel", - } - } -} +impl<T> error::Error for TrySendError<T> {} #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl<T> From<SendError<T>> for TrySendError<T> { @@ -1168,12 +1155,7 @@ impl fmt::Display for RecvError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for RecvError { - #[allow(deprecated)] - fn description(&self) -> &str { - "receiving on a closed channel" - } -} +impl error::Error for RecvError {} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for TryRecvError { @@ -1186,15 +1168,7 @@ impl fmt::Display for TryRecvError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for TryRecvError { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - TryRecvError::Empty => "receiving on an empty channel", - TryRecvError::Disconnected => "receiving on a closed channel", - } - } -} +impl error::Error for TryRecvError {} #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From<RecvError> for TryRecvError { @@ -1221,15 +1195,7 @@ impl fmt::Display for RecvTimeoutError { } #[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")] -impl error::Error for RecvTimeoutError { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - RecvTimeoutError::Timeout => "timed out waiting on channel", - RecvTimeoutError::Disconnected => "channel is empty and sending half is closed", - } - } -} +impl error::Error for RecvTimeoutError {} #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From<RecvError> for RecvTimeoutError { diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 31889dcc10f..49a71b9ad10 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -263,12 +263,7 @@ impl<T> fmt::Display for PoisonError<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Error for PoisonError<T> { - #[allow(deprecated)] - fn description(&self) -> &str { - "poisoned lock: another task failed inside" - } -} +impl<T> Error for PoisonError<T> {} impl<T> PoisonError<T> { /// Creates a `PoisonError`. @@ -376,17 +371,6 @@ impl<T> fmt::Display for TryLockError<T> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> Error for TryLockError<T> { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - match *self { - #[cfg(panic = "unwind")] - TryLockError::Poisoned(ref p) => p.description(), - #[cfg(not(panic = "unwind"))] - TryLockError::Poisoned(ref p) => match p._never {}, - TryLockError::WouldBlock => "try_lock failed because the operation would block", - } - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { match *self { diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 242df10bc32..2389fd1bcb6 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -452,12 +452,7 @@ pub struct NonIpSockAddr { host: String, } -impl error::Error for NonIpSockAddr { - #[allow(deprecated)] - fn description(&self) -> &str { - "Failed to convert address to SocketAddr" - } -} +impl error::Error for NonIpSockAddr {} impl fmt::Display for NonIpSockAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index a998c3165e5..0fe713a503b 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -1,5 +1,4 @@ use super::hermit_abi; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; @@ -52,12 +51,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on hermit yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 6e43a79ddec..4a297b6823f 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -59,8 +59,7 @@ pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> { #[inline] pub fn is_interrupted(code: i32) -> bool { - use fortanix_sgx_abi::Error; - code == Error::Interrupted as _ + code == fortanix_sgx_abi::Error::Interrupted as _ } pub fn decode_error_kind(code: i32) -> ErrorKind { diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs index 70f838679c9..28d79963ac8 100644 --- a/library/std/src/sys/pal/sgx/os.rs +++ b/library/std/src/sys/pal/sgx/os.rs @@ -1,11 +1,10 @@ use fortanix_sgx_abi::{Error, RESULT_SUCCESS}; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; use crate::sys::{decode_error_kind, sgx_ineffective, unsupported}; -use crate::{fmt, io, str}; +use crate::{fmt, io}; pub fn errno() -> i32 { RESULT_SUCCESS @@ -59,12 +58,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported in SGX yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs index 8f5976b0592..cb6e2cbceae 100644 --- a/library/std/src/sys/pal/solid/os.rs +++ b/library/std/src/sys/pal/solid/os.rs @@ -1,5 +1,4 @@ use super::{error, itron, unsupported}; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::path::{self, PathBuf}; use crate::{fmt, io}; @@ -58,12 +57,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/sys/pal/teeos/os.rs b/library/std/src/sys/pal/teeos/os.rs index 03f3c72b022..512b3e2885b 100644 --- a/library/std/src/sys/pal/teeos/os.rs +++ b/library/std/src/sys/pal/teeos/os.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::path::PathBuf; use crate::{fmt, io, path}; @@ -62,12 +61,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index bfd4dc81cb4..aae6cb9e064 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -2,7 +2,6 @@ use r_efi::efi::Status; use r_efi::efi::protocols::{device_path, loaded_image_device_path}; use super::{RawOsError, helpers, unsupported_err}; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::uefi; @@ -122,7 +121,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError {} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { let protocol = helpers::image_handle_protocol::<device_path::Protocol>( diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 1110b775c09..81275afa707 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -7,7 +7,6 @@ mod tests; use libc::{c_char, c_int, c_void}; -use crate::error::Error as StdError; use crate::ffi::{CStr, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::{self, PathBuf}; @@ -248,12 +247,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} +impl crate::error::Error for JoinPathsError {} #[cfg(target_os = "aix")] pub fn current_exe() -> io::Result<PathBuf> { diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs index a8ef97ecf67..13d2a2044f4 100644 --- a/library/std/src/sys/pal/unsupported/os.rs +++ b/library/std/src/sys/pal/unsupported/os.rs @@ -1,5 +1,4 @@ use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; @@ -51,12 +50,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index 672cf70d1a5..151ba254ec4 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use crate::error::Error as StdError; use crate::ffi::{CStr, OsStr, OsString}; use crate::marker::PhantomData; use crate::os::wasi::prelude::*; @@ -105,12 +104,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on wasm yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index f331282d2d7..1b3c80c079b 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -8,7 +8,6 @@ mod tests; use super::api; #[cfg(not(target_vendor = "uwp"))] use super::api::WinError; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::os::windows::ffi::EncodeWide; use crate::os::windows::prelude::*; @@ -162,12 +161,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { super::fill_utf16_buf( diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index d612a27d2bd..d9b8418e6c3 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -1,5 +1,4 @@ use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::xous::ffi::Error as XousError; @@ -110,12 +109,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index a8ef97ecf67..13d2a2044f4 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -1,5 +1,4 @@ use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; @@ -51,12 +50,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result<PathBuf> { unsupported() diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 07bb41f1496..84fbb4c2fe4 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -717,12 +717,7 @@ impl SystemTimeError { } #[stable(feature = "time2", since = "1.8.0")] -impl Error for SystemTimeError { - #[allow(deprecated)] - fn description(&self) -> &str { - "other time was not earlier than self" - } -} +impl Error for SystemTimeError {} #[stable(feature = "time2", since = "1.8.0")] impl fmt::Display for SystemTimeError { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 40e08361a0f..2ece53eb0cc 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -312,6 +312,12 @@ def default_build_triple(verbose): kernel, cputype, processor = uname.decode(default_encoding).split(maxsplit=2) + # ON NetBSD, use `uname -p` to set the CPU type + if kernel == "NetBSD": + cputype = ( + subprocess.check_output(["uname", "-p"]).strip().decode(default_encoding) + ) + # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. kerneltype_mapper = { @@ -433,10 +439,16 @@ def default_build_triple(verbose): kernel = "linux-androideabi" else: kernel += "eabihf" - elif cputype in {"armv7l", "armv8l"}: + elif cputype in {"armv6hf", "earmv6hf"}: + cputype = "armv6" + if kernel == "unknown-netbsd": + kernel += "-eabihf" + elif cputype in {"armv7l", "earmv7hf", "armv8l"}: cputype = "armv7" if kernel == "linux-android": kernel = "linux-androideabi" + elif kernel == "unknown-netbsd": + kernel += "-eabihf" else: kernel += "eabihf" elif cputype == "mips": diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6ca32aca345..d30005c8d51 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -26,7 +26,9 @@ use crate::core::builder; use crate::core::builder::{ Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, }; -use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; +use crate::core::config::{ + CompilerBuiltins, DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection, +}; use crate::utils::build_stamp; use crate::utils::build_stamp::BuildStamp; use crate::utils::exec::command; @@ -96,10 +98,36 @@ impl Std { } deps } + + /// Returns true if the standard library will be uplifted from stage 1 for the given + /// `build_compiler` (which determines the stdlib stage) and `target`. + /// + /// Uplifting is enabled if we're building a stage2+ libstd, full bootstrap is + /// disabled and we have a stage1 libstd already compiled for the given target. + pub fn should_be_uplifted_from_stage_1( + builder: &Builder<'_>, + stage: u32, + target: TargetSelection, + ) -> bool { + stage > 1 + && !builder.config.full_bootstrap + // This estimates if a stage1 libstd exists for the given target. If we're not + // cross-compiling, it should definitely exist by the time we're building a stage2 + // libstd. + // Or if we are cross-compiling, and we are building a cross-compiled rustc, then that + // rustc needs to link to a cross-compiled libstd, so again we should have a stage1 + // libstd for the given target prepared. + // Even if we guess wrong in the cross-compiled case, the worst that should happen is + // that we build a fresh stage1 libstd below, and then we immediately uplift it, so we + // don't pay the libstd build cost twice. + && (target == builder.host_target || builder.config.hosts.contains(&target)) + } } impl Step for Std { - type Output = (); + /// Build stamp of std, if it was indeed built or uplifted. + type Output = Option<BuildStamp>; + const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -136,15 +164,20 @@ impl Step for Std { /// This will build the standard library for a particular stage of the build /// using the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. - fn run(self, builder: &Builder<'_>) { + fn run(self, builder: &Builder<'_>) -> Self::Output { let target = self.target; - // We already have std ready to be used for stage 0. - if self.build_compiler.stage == 0 { + // In most cases, we already have the std ready to be used for stage 0. + // However, if we are doing a local rebuild (so the build compiler can compile the standard + // library even on stage 0), and we're cross-compiling (so the stage0 standard library for + // *target* is not available), we still allow the stdlib to be built here. + if self.build_compiler.stage == 0 + && !(builder.local_rebuild && target != builder.host_target) + { let compiler = self.build_compiler; builder.ensure(StdLink::from_std(self, compiler)); - return; + return None; } let build_compiler = if builder.download_rustc() && self.force_recompile { @@ -169,7 +202,7 @@ impl Step for Std { &sysroot, builder.config.ci_rust_std_contents(), ); - return; + return None; } if builder.config.keep_stage.contains(&build_compiler.stage) @@ -185,7 +218,7 @@ impl Step for Std { self.copy_extra_objects(builder, &build_compiler, target); builder.ensure(StdLink::from_std(self, build_compiler)); - return; + return Some(build_stamp::libstd_stamp(builder, build_compiler, target)); } let mut target_deps = builder.ensure(StartupObjects { compiler: build_compiler, target }); @@ -193,24 +226,9 @@ impl Step for Std { // Stage of the stdlib that we're building let stage = build_compiler.stage; - // If we're building a stage2+ libstd, full bootstrap is - // disabled and we have a stage1 libstd already compiled for the given target, - // then simply uplift a previously built stage1 library. - if build_compiler.stage > 1 - && !builder.config.full_bootstrap - // This estimates if a stage1 libstd exists for the given target. If we're not - // cross-compiling, it should definitely exist by the time we're building a stage2 - // libstd. - // Or if we are cross-compiling, and we are building a cross-compiled rustc, then that - // rustc needs to link to a cross-compiled libstd, so again we should have a stage1 - // libstd for the given target prepared. - // Even if we guess wrong in the cross-compiled case, the worst that should happen is - // that we build a fresh stage1 libstd below, and then we immediately uplift it, so we - // don't pay the libstd build cost twice. - && (target == builder.host_target || builder.config.hosts.contains(&target)) - { + if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage, target) { let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target); - builder.std(build_compiler_for_std_to_uplift, target); + let stage_1_stamp = builder.std(build_compiler_for_std_to_uplift, target); let msg = if build_compiler_for_std_to_uplift.host == target { format!( @@ -231,7 +249,7 @@ impl Step for Std { self.copy_extra_objects(builder, &build_compiler, target); builder.ensure(StdLink::from_std(self, build_compiler_for_std_to_uplift)); - return; + return stage_1_stamp; } target_deps.extend(self.copy_extra_objects(builder, &build_compiler, target)); @@ -284,11 +302,13 @@ impl Step for Std { build_compiler, target, ); + + let stamp = build_stamp::libstd_stamp(builder, build_compiler, target); run_cargo( builder, cargo, vec![], - &build_stamp::libstd_stamp(builder, build_compiler, target), + &stamp, target_deps, self.is_for_mir_opt_tests, // is_check false, @@ -298,6 +318,7 @@ impl Step for Std { self, builder.compiler(build_compiler.stage, builder.config.host_target), )); + Some(stamp) } fn metadata(&self) -> Option<StepMetadata> { @@ -560,29 +581,36 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car // If `compiler-rt` is available ensure that the `c` feature of the // `compiler-builtins` crate is enabled and it's configured to learn where // `compiler-rt` is located. - let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins(target) { - // NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce `submodules = false`, so this is a no-op. - // But, the user could still decide to manually use an in-tree submodule. - // - // NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt` that doesn't match the LLVM we're linking to. - // That's probably ok? At least, the difference wasn't enforced before. There's a comment in - // the compiler_builtins build script that makes me nervous, though: - // https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579 - builder.require_submodule( - "src/llvm-project", - Some( - "The `build.optimized-compiler-builtins` config option \ - requires `compiler-rt` sources from LLVM.", - ), - ); - let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); - assert!(compiler_builtins_root.exists()); - // The path to `compiler-rt` is also used by `profiler_builtins` (above), - // so if you're changing something here please also change that as appropriate. - cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); - " compiler-builtins-c" - } else { - "" + let compiler_builtins_c_feature = match builder.config.optimized_compiler_builtins(target) { + CompilerBuiltins::LinkLLVMBuiltinsLib(path) => { + cargo.env("LLVM_COMPILER_RT_LIB", path); + " compiler-builtins-c" + } + CompilerBuiltins::BuildLLVMFuncs => { + // NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce + // `submodules = false`, so this is a no-op. But, the user could still decide to + // manually use an in-tree submodule. + // + // NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt` + // that doesn't match the LLVM we're linking to. That's probably ok? At least, the + // difference wasn't enforced before. There's a comment in the compiler_builtins build + // script that makes me nervous, though: + // https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579 + builder.require_submodule( + "src/llvm-project", + Some( + "The `build.optimized-compiler-builtins` config option \ + requires `compiler-rt` sources from LLVM.", + ), + ); + let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); + assert!(compiler_builtins_root.exists()); + // The path to `compiler-rt` is also used by `profiler_builtins` (above), + // so if you're changing something here please also change that as appropriate. + cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); + " compiler-builtins-c" + } + CompilerBuiltins::BuildRustOnly => "", }; // `libtest` uses this to know whether or not to support @@ -1309,9 +1337,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS cargo.env("CFG_OMIT_GIT_HASH", "1"); } - if let Some(backend) = builder.config.default_codegen_backend(target) { - cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", backend.name()); - } + cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", builder.config.default_codegen_backend(target).name()); let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); let target_config = builder.config.target_config.get(&target); @@ -2008,6 +2034,7 @@ impl Step for Assemble { let host_llvm_bin_dir = command(&host_llvm_config) .arg("--bindir") + .cached() .run_capture_stdout(builder) .stdout() .trim() diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index daac75c03e2..778c3beb50f 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -21,7 +21,9 @@ use tracing::instrument; use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name}; use crate::core::build_steps::doc::DocumentationFormat; -use crate::core::build_steps::tool::{self, RustcPrivateCompilers, Tool}; +use crate::core::build_steps::tool::{ + self, RustcPrivateCompilers, Tool, ToolTargetBuildMode, get_tool_target_compiler, +}; use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor}; use crate::core::build_steps::{compile, llvm}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata}; @@ -75,7 +77,10 @@ impl Step for Docs { /// Builds the `rust-docs` installer component. fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { let host = self.host; - builder.default_doc(&[]); + // FIXME: explicitly enumerate the steps that should be executed here, and gather their + // documentation, rather than running all default steps and then read their output + // from a shared directory. + builder.run_default_doc_steps(); let dest = "share/doc/rust/html"; @@ -132,13 +137,20 @@ impl Step for JsonDocs { } } +/// Builds the `rustc-docs` installer component. +/// Apart from the documentation of the `rustc_*` crates, it also includes the documentation of +/// various in-tree helper tools (bootstrap, build_helper, tidy), +/// and also rustc_private tools like rustdoc, clippy, miri or rustfmt. +/// +/// It is currently hosted at <https://doc.rust-lang.org/nightly/nightly-rustc>. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustcDocs { - pub host: TargetSelection, + target: TargetSelection, } impl Step for RustcDocs { - type Output = Option<GeneratedTarball>; + type Output = GeneratedTarball; + const DEFAULT: bool = true; const IS_HOST: bool = true; @@ -148,18 +160,17 @@ impl Step for RustcDocs { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustcDocs { host: run.target }); + run.builder.ensure(RustcDocs { target: run.target }); } - /// Builds the `rustc-docs` installer component. - fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - let host = self.host; - builder.default_doc(&[]); + fn run(self, builder: &Builder<'_>) -> Self::Output { + let target = self.target; + builder.run_default_doc_steps(); - let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple); + let mut tarball = Tarball::new(builder, "rustc-docs", &target.triple); tarball.set_product_name("Rustc Documentation"); - tarball.add_bulk_dir(builder.compiler_doc_out(host), "share/doc/rust/html/rustc"); - Some(tarball.generate()) + tarball.add_bulk_dir(builder.compiler_doc_out(target), "share/doc/rust/html/rustc"); + tarball.generate() } } @@ -354,9 +365,13 @@ fn get_cc_search_dirs( (bin_path, lib_path) } +/// Builds the `rust-mingw` installer component. +/// +/// This contains all the bits and pieces to run the MinGW Windows targets +/// without any extra installed software (e.g., we bundle gcc, libraries, etc.). #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Mingw { - pub host: TargetSelection, + target: TargetSelection, } impl Step for Mingw { @@ -368,39 +383,46 @@ impl Step for Mingw { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Mingw { host: run.target }); + run.builder.ensure(Mingw { target: run.target }); } - /// Builds the `rust-mingw` installer component. - /// - /// This contains all the bits and pieces to run the MinGW Windows targets - /// without any extra installed software (e.g., we bundle gcc, libraries, etc). fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - let host = self.host; - if !host.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker { + let target = self.target; + if !target.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker { return None; } - let mut tarball = Tarball::new(builder, "rust-mingw", &host.triple); + let mut tarball = Tarball::new(builder, "rust-mingw", &target.triple); tarball.set_product_name("Rust MinGW"); - make_win_dist(tarball.image_dir(), host, builder); + make_win_dist(tarball.image_dir(), target, builder); Some(tarball.generate()) } fn metadata(&self) -> Option<StepMetadata> { - Some(StepMetadata::dist("mingw", self.host)) + Some(StepMetadata::dist("mingw", self.target)) } } +/// Creates the `rustc` installer component. +/// +/// This includes: +/// - The compiler and LLVM. +/// - Debugger scripts. +/// - Various helper tools, e.g. LLD or Rust Analyzer proc-macro server (if enabled). +/// - The licenses of all code used by the compiler. +/// +/// It does not include any standard library. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Rustc { - pub compiler: Compiler, + /// This is the compiler that we will *ship* in this dist step. + pub target_compiler: Compiler, } impl Step for Rustc { type Output = GeneratedTarball; + const DEFAULT: bool = true; const IS_HOST: bool = true; @@ -409,19 +431,19 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(Rustc { compiler: run.builder.compiler(run.builder.top_stage, run.target) }); + run.builder.ensure(Rustc { + target_compiler: run.builder.compiler(run.builder.top_stage, run.target), + }); } - /// Creates the `rustc` installer component. fn run(self, builder: &Builder<'_>) -> GeneratedTarball { - let compiler = self.compiler; - let host = self.compiler.host; + let target_compiler = self.target_compiler; + let target = self.target_compiler.host; - let tarball = Tarball::new(builder, "rustc", &host.triple); + let tarball = Tarball::new(builder, "rustc", &target.triple); // Prepare the rustc "image", what will actually end up getting installed - prepare_image(builder, compiler, tarball.image_dir()); + prepare_image(builder, target_compiler, tarball.image_dir()); // On MinGW we've got a few runtime DLL dependencies that we need to // include. @@ -430,16 +452,16 @@ impl Step for Rustc { // anything requiring us to distribute a license, but it's likely the // install will *also* include the rust-mingw package, which also needs // licenses, so to be safe we just include it here in all MinGW packages. - if host.contains("pc-windows-gnu") && builder.config.dist_include_mingw_linker { - runtime_dll_dist(tarball.image_dir(), host, builder); + if target.contains("pc-windows-gnu") && builder.config.dist_include_mingw_linker { + runtime_dll_dist(tarball.image_dir(), target, builder); tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc"); } return tarball.generate(); - fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) { - let host = compiler.host; - let src = builder.sysroot(compiler); + fn prepare_image(builder: &Builder<'_>, target_compiler: Compiler, image: &Path) { + let target = target_compiler.host; + let src = builder.sysroot(target_compiler); // Copy rustc binary t!(fs::create_dir_all(image.join("bin"))); @@ -452,17 +474,11 @@ impl Step for Rustc { .as_ref() .is_none_or(|tools| tools.iter().any(|tool| tool == "rustdoc")) { - let rustdoc = builder.rustdoc_for_compiler(compiler); + let rustdoc = builder.rustdoc_for_compiler(target_compiler); builder.install(&rustdoc, &image.join("bin"), FileType::Executable); } - let ra_proc_macro_srv_compiler = - builder.compiler_for(compiler.stage, builder.config.host_target, compiler.host); - let compilers = RustcPrivateCompilers::from_build_compiler( - builder, - ra_proc_macro_srv_compiler, - compiler.host, - ); + let compilers = RustcPrivateCompilers::from_target_compiler(builder, target_compiler); if let Some(ra_proc_macro_srv) = builder.ensure_if_default( tool::RustAnalyzerProcMacroSrv::from_compilers(compilers), @@ -472,11 +488,11 @@ impl Step for Rustc { builder.install(&ra_proc_macro_srv.tool_path, &dst, FileType::Executable); } - let libdir_relative = builder.libdir_relative(compiler); + let libdir_relative = builder.libdir_relative(target_compiler); // Copy runtime DLLs needed by the compiler if libdir_relative.to_str() != Some("bin") { - let libdir = builder.rustc_libdir(compiler); + let libdir = builder.rustc_libdir(target_compiler); for entry in builder.read_dir(&libdir) { // A safeguard that we will not ship libgccjit.so from the libdir, in case the // GCC codegen backend is enabled by default. @@ -503,15 +519,15 @@ impl Step for Rustc { // components like the llvm tools and LLD. LLD is included below and // tools/LLDB come later, so let's just throw it in the rustc // component for now. - maybe_install_llvm_runtime(builder, host, image); + maybe_install_llvm_runtime(builder, target, image); - let dst_dir = image.join("lib/rustlib").join(host).join("bin"); + let dst_dir = image.join("lib/rustlib").join(target).join("bin"); t!(fs::create_dir_all(&dst_dir)); // Copy over lld if it's there if builder.config.lld_enabled { - let src_dir = builder.sysroot_target_bindir(compiler, host); - let rust_lld = exe("rust-lld", compiler.host); + let src_dir = builder.sysroot_target_bindir(target_compiler, target); + let rust_lld = exe("rust-lld", target_compiler.host); builder.copy_link( &src_dir.join(&rust_lld), &dst_dir.join(&rust_lld), @@ -521,7 +537,7 @@ impl Step for Rustc { let self_contained_lld_dst_dir = dst_dir.join("gcc-ld"); t!(fs::create_dir(&self_contained_lld_dst_dir)); for name in crate::LLD_FILE_NAMES { - let exe_name = exe(name, compiler.host); + let exe_name = exe(name, target_compiler.host); builder.copy_link( &self_contained_lld_src_dir.join(&exe_name), &self_contained_lld_dst_dir.join(&exe_name), @@ -530,10 +546,12 @@ impl Step for Rustc { } } - if builder.config.llvm_enabled(compiler.host) && builder.config.llvm_tools_enabled { - let src_dir = builder.sysroot_target_bindir(compiler, host); - let llvm_objcopy = exe("llvm-objcopy", compiler.host); - let rust_objcopy = exe("rust-objcopy", compiler.host); + if builder.config.llvm_enabled(target_compiler.host) + && builder.config.llvm_tools_enabled + { + let src_dir = builder.sysroot_target_bindir(target_compiler, target); + let llvm_objcopy = exe("llvm-objcopy", target_compiler.host); + let rust_objcopy = exe("rust-objcopy", target_compiler.host); builder.copy_link( &src_dir.join(&llvm_objcopy), &dst_dir.join(&rust_objcopy), @@ -542,8 +560,8 @@ impl Step for Rustc { } if builder.tool_enabled("wasm-component-ld") { - let src_dir = builder.sysroot_target_bindir(compiler, host); - let ld = exe("wasm-component-ld", compiler.host); + let src_dir = builder.sysroot_target_bindir(target_compiler, target); + let ld = exe("wasm-component-ld", target_compiler.host); builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld), FileType::Executable); } @@ -564,7 +582,7 @@ impl Step for Rustc { } // Debugger scripts - builder.ensure(DebuggerScripts { sysroot: image.to_owned(), host }); + builder.ensure(DebuggerScripts { sysroot: image.to_owned(), target }); // HTML copyright files let file_list = builder.ensure(super::run::GenerateCopyright); @@ -590,14 +608,16 @@ impl Step for Rustc { } fn metadata(&self) -> Option<StepMetadata> { - Some(StepMetadata::dist("rustc", self.compiler.host)) + Some(StepMetadata::dist("rustc", self.target_compiler.host)) } } +/// Copies debugger scripts for `target` into the given compiler `sysroot`. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct DebuggerScripts { + /// Sysroot of a compiler into which will the debugger scripts be copied to. pub sysroot: PathBuf, - pub host: TargetSelection, + pub target: TargetSelection, } impl Step for DebuggerScripts { @@ -607,16 +627,15 @@ impl Step for DebuggerScripts { run.never() } - /// Copies debugger scripts for `target` into the `sysroot` specified. fn run(self, builder: &Builder<'_>) { - let host = self.host; + let target = self.target; let sysroot = self.sysroot; let dst = sysroot.join("lib/rustlib/etc"); t!(fs::create_dir_all(&dst)); let cp_debugger_script = |file: &str| { builder.install(&builder.src.join("src/etc/").join(file), &dst, FileType::Regular); }; - if host.contains("windows-msvc") { + if target.contains("windows-msvc") { // windbg debugger scripts builder.install( &builder.src.join("src/etc/rust-windbg.cmd"), @@ -730,12 +749,40 @@ fn copy_target_libs( } } +/// Builds the standard library (`rust-std`) dist component for a given `target`. +/// This includes the standard library dynamic library file (e.g. .so/.dll), along with stdlib +/// .rlibs. +/// +/// Note that due to uplifting, we actually ship the stage 1 library +/// (built using the stage1 compiler) even with a stage 2 dist, unless `full-bootstrap` is enabled. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Std { - pub compiler: Compiler, + /// Compiler that will build the standard library. + pub build_compiler: Compiler, pub target: TargetSelection, } +impl Std { + pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self { + // This is an important optimization mainly for CI. + // Normally, to build stage N libstd, we need stage N rustc. + // However, if we know that we will uplift libstd from stage 1 anyway, building the stage N + // rustc can be wasteful. + // In particular, if we do a cross-compiling dist stage 2 build from T1 to T2, we need: + // - stage 2 libstd for T2 (uplifted from stage 1, where it was built by T1 rustc) + // - stage 2 rustc for T2 + // However, without this optimization, we would also build stage 2 rustc for **T1**, which + // is completely wasteful. + let build_compiler = + if compile::Std::should_be_uplifted_from_stage_1(builder, builder.top_stage, target) { + builder.compiler(1, builder.host_target) + } else { + builder.compiler(builder.top_stage, builder.host_target) + }; + Std { build_compiler, target } + } +} + impl Step for Std { type Output = Option<GeneratedTarball>; const DEFAULT: bool = true; @@ -745,31 +792,25 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Std { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), - target: run.target, - }); + run.builder.ensure(Std::new(run.builder, run.target)); } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - let compiler = self.compiler; + let build_compiler = self.build_compiler; let target = self.target; - if skip_host_target_lib(builder, compiler) { + if skip_host_target_lib(builder, build_compiler) { return None; } - builder.std(compiler, target); + // It's possible that std was uplifted and thus built with a different build compiler + // So we need to read the stamp that was actually generated when std was built + let stamp = + builder.std(build_compiler, target).expect("Standard library has to be built for dist"); let mut tarball = Tarball::new(builder, "rust-std", &target.triple); tarball.include_target_in_component_name(true); - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); - let stamp = build_stamp::libstd_stamp(builder, compiler_to_use, target); verify_uefi_rlib_format(builder, target, &stamp); copy_target_libs(builder, target, tarball.image_dir(), &stamp); @@ -777,7 +818,7 @@ impl Step for Std { } fn metadata(&self) -> Option<StepMetadata> { - Some(StepMetadata::dist("std", self.target).built_by(self.compiler)) + Some(StepMetadata::dist("std", self.target).built_by(self.build_compiler)) } } @@ -787,8 +828,9 @@ impl Step for Std { /// (Don't confuse this with [`RustDev`], without the `c`!) #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { - pub compiler: Compiler, - pub target: TargetSelection, + /// The compiler that will build rustc which will be shipped in this component. + build_compiler: Compiler, + target: TargetSelection, } impl Step for RustcDev { @@ -802,28 +844,27 @@ impl Step for RustcDev { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustcDev { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + // We currently always ship a stage 2 rustc-dev component, so we build it with the + // stage 1 compiler. This might change in the future. + // The precise stage used here is important, so we hard-code it. + build_compiler: run.builder.compiler(1, run.builder.config.host_target), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - let compiler = self.compiler; + let build_compiler = self.build_compiler; let target = self.target; - if skip_host_target_lib(builder, compiler) { + if skip_host_target_lib(builder, build_compiler) { return None; } - builder.ensure(compile::Rustc::new(compiler, target)); + // Build the compiler that we will ship + builder.ensure(compile::Rustc::new(build_compiler, target)); let tarball = Tarball::new(builder, "rustc-dev", &target.triple); - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); - let stamp = build_stamp::librustc_stamp(builder, compiler_to_use, target); + let stamp = build_stamp::librustc_stamp(builder, build_compiler, target); copy_target_libs(builder, target, tarball.image_dir(), &stamp); let src_files = &["Cargo.lock"]; @@ -847,16 +888,25 @@ impl Step for RustcDev { Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("rustc-dev", self.target).built_by(self.build_compiler)) + } } +/// The `rust-analysis` component used to create a tarball of save-analysis metadata. +/// +/// This component has been deprecated and its contents now only include a warning about +/// its non-availability. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Analysis { - pub compiler: Compiler, - pub target: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, } impl Step for Analysis { type Output = Option<GeneratedTarball>; + const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -865,24 +915,17 @@ impl Step for Analysis { } fn make_run(run: RunConfig<'_>) { + // The step just produces a deprecation notice, so we just hardcode stage 1 run.builder.ensure(Analysis { - // Find the actual compiler (handling the full bootstrap option) which - // produced the save-analysis data because that data isn't copied - // through the sysroot uplifting. - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + build_compiler: run.builder.compiler(1, run.builder.config.host_target), target: run.target, }); } - /// Creates a tarball of (degenerate) save-analysis metadata, if available. fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - let compiler = self.compiler; + let compiler = self.build_compiler; let target = self.target; - if !builder.config.is_host_target(compiler.host) { + if skip_host_target_lib(builder, compiler) { return None; } @@ -905,6 +948,10 @@ impl Step for Analysis { tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple)); Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("analysis", self.target).built_by(self.build_compiler)) + } } /// Use the `builder` to make a filtered copy of `base`/X for X in (`src_dirs` - `exclude_dirs`) to @@ -1251,10 +1298,9 @@ impl Step for Cargo { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Cargo { - build_compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, + build_compiler: get_tool_target_compiler( + run.builder, + ToolTargetBuildMode::Build(run.target), ), target: run.target, }); @@ -1285,11 +1331,16 @@ impl Step for Cargo { Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("cargo", self.target).built_by(self.build_compiler)) + } } +/// Distribute the rust-analyzer component, which is used as a LSP by various IDEs. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { - pub build_compiler: Compiler, + pub compilers: RustcPrivateCompilers, pub target: TargetSelection, } @@ -1305,21 +1356,14 @@ impl Step for RustAnalyzer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustAnalyzer { - build_compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { let target = self.target; - let compilers = - RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target); - - let rust_analyzer = builder.ensure(tool::RustAnalyzer::from_compilers(compilers)); + let rust_analyzer = builder.ensure(tool::RustAnalyzer::from_compilers(self.compilers)); let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); tarball.set_overlay(OverlayKind::RustAnalyzer); @@ -1328,11 +1372,18 @@ impl Step for RustAnalyzer { tarball.add_legal_and_readme_to("share/doc/rust-analyzer"); Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::dist("rust-analyzer", self.target) + .built_by(self.compilers.build_compiler()), + ) + } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Clippy { - pub build_compiler: Compiler, + pub compilers: RustcPrivateCompilers, pub target: TargetSelection, } @@ -1348,25 +1399,19 @@ impl Step for Clippy { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Clippy { - build_compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { let target = self.target; - let compilers = - RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target); // Prepare the image directory // We expect clippy to build, because we've exited this step above if tool // state for clippy isn't testing. - let clippy = builder.ensure(tool::Clippy::from_compilers(compilers)); - let cargoclippy = builder.ensure(tool::CargoClippy::from_compilers(compilers)); + let clippy = builder.ensure(tool::Clippy::from_compilers(self.compilers)); + let cargoclippy = builder.ensure(tool::CargoClippy::from_compilers(self.compilers)); let mut tarball = Tarball::new(builder, "clippy", &target.triple); tarball.set_overlay(OverlayKind::Clippy); @@ -1376,11 +1421,15 @@ impl Step for Clippy { tarball.add_legal_and_readme_to("share/doc/clippy"); Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("clippy", self.target).built_by(self.compilers.build_compiler())) + } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Miri { - pub build_compiler: Compiler, + pub compilers: RustcPrivateCompilers, pub target: TargetSelection, } @@ -1396,11 +1445,7 @@ impl Step for Miri { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Miri { - build_compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), target: run.target, }); } @@ -1413,10 +1458,8 @@ impl Step for Miri { return None; } - let compilers = - RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target); - let miri = builder.ensure(tool::Miri::from_compilers(compilers)); - let cargomiri = builder.ensure(tool::CargoMiri::from_compilers(compilers)); + let miri = builder.ensure(tool::Miri::from_compilers(self.compilers)); + let cargomiri = builder.ensure(tool::CargoMiri::from_compilers(self.compilers)); let mut tarball = Tarball::new(builder, "miri", &self.target.triple); tarball.set_overlay(OverlayKind::Miri); @@ -1426,11 +1469,15 @@ impl Step for Miri { tarball.add_legal_and_readme_to("share/doc/miri"); Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("miri", self.target).built_by(self.compilers.build_compiler())) + } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct CraneliftCodegenBackend { - pub build_compiler: Compiler, + pub compilers: RustcPrivateCompilers, pub target: TargetSelection, } @@ -1454,11 +1501,7 @@ impl Step for CraneliftCodegenBackend { fn make_run(run: RunConfig<'_>) { run.builder.ensure(CraneliftCodegenBackend { - build_compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), target: run.target, }); } @@ -1472,8 +1515,6 @@ impl Step for CraneliftCodegenBackend { } let target = self.target; - let compilers = - RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target); if !target_supports_cranelift_backend(target) { builder.info("target not supported by rustc_codegen_cranelift. skipping"); return None; @@ -1484,6 +1525,7 @@ impl Step for CraneliftCodegenBackend { tarball.is_preview(true); tarball.add_legal_and_readme_to("share/doc/rustc_codegen_cranelift"); + let compilers = self.compilers; let stamp = builder.ensure(compile::CraneliftCodegenBackend { compilers }); if builder.config.dry_run() { @@ -1513,15 +1555,15 @@ impl Step for CraneliftCodegenBackend { fn metadata(&self) -> Option<StepMetadata> { Some( - StepMetadata::dist("rustc_codegen_cranelift", self.build_compiler.host) - .built_by(self.build_compiler), + StepMetadata::dist("rustc_codegen_cranelift", self.target) + .built_by(self.compilers.build_compiler()), ) } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { - pub build_compiler: Compiler, + pub compilers: RustcPrivateCompilers, pub target: TargetSelection, } @@ -1537,21 +1579,14 @@ impl Step for Rustfmt { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustfmt { - build_compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - let compilers = - RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target); - - let rustfmt = builder.ensure(tool::Rustfmt::from_compilers(compilers)); - let cargofmt = builder.ensure(tool::Cargofmt::from_compilers(compilers)); + let rustfmt = builder.ensure(tool::Rustfmt::from_compilers(self.compilers)); + let cargofmt = builder.ensure(tool::Cargofmt::from_compilers(self.compilers)); let mut tarball = Tarball::new(builder, "rustfmt", &self.target.triple); tarball.set_overlay(OverlayKind::Rustfmt); @@ -1561,12 +1596,16 @@ impl Step for Rustfmt { tarball.add_legal_and_readme_to("share/doc/rustfmt"); Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("rustfmt", self.target).built_by(self.compilers.build_compiler())) + } } +/// Extended archive that contains the compiler, standard library and a bunch of tools. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Extended { - stage: u32, - host: TargetSelection, + build_compiler: Compiler, target: TargetSelection, } @@ -1582,8 +1621,9 @@ impl Step for Extended { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Extended { - stage: run.builder.top_stage, - host: run.builder.config.host_target, + build_compiler: run + .builder + .compiler(run.builder.top_stage - 1, run.builder.host_target), target: run.target, }); } @@ -1591,10 +1631,7 @@ impl Step for Extended { /// Creates a combined installer for the specified target in the provided stage. fn run(self, builder: &Builder<'_>) { let target = self.target; - let stage = self.stage; - let compiler = builder.compiler_for(self.stage, self.host, self.target); - - builder.info(&format!("Dist extended stage{} ({})", compiler.stage, target)); + builder.info(&format!("Dist extended stage{} ({target})", builder.top_stage)); let mut tarballs = Vec::new(); let mut built_tools = HashSet::new(); @@ -1607,34 +1644,38 @@ impl Step for Extended { }; } - let target_compiler = builder.compiler(stage, target); + let rustc_private_compilers = + RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target); + let build_compiler = rustc_private_compilers.build_compiler(); + let target_compiler = rustc_private_compilers.target_compiler(); + // When rust-std package split from rustc, we needed to ensure that during // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. - tarballs.push(builder.ensure(Rustc { compiler: target_compiler })); - tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std")); + tarballs.push(builder.ensure(Rustc { target_compiler })); + tarballs.push(builder.ensure(Std { build_compiler, target }).expect("missing std")); if target.is_windows_gnu() { - tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw")); + tarballs.push(builder.ensure(Mingw { target }).expect("missing mingw")); } add_component!("rust-docs" => Docs { host: target }); // Std stage N is documented with compiler stage N add_component!("rust-json-docs" => JsonDocs { build_compiler: target_compiler, target }); - add_component!("cargo" => Cargo { build_compiler: compiler, target }); - add_component!("rustfmt" => Rustfmt { build_compiler: compiler, target }); - add_component!("rust-analyzer" => RustAnalyzer { build_compiler: compiler, target }); + add_component!("cargo" => Cargo { build_compiler, target }); + add_component!("rustfmt" => Rustfmt { compilers: rustc_private_compilers, target }); + add_component!("rust-analyzer" => RustAnalyzer { compilers: rustc_private_compilers, target }); add_component!("llvm-components" => LlvmTools { target }); - add_component!("clippy" => Clippy { build_compiler: compiler, target }); - add_component!("miri" => Miri { build_compiler: compiler, target }); - add_component!("analysis" => Analysis { compiler, target }); + add_component!("clippy" => Clippy { compilers: rustc_private_compilers, target }); + add_component!("miri" => Miri { compilers: rustc_private_compilers, target }); + add_component!("analysis" => Analysis { build_compiler, target }); add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend { - build_compiler: compiler, + compilers: rustc_private_compilers, target }); add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker { - build_compiler: compiler, + build_compiler, target }); @@ -2100,6 +2141,10 @@ impl Step for Extended { } } } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("extended", self.target).built_by(self.build_compiler)) + } } fn add_env( @@ -2236,6 +2281,7 @@ fn maybe_install_llvm( { trace!("LLVM already built, installing LLVM files"); let mut cmd = command(host_llvm_config); + cmd.cached(); cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); let files = cmd.run_capture_stdout(builder).stdout(); @@ -2562,15 +2608,17 @@ impl Step for RustDev { /// Tarball intended for internal consumption to ease rustc/std development. /// +/// It only packages the binaries that were already compiled when bootstrap itself was built. +/// /// Should not be considered stable by end users. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Bootstrap { - pub target: TargetSelection, + target: TargetSelection, } impl Step for Bootstrap { type Output = Option<GeneratedTarball>; - const DEFAULT: bool = false; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -2597,6 +2645,10 @@ impl Step for Bootstrap { Some(tarball.generate()) } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("bootstrap", self.target)) + } } /// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the @@ -2605,12 +2657,12 @@ impl Step for Bootstrap { /// Should not be considered stable by end users. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct BuildManifest { - pub target: TargetSelection, + target: TargetSelection, } impl Step for BuildManifest { type Output = GeneratedTarball; - const DEFAULT: bool = false; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -2628,16 +2680,20 @@ impl Step for BuildManifest { tarball.add_file(&build_manifest, "bin", FileType::Executable); tarball.generate() } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("build-manifest", self.target)) + } } /// Tarball containing artifacts necessary to reproduce the build of rustc. /// -/// Currently this is the PGO profile data. +/// Currently this is the PGO (and possibly BOLT) profile data. /// /// Should not be considered stable by end users. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct ReproducibleArtifacts { - pub target: TargetSelection, + target: TargetSelection, } impl Step for ReproducibleArtifacts { @@ -2670,6 +2726,10 @@ impl Step for ReproducibleArtifacts { } if added_anything { Some(tarball.generate()) } else { None } } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("reproducible-artifacts", self.target)) + } } /// Tarball containing a prebuilt version of the libgccjit library, @@ -2677,7 +2737,7 @@ impl Step for ReproducibleArtifacts { /// backend needing a prebuilt libLLVM). #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Gcc { - pub target: TargetSelection, + target: TargetSelection, } impl Step for Gcc { @@ -2697,4 +2757,8 @@ impl Step for Gcc { tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary); tarball.generate() } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::dist("gcc", self.target)) + } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 7fe19c00ef5..8c20c8c479a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -784,7 +784,7 @@ fn doc_std( let description = format!("library{} in {} format", crate_description(requested_crates), format.as_str()); - let _guard = builder.msg(Kind::Doc, description, None, build_compiler, target); + let _guard = builder.msg(Kind::Doc, description, Mode::Std, build_compiler, target); cargo.into_cmd().run(builder); builder.cp_link_r(&out_dir, out); @@ -994,7 +994,7 @@ macro_rules! tool_doc { (compilers.build_compiler(), Mode::ToolRustc) } else { // bootstrap/host tools have to be documented with the stage 0 compiler - (prepare_doc_compiler(run.builder, target, 1), Mode::ToolBootstrap) + (prepare_doc_compiler(run.builder, run.builder.host_target, 1), Mode::ToolBootstrap) }; run.builder.ensure($tool { build_compiler, mode, target }); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 4457258e9cd..ce68dbf5a20 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -7,6 +7,7 @@ use std::path::{Component, Path, PathBuf}; use std::{env, fs}; use crate::core::build_steps::dist; +use crate::core::build_steps::tool::RustcPrivateCompilers; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; use crate::utils::exec::command; @@ -64,17 +65,14 @@ fn is_dir_writable_for_user(dir: &Path) -> bool { fn install_sh( builder: &Builder<'_>, package: &str, - stage: u32, - host: Option<TargetSelection>, + build_compiler: impl Into<Option<Compiler>>, + target: Option<TargetSelection>, tarball: &GeneratedTarball, ) { - let _guard = builder.msg( - Kind::Install, - package, - None, - (host.unwrap_or(builder.host_target), stage), - host, - ); + let _guard = match build_compiler.into() { + Some(build_compiler) => builder.msg(Kind::Install, package, None, build_compiler, target), + None => builder.msg_unstaged(Kind::Install, package, target.unwrap_or(builder.host_target)), + }; let prefix = default_path(&builder.config.prefix, "/usr/local"); let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); @@ -166,10 +164,10 @@ macro_rules! install { IS_HOST: $IS_HOST:expr, $run_item:block $(, $c:ident)*;)+) => { $( - #[derive(Debug, Clone, Hash, PartialEq, Eq)] + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { - pub compiler: Compiler, - pub target: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, } impl $name { @@ -193,7 +191,7 @@ macro_rules! install { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), + build_compiler: run.builder.compiler(run.builder.top_stage - 1, run.builder.config.host_target), target: run.target, }); } @@ -208,96 +206,95 @@ macro_rules! install { install!((self, builder, _config), Docs, path = "src/doc", _config.docs, IS_HOST: false, { let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs"); - install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "docs", self.build_compiler, Some(self.target), &tarball); }; Std, path = "library/std", true, IS_HOST: false, { // `expect` should be safe, only None when host != build, but this // only runs when host == build - let tarball = builder.ensure(dist::Std { - compiler: self.compiler, - target: self.target - }).expect("missing std"); - install_sh(builder, "std", self.compiler.stage, Some(self.target), &tarball); + let std = dist::Std::new(builder, self.target); + let build_compiler = std.build_compiler; + let tarball = builder.ensure(std).expect("missing std"); + install_sh(builder, "std", build_compiler, Some(self.target), &tarball); }; Cargo, alias = "cargo", Self::should_build(_config), IS_HOST: true, { let tarball = builder - .ensure(dist::Cargo { build_compiler: self.compiler, target: self.target }) + .ensure(dist::Cargo { build_compiler: self.build_compiler, target: self.target }) .expect("missing cargo"); - install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "cargo", self.build_compiler, Some(self.target), &tarball); }; RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = - builder.ensure(dist::RustAnalyzer { build_compiler: self.compiler, target: self.target }) + builder.ensure(dist::RustAnalyzer { compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target), target: self.target }) { - install_sh(builder, "rust-analyzer", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "rust-analyzer", self.build_compiler, Some(self.target), &tarball); } else { builder.info( - &format!("skipping Install rust-analyzer stage{} ({})", self.compiler.stage, self.target), + &format!("skipping Install rust-analyzer stage{} ({})", self.build_compiler.stage + 1, self.target), ); } }; Clippy, alias = "clippy", Self::should_build(_config), IS_HOST: true, { let tarball = builder - .ensure(dist::Clippy { build_compiler: self.compiler, target: self.target }) + .ensure(dist::Clippy { compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target), target: self.target }) .expect("missing clippy"); - install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "clippy", self.build_compiler, Some(self.target), &tarball); }; Miri, alias = "miri", Self::should_build(_config), IS_HOST: true, { - if let Some(tarball) = builder.ensure(dist::Miri { build_compiler: self.compiler, target: self.target }) { - install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball); + if let Some(tarball) = builder.ensure(dist::Miri { compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target) , target: self.target }) { + install_sh(builder, "miri", self.build_compiler, Some(self.target), &tarball); } else { // Miri is only available on nightly builder.info( - &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target), + &format!("skipping Install miri stage{} ({})", self.build_compiler.stage + 1, self.target), ); } }; LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.host_target), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) { - install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "llvm-tools", None, Some(self.target), &tarball); } else { builder.info( - &format!("skipping llvm-tools stage{} ({}): external LLVM", self.compiler.stage, self.target), + &format!("skipping llvm-tools ({}): external LLVM", self.target), ); } }; Rustfmt, alias = "rustfmt", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::Rustfmt { - build_compiler: self.compiler, + compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target), target: self.target }) { - install_sh(builder, "rustfmt", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "rustfmt", self.build_compiler, Some(self.target), &tarball); } else { builder.info( - &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target), + &format!("skipping Install Rustfmt stage{} ({})", self.build_compiler.stage + 1, self.target), ); } }; Rustc, path = "compiler/rustc", true, IS_HOST: true, { let tarball = builder.ensure(dist::Rustc { - compiler: builder.compiler(builder.top_stage, self.target), + target_compiler: builder.compiler(self.build_compiler.stage + 1, self.target), }); - install_sh(builder, "rustc", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "rustc", self.build_compiler, Some(self.target), &tarball); }; RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend { - build_compiler: self.compiler, + compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target), target: self.target }) { - install_sh(builder, "rustc-codegen-cranelift", self.compiler.stage, Some(self.target), &tarball); + install_sh(builder, "rustc-codegen-cranelift", self.build_compiler, Some(self.target), &tarball); } else { builder.info( &format!("skipping Install CodegenBackend(\"cranelift\") stage{} ({})", - self.compiler.stage, self.target), + self.build_compiler.stage + 1, self.target), ); } }; LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), IS_HOST: true, { - if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { build_compiler: self.compiler, target: self.target }) { - install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball); + if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { build_compiler: self.build_compiler, target: self.target }) { + install_sh(builder, "llvm-bitcode-linker", self.build_compiler, Some(self.target), &tarball); } else { builder.info( - &format!("skipping llvm-bitcode-linker stage{} ({})", self.compiler.stage, self.target), + &format!("skipping llvm-bitcode-linker stage{} ({})", self.build_compiler.stage + 1, self.target), ); } }; @@ -305,7 +302,7 @@ install!((self, builder, _config), #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Src { - pub stage: u32, + stage: u32, } impl Step for Src { @@ -325,6 +322,6 @@ impl Step for Src { fn run(self, builder: &Builder<'_>) { let tarball = builder.ensure(dist::Src); - install_sh(builder, "src", self.stage, None, &tarball); + install_sh(builder, "src", None, None, &tarball); } } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 70259f0d1d7..d47c1495838 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -486,8 +486,11 @@ impl Step for Llvm { let LlvmResult { host_llvm_config, .. } = builder.ensure(Llvm { target: builder.config.host_target }); if !builder.config.dry_run() { - let llvm_bindir = - command(&host_llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); + let llvm_bindir = command(&host_llvm_config) + .arg("--bindir") + .cached() + .run_capture_stdout(builder) + .stdout(); let host_bin = Path::new(llvm_bindir.trim()); cfg.define( "LLVM_TABLEGEN", @@ -593,7 +596,13 @@ impl Step for Llvm { } pub fn get_llvm_version(builder: &Builder<'_>, llvm_config: &Path) -> String { - command(llvm_config).arg("--version").run_capture_stdout(builder).stdout().trim().to_owned() + command(llvm_config) + .arg("--version") + .cached() + .run_capture_stdout(builder) + .stdout() + .trim() + .to_owned() } pub fn get_llvm_version_major(builder: &Builder<'_>, llvm_config: &Path) -> u8 { diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index c6288f63847..d9de6b7ef96 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -5,13 +5,14 @@ use std::path::PathBuf; +use build_helper::exit; use clap_complete::{Generator, shells}; use crate::core::build_steps::dist::distdir; use crate::core::build_steps::test; use crate::core::build_steps::tool::{self, RustcPrivateCompilers, SourceType, Tool}; use crate::core::build_steps::vendor::{Vendor, default_paths_to_vendor}; -use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; +use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata}; use crate::core::config::TargetSelection; use crate::core::config::flags::get_completion; use crate::utils::exec::command; @@ -100,8 +101,17 @@ impl Step for ReplaceVersionPlaceholder { } } +/// Invoke the Miri tool on a specified file. +/// +/// Note that Miri always executed on the host, as it is an interpreter. +/// That means that `x run miri --target FOO` will build miri for the host, +/// prepare a miri sysroot for the target `FOO` and then execute miri with +/// the target `FOO`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Miri { + /// The build compiler that will build miri and the target compiler to which miri links. + compilers: RustcPrivateCompilers, + /// The target which will miri interpret. target: TargetSelection, } @@ -113,14 +123,9 @@ impl Step for Miri { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Miri { target: run.target }); - } - - fn run(self, builder: &Builder<'_>) { - let host = builder.build.host_target; - let target = self.target; + let builder = run.builder; - // `x run` uses stage 0 by default but miri does not work well with stage 0. + // `x run` uses stage 0 by default, but miri does not work well with stage 0. // Change the stage to 1 if it's not set explicitly. let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { builder.top_stage @@ -129,14 +134,22 @@ impl Step for Miri { }; if stage == 0 { - eprintln!("miri cannot be run at stage 0"); - std::process::exit(1); + eprintln!("ERROR: miri cannot be run at stage 0"); + exit!(1); } - // This compiler runs on the host, we'll just use it for the target. - let compilers = RustcPrivateCompilers::new(builder, stage, target); - let miri_build = builder.ensure(tool::Miri::from_compilers(compilers)); - let host_compiler = miri_build.build_compiler; + // Miri always runs on the host, because it can interpret code for any target + let compilers = RustcPrivateCompilers::new(builder, stage, builder.host_target); + + run.builder.ensure(Miri { compilers, target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let host = builder.build.host_target; + let compilers = self.compilers; + let target = self.target; + + builder.ensure(tool::Miri::from_compilers(compilers)); // Get a target sysroot for Miri. let miri_sysroot = @@ -147,7 +160,7 @@ impl Step for Miri { // add_rustc_lib_path does not add the path that contains librustc_driver-<...>.so. let mut miri = tool::prepare_tool_cargo( builder, - host_compiler, + compilers.build_compiler(), Mode::ToolRustc, host, Kind::Run, @@ -167,6 +180,10 @@ impl Step for Miri { miri.into_cmd().run(builder); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::run("miri", self.target).built_by(self.compilers.build_compiler())) + } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 269e7da8d7b..abe79405984 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -153,7 +153,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" } // Build all the default documentation. - builder.default_doc(&[]); + builder.run_default_doc_steps(); // Build the linkchecker before calling `msg`, since GHA doesn't support nested groups. let linkchecker = builder.tool_cmd(Tool::Linkchecker); @@ -208,7 +208,7 @@ impl Step for HtmlCheck { panic!("Cannot run html-check tests"); } // Ensure that a few different kinds of documentation are available. - builder.default_doc(&[]); + builder.run_default_doc_steps(); builder.ensure(crate::core::build_steps::doc::Rustc::for_stage( builder, builder.top_stage, @@ -1719,7 +1719,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the if suite == "debuginfo" { builder.ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler).to_path_buf(), - host: target, + target, }); } if suite == "run-make" { @@ -1850,7 +1850,7 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} // Tells compiletest which codegen backend to use. // It is used to e.g. ignore tests that don't support that codegen backend. cmd.arg("--default-codegen-backend") - .arg(builder.config.default_codegen_backend(compiler.host).unwrap().name()); + .arg(builder.config.default_codegen_backend(compiler.host).name()); } if builder.build.config.llvm_enzyme { @@ -2043,6 +2043,7 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} if !builder.config.dry_run() { let llvm_version = get_llvm_version(builder, &host_llvm_config); let llvm_components = command(&host_llvm_config) + .cached() .arg("--components") .run_capture_stdout(builder) .stdout(); @@ -2062,8 +2063,11 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} // separate compilations. We can add LLVM's library path to the // rustc args as a workaround. if !builder.config.dry_run() && suite.ends_with("fulldeps") { - let llvm_libdir = - command(&host_llvm_config).arg("--libdir").run_capture_stdout(builder).stdout(); + let llvm_libdir = command(&host_llvm_config) + .cached() + .arg("--libdir") + .run_capture_stdout(builder) + .stdout(); let link_llvm = if target.is_msvc() { format!("-Clink-arg=-LIBPATH:{llvm_libdir}") } else { @@ -3117,45 +3121,55 @@ impl Step for Distcheck { /// /// FIXME(#136822): dist components are under-tested. fn run(self, builder: &Builder<'_>) { - builder.info("Distcheck"); - let dir = builder.tempdir().join("distcheck"); - let _ = fs::remove_dir_all(&dir); - t!(fs::create_dir_all(&dir)); - - // Guarantee that these are built before we begin running. - builder.ensure(dist::PlainSourceTarball); - builder.ensure(dist::Src); + // Use a temporary directory completely outside the current checkout, to avoid reusing any + // local source code, built artifacts or configuration by accident + let root_dir = std::env::temp_dir().join("distcheck"); + + // Check that we can build some basic things from the plain source tarball + builder.info("Distcheck plain source tarball"); + let plain_src_tarball = builder.ensure(dist::PlainSourceTarball); + let plain_src_dir = root_dir.join("distcheck-plain-src"); + builder.clear_dir(&plain_src_dir); + + let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS") + .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>()) + .unwrap_or_default(); command("tar") .arg("-xf") - .arg(builder.ensure(dist::PlainSourceTarball).tarball()) + .arg(plain_src_tarball.tarball()) .arg("--strip-components=1") - .current_dir(&dir) + .current_dir(&plain_src_dir) .run(builder); command("./configure") - .args(&builder.config.configure_args) + .arg("--set") + .arg("rust.omit-git-hash=false") + .args(&configure_args) .arg("--enable-vendor") - .current_dir(&dir) + .current_dir(&plain_src_dir) .run(builder); command(helpers::make(&builder.config.host_target.triple)) .arg("check") - .current_dir(&dir) + // Do not run the build as if we were in CI, otherwise git would be assumed to be + // present, but we build from a tarball here + .env("GITHUB_ACTIONS", "0") + .current_dir(&plain_src_dir) .run(builder); // Now make sure that rust-src has all of libstd's dependencies builder.info("Distcheck rust-src"); - let dir = builder.tempdir().join("distcheck-src"); - let _ = fs::remove_dir_all(&dir); - t!(fs::create_dir_all(&dir)); + let src_tarball = builder.ensure(dist::Src); + let src_dir = root_dir.join("distcheck-src"); + builder.clear_dir(&src_dir); command("tar") .arg("-xf") - .arg(builder.ensure(dist::Src).tarball()) + .arg(src_tarball.tarball()) .arg("--strip-components=1") - .current_dir(&dir) + .current_dir(&src_dir) .run(builder); - let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); + let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); command(&builder.initial_cargo) // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. @@ -3163,7 +3177,7 @@ impl Step for Distcheck { .arg("generate-lockfile") .arg("--manifest-path") .arg(&toml) - .current_dir(&dir) + .current_dir(&src_dir) .run(builder); } } diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 7b860ceb943..0e9d4e7e32b 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -19,6 +19,7 @@ pub const VENDOR_DIR: &str = "vendor"; pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<(PathBuf, Vec<&'static str>)> { [ ("src/tools/cargo/Cargo.toml", vec!["src/tools/cargo"]), + ("src/tools/clippy/clippy_test_deps/Cargo.toml", vec![]), ("src/tools/rust-analyzer/Cargo.toml", vec![]), ("compiler/rustc_codegen_cranelift/Cargo.toml", vec![]), ("compiler/rustc_codegen_gcc/Cargo.toml", vec![]), diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 72192403412..cdf6fe573e5 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -132,10 +132,7 @@ impl Cargo { } pub fn into_cmd(self) -> BootstrapCommand { - let mut cmd: BootstrapCommand = self.into(); - // Disable caching for commands originating from Cargo-related operations. - cmd.do_not_cache(); - cmd + self.into() } /// Same as [`Cargo::new`] except this one doesn't configure the linker with @@ -1085,7 +1082,7 @@ impl Builder<'_> { && let Some(llvm_config) = self.llvm_config(target) { let llvm_libdir = - command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout(); + command(llvm_config).cached().arg("--libdir").run_capture_stdout(self).stdout(); if target.is_msvc() { rustflags.arg(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}")); } else { @@ -1326,12 +1323,7 @@ impl Builder<'_> { if let Some(limit) = limit && (build_compiler_stage == 0 - || self - .config - .default_codegen_backend(target) - .cloned() - .unwrap_or_default() - .is_llvm()) + || self.config.default_codegen_backend(target).is_llvm()) { rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}")); } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 40460bf168d..f794f4e079a 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -22,6 +22,7 @@ use crate::core::build_steps::{ }; use crate::core::config::flags::Subcommand; use crate::core::config::{DryRun, TargetSelection}; +use crate::utils::build_stamp::BuildStamp; use crate::utils::cache::Cache; use crate::utils::exec::{BootstrapCommand, ExecutionContext, command}; use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linker_args, t}; @@ -144,8 +145,7 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { } /// Metadata that describes an executed step, mostly for testing and tracing. -#[allow(unused)] -#[derive(Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct StepMetadata { name: String, kind: Kind, @@ -181,6 +181,10 @@ impl StepMetadata { Self::new(name, target, Kind::Test) } + pub fn run(name: &str, target: TargetSelection) -> Self { + Self::new(name, target, Kind::Run) + } + fn new(name: &str, target: TargetSelection, kind: Kind) -> Self { Self { name: name.to_string(), kind, target, built_by: None, stage: None, metadata: None } } @@ -1308,8 +1312,9 @@ impl<'a> Builder<'a> { self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths); } - pub fn default_doc(&self, paths: &[PathBuf]) { - self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths); + /// Run all default documentation steps to build documentation. + pub fn run_default_doc_steps(&self) { + self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]); } pub fn doc_rust_lang_org_channel(&self) -> String { @@ -1411,6 +1416,8 @@ impl<'a> Builder<'a> { /// The standard library will be linked to the sysroot of the passed compiler. /// /// Prefer using this method rather than manually invoking `Std::new`. + /// + /// Returns an optional build stamp, if libstd was indeed built. #[cfg_attr( feature = "tracing", instrument( @@ -1424,29 +1431,38 @@ impl<'a> Builder<'a> { ), ), )] - pub fn std(&self, compiler: Compiler, target: TargetSelection) { + pub fn std(&self, compiler: Compiler, target: TargetSelection) -> Option<BuildStamp> { // FIXME: make the `Std` step return some type-level "proof" that std was indeed built, // and then require passing that to all Cargo invocations that we do. - // The "stage 0" std is always precompiled and comes with the stage0 compiler, so we have - // special logic for it, to avoid creating needless and confusing Std steps that don't + // The "stage 0" std is almost always precompiled and comes with the stage0 compiler, so we + // have special logic for it, to avoid creating needless and confusing Std steps that don't // actually build anything. + // We only allow building the stage0 stdlib if we do a local rebuild, so the stage0 compiler + // actually comes from in-tree sources, and we're cross-compiling, so the stage0 for the + // given `target` is not available. if compiler.stage == 0 { if target != compiler.host { - panic!( - r"It is not possible to build the standard library for `{target}` using the stage0 compiler. + if self.local_rebuild { + self.ensure(Std::new(compiler, target)) + } else { + panic!( + r"It is not possible to build the standard library for `{target}` using the stage0 compiler. You have to build a stage1 compiler for `{}` first, and then use it to build a standard library for `{target}`. +Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler built from in-tree sources. ", - compiler.host - ) + compiler.host + ) + } + } else { + // We still need to link the prebuilt standard library into the ephemeral stage0 sysroot + self.ensure(StdLink::from_std(Std::new(compiler, target), compiler)); + None } - - // We still need to link the prebuilt standard library into the ephemeral stage0 sysroot - self.ensure(StdLink::from_std(Std::new(compiler, target), compiler)); } else { // This step both compiles the std and links it into the compiler's sysroot. // Yes, it's quite magical and side-effecty.. would be nice to refactor later. - self.ensure(Std::new(compiler, target)); + self.ensure(Std::new(compiler, target)) } } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 2afba25ae59..3c2cb782850 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -854,6 +854,18 @@ mod snapshot { } #[test] + fn build_library_stage_0_local_rebuild() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("build") + .path("library") + .stage(0) + .targets(&[TEST_TRIPLE_1]) + .args(&["--set", "build.local-rebuild=true"]) + .render_steps(), @"[build] rustc 0 <host> -> std 0 <target1>"); + } + + #[test] fn build_library_stage_1() { let ctx = TestCtx::new(); insta::assert_snapshot!( @@ -1134,7 +1146,9 @@ mod snapshot { [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> [dist] rustc 1 <host> -> std 1 <host> + [dist] rustc 1 <host> -> rustc-dev 2 <host> [dist] src <> + [dist] reproducible-artifacts <host> " ); } @@ -1196,15 +1210,24 @@ mod snapshot { [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> [dist] rustc 1 <host> -> std 1 <host> + [dist] rustc 1 <host> -> rustc-dev 2 <host> + [dist] rustc 1 <host> -> analysis 2 <host> [dist] src <> [build] rustc 1 <host> -> cargo 2 <host> + [dist] rustc 1 <host> -> cargo 2 <host> [build] rustc 1 <host> -> rust-analyzer 2 <host> + [dist] rustc 1 <host> -> rust-analyzer 2 <host> [build] rustc 1 <host> -> rustfmt 2 <host> [build] rustc 1 <host> -> cargo-fmt 2 <host> + [dist] rustc 1 <host> -> rustfmt 2 <host> [build] rustc 1 <host> -> clippy-driver 2 <host> [build] rustc 1 <host> -> cargo-clippy 2 <host> + [dist] rustc 1 <host> -> clippy 2 <host> [build] rustc 1 <host> -> miri 2 <host> [build] rustc 1 <host> -> cargo-miri 2 <host> + [dist] rustc 1 <host> -> miri 2 <host> + [dist] rustc 1 <host> -> extended 2 <host> + [dist] reproducible-artifacts <host> "); } @@ -1276,7 +1299,9 @@ mod snapshot { [dist] rustc 1 <host> -> std 1 <host> [build] rustc 2 <host> -> std 2 <target1> [dist] rustc 2 <host> -> std 2 <target1> + [dist] rustc 1 <host> -> rustc-dev 2 <host> [dist] src <> + [dist] reproducible-artifacts <host> " ); } @@ -1334,7 +1359,11 @@ mod snapshot { [build] rustdoc 2 <target1> [dist] rustc <target1> [dist] rustc 1 <host> -> std 1 <host> + [dist] rustc 1 <host> -> rustc-dev 2 <host> + [dist] rustc 1 <host> -> rustc-dev 2 <target1> [dist] src <> + [dist] reproducible-artifacts <host> + [dist] reproducible-artifacts <target1> " ); } @@ -1413,7 +1442,11 @@ mod snapshot { [dist] rustc <target1> [dist] rustc 1 <host> -> std 1 <host> [dist] rustc 1 <host> -> std 1 <target1> + [dist] rustc 1 <host> -> rustc-dev 2 <host> + [dist] rustc 1 <host> -> rustc-dev 2 <target1> [dist] src <> + [dist] reproducible-artifacts <host> + [dist] reproducible-artifacts <target1> " ); } @@ -1462,10 +1495,8 @@ mod snapshot { "); } - /// This also serves as an important regression test for <https://github.com/rust-lang/rust/issues/138123> - /// and <https://github.com/rust-lang/rust/issues/138004>. #[test] - fn dist_all_cross() { + fn dist_all_cross_extended() { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx @@ -1518,22 +1549,99 @@ mod snapshot { [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <target1> [dist] rustc 1 <host> -> std 1 <target1> + [dist] rustc 1 <host> -> rustc-dev 2 <target1> + [dist] rustc 1 <host> -> analysis 2 <target1> [dist] src <> [build] rustc 1 <host> -> cargo 2 <target1> + [dist] rustc 1 <host> -> cargo 2 <target1> [build] rustc 1 <host> -> rust-analyzer 2 <target1> + [dist] rustc 1 <host> -> rust-analyzer 2 <target1> [build] rustc 1 <host> -> rustfmt 2 <target1> [build] rustc 1 <host> -> cargo-fmt 2 <target1> + [dist] rustc 1 <host> -> rustfmt 2 <target1> [build] rustc 1 <host> -> clippy-driver 2 <target1> [build] rustc 1 <host> -> cargo-clippy 2 <target1> + [dist] rustc 1 <host> -> clippy 2 <target1> [build] rustc 1 <host> -> miri 2 <target1> [build] rustc 1 <host> -> cargo-miri 2 <target1> + [dist] rustc 1 <host> -> miri 2 <target1> [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <target1> [doc] rustc 2 <target1> -> std 2 <target1> crates=[] + [dist] rustc 1 <host> -> extended 2 <target1> + [dist] reproducible-artifacts <target1> "); } - // Enable dist cranelift tarball by default with `x dist` if cranelift is enabled in - // `rust.codegen-backends`. + /// Simulates e.g. the powerpc64 builder, which is fully cross-compiled from x64, but it does + /// not build docs. Crutically, it shouldn't build host stage 2 rustc. + /// + /// This is a regression test for <https://github.com/rust-lang/rust/issues/138123> + /// and <https://github.com/rust-lang/rust/issues/138004>. + #[test] + fn dist_all_cross_extended_no_docs() { + let ctx = TestCtx::new(); + let steps = ctx + .config("dist") + .hosts(&[TEST_TRIPLE_1]) + .targets(&[TEST_TRIPLE_1]) + .args(&[ + "--set", + "rust.channel=nightly", + "--set", + "build.extended=true", + "--set", + "build.docs=false", + ]) + .get_steps(); + + // Make sure that we don't build stage2 host rustc + steps.assert_no_match(|m| { + m.name == "rustc" + && m.built_by.map(|b| b.stage) == Some(1) + && *m.target.triple == host_target() + }); + + insta::assert_snapshot!( + steps.render(), @r" + [dist] mingw <target1> + [build] llvm <host> + [build] llvm <target1> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 0 <host> -> WasmComponentLd 1 <host> + [build] rustc 1 <host> -> std 1 <target1> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <target1> + [build] rustc 1 <host> -> WasmComponentLd 2 <target1> + [build] rustdoc 2 <target1> + [build] rustc 1 <host> -> rust-analyzer-proc-macro-srv 2 <target1> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> + [dist] rustc <target1> + [dist] rustc 1 <host> -> std 1 <target1> + [dist] rustc 1 <host> -> rustc-dev 2 <target1> + [dist] rustc 1 <host> -> analysis 2 <target1> + [dist] src <> + [build] rustc 1 <host> -> cargo 2 <target1> + [dist] rustc 1 <host> -> cargo 2 <target1> + [build] rustc 1 <host> -> rust-analyzer 2 <target1> + [dist] rustc 1 <host> -> rust-analyzer 2 <target1> + [build] rustc 1 <host> -> rustfmt 2 <target1> + [build] rustc 1 <host> -> cargo-fmt 2 <target1> + [dist] rustc 1 <host> -> rustfmt 2 <target1> + [build] rustc 1 <host> -> clippy-driver 2 <target1> + [build] rustc 1 <host> -> cargo-clippy 2 <target1> + [dist] rustc 1 <host> -> clippy 2 <target1> + [build] rustc 1 <host> -> miri 2 <target1> + [build] rustc 1 <host> -> cargo-miri 2 <target1> + [dist] rustc 1 <host> -> miri 2 <target1> + [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <target1> + [dist] rustc 1 <host> -> extended 2 <target1> + [dist] reproducible-artifacts <target1> + "); + } + + /// Enable dist cranelift tarball by default with `x dist` if cranelift is enabled in + /// `rust.codegen-backends`. #[test] fn dist_cranelift_by_default() { let ctx = TestCtx::new(); @@ -1581,7 +1689,38 @@ mod snapshot { [dist] rustc <host> [dist] rustc 1 <host> -> rustc_codegen_cranelift 2 <host> [dist] rustc 1 <host> -> std 1 <host> + [dist] rustc 1 <host> -> rustc-dev 2 <host> [dist] src <> + [dist] reproducible-artifacts <host> + "); + } + + #[test] + fn dist_bootstrap() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx + .config("dist") + .path("bootstrap") + .render_steps(), @r" + [build] rustc 0 <host> -> RustInstaller 1 <host> + [dist] bootstrap <host> + "); + } + + #[test] + fn dist_library_stage_0_local_rebuild() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("dist") + .path("rust-std") + .stage(0) + .targets(&[TEST_TRIPLE_1]) + .args(&["--set", "build.local-rebuild=true"]) + .render_steps(), @r" + [build] rustc 0 <host> -> std 0 <target1> + [build] rustc 0 <host> -> RustInstaller 1 <host> + [dist] rustc 0 <host> -> std 0 <target1> "); } @@ -2126,6 +2265,214 @@ mod snapshot { [doc] rustc 1 <host> -> reference (book) 2 <host> "); } + + #[test] + fn clippy_ci() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("ci") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 0 <host> -> clippy-driver 1 <host> + [build] rustc 0 <host> -> cargo-clippy 1 <host> + [clippy] rustc 1 <host> -> bootstrap 2 <host> + [clippy] rustc 1 <host> -> std 1 <host> + [clippy] rustc 1 <host> -> rustc 2 <host> + [check] rustc 1 <host> -> rustc 2 <host> + [clippy] rustc 1 <host> -> rustc_codegen_gcc 2 <host> + "); + } + + #[test] + fn clippy_compiler_stage1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("compiler") + .render_steps(), @r" + [build] llvm <host> + [clippy] rustc 0 <host> -> rustc 1 <host> + "); + } + + #[test] + fn clippy_compiler_stage2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("compiler") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 0 <host> -> clippy-driver 1 <host> + [build] rustc 0 <host> -> cargo-clippy 1 <host> + [clippy] rustc 1 <host> -> rustc 2 <host> + "); + } + + #[test] + fn clippy_std_stage1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("std") + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 0 <host> -> clippy-driver 1 <host> + [build] rustc 0 <host> -> cargo-clippy 1 <host> + [clippy] rustc 1 <host> -> std 1 <host> + "); + } + + #[test] + fn clippy_std_stage2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("std") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [build] rustc 1 <host> -> clippy-driver 2 <host> + [build] rustc 1 <host> -> cargo-clippy 2 <host> + [clippy] rustc 2 <host> -> std 2 <host> + "); + } + + #[test] + fn clippy_miri_stage1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("miri") + .stage(1) + .render_steps(), @r" + [build] llvm <host> + [check] rustc 0 <host> -> rustc 1 <host> + [clippy] rustc 0 <host> -> miri 1 <host> + "); + } + + #[test] + fn clippy_miri_stage2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("miri") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [check] rustc 1 <host> -> rustc 2 <host> + [build] rustc 0 <host> -> clippy-driver 1 <host> + [build] rustc 0 <host> -> cargo-clippy 1 <host> + [clippy] rustc 1 <host> -> miri 2 <host> + "); + } + + #[test] + fn clippy_bootstrap() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("bootstrap") + .render_steps(), @"[clippy] rustc 0 <host> -> bootstrap 1 <host>"); + } + + #[test] + fn install_extended() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("install") + .args(&[ + // Using backslashes fails with `--set` + "--set", &format!("install.prefix={}", ctx.dir().display()).replace("\\", "/"), + "--set", &format!("install.sysconfdir={}", ctx.dir().display()).replace("\\", "/"), + "--set", "build.extended=true" + ]) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 0 <host> -> WasmComponentLd 1 <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> + [doc] unstable-book (book) <host> + [build] rustc 1 <host> -> std 1 <host> + [doc] book (book) <host> + [doc] book/first-edition (book) <host> + [doc] book/second-edition (book) <host> + [doc] book/2018-edition (book) <host> + [build] rustdoc 1 <host> + [doc] rustc 1 <host> -> standalone 2 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [build] rustc 1 <host> -> WasmComponentLd 2 <host> + [build] rustdoc 2 <host> + [doc] rustc 2 <host> -> std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 <host> -> error-index 2 <host> + [doc] rustc 1 <host> -> error-index 2 <host> + [doc] nomicon (book) <host> + [doc] rustc 1 <host> -> reference (book) 2 <host> + [doc] rustdoc (book) <host> + [doc] rust-by-example (book) <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [doc] rustc (book) <host> + [doc] cargo (book) <host> + [doc] clippy (book) <host> + [doc] embedded-book (book) <host> + [doc] edition-guide (book) <host> + [doc] style-guide (book) <host> + [doc] rustc 1 <host> -> releases 2 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> + [dist] docs <host> + [dist] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rust-analyzer-proc-macro-srv 2 <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> + [dist] rustc <host> + [build] rustc 1 <host> -> cargo 2 <host> + [dist] rustc 1 <host> -> cargo 2 <host> + [build] rustc 1 <host> -> rust-analyzer 2 <host> + [dist] rustc 1 <host> -> rust-analyzer 2 <host> + [build] rustc 1 <host> -> rustfmt 2 <host> + [build] rustc 1 <host> -> cargo-fmt 2 <host> + [dist] rustc 1 <host> -> rustfmt 2 <host> + [build] rustc 1 <host> -> clippy-driver 2 <host> + [build] rustc 1 <host> -> cargo-clippy 2 <host> + [dist] rustc 1 <host> -> clippy 2 <host> + [build] rustc 1 <host> -> miri 2 <host> + [build] rustc 1 <host> -> cargo-miri 2 <host> + [dist] rustc 1 <host> -> miri 2 <host> + [dist] src <> + "); + } + + // Check that `x run miri --target FOO` actually builds miri for the host. + #[test] + fn run_miri() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("run") + .path("miri") + .stage(1) + .targets(&[TEST_TRIPLE_1]) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 0 <host> -> miri 1 <host> + [build] rustc 0 <host> -> cargo-miri 1 <host> + [run] rustc 0 <host> -> miri 1 <target1> + "); + } } struct ExecutedSteps { @@ -2180,6 +2527,21 @@ impl ExecutedSteps { } } + /// Make sure that no metadata matches the given `func`. + #[track_caller] + fn assert_no_match<F>(&self, func: F) + where + F: Fn(StepMetadata) -> bool, + { + for metadata in self.steps.iter().filter_map(|s| s.metadata.clone()) { + if func(metadata.clone()) { + panic!( + "Metadata {metadata:?} was found, even though it should have not been present" + ); + } + } + } + fn contains(&self, metadata: &StepMetadata) -> bool { self.steps .iter() diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 84c9f9cc4d2..a8eb563015f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -46,8 +46,8 @@ use crate::core::config::toml::rust::{ }; use crate::core::config::toml::target::Target; use crate::core::config::{ - DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, - StringOrBool, threads_from_config, + CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, + RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, }; use crate::core::download::{ DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt, @@ -121,8 +121,7 @@ pub struct Config { pub patch_binaries_for_nix: Option<bool>, pub stage0_metadata: build_helper::stage0_parser::Stage0, pub android_ndk: Option<PathBuf>, - /// Whether to use the `c` feature of the `compiler_builtins` crate. - pub optimized_compiler_builtins: bool, + pub optimized_compiler_builtins: CompilerBuiltins, pub stdout_is_tty: bool, pub stderr_is_tty: bool, @@ -961,8 +960,8 @@ impl Config { Subcommand::Dist => flags_stage.or(build_dist_stage).unwrap_or(2), Subcommand::Install => flags_stage.or(build_install_stage).unwrap_or(2), Subcommand::Perf { .. } => flags_stage.unwrap_or(1), - // These are all bootstrap tools, which don't depend on the compiler. - // The stage we pass shouldn't matter, but use 0 just in case. + // Most of the run commands execute bootstrap tools, which don't depend on the compiler. + // Other commands listed here should always use bootstrap tools. Subcommand::Clean { .. } | Subcommand::Run { .. } | Subcommand::Setup { .. } @@ -970,23 +969,38 @@ impl Config { | Subcommand::Vendor { .. } => flags_stage.unwrap_or(0), }; - // Now check that the selected stage makes sense, and if not, print a warning and end + let local_rebuild = build_local_rebuild.unwrap_or(false); + + let check_stage0 = |kind: &str| { + if local_rebuild { + eprintln!("WARNING: running {kind} in stage 0. This might not work as expected."); + } else { + eprintln!( + "ERROR: cannot {kind} anything on stage 0. Use at least stage 1 or set build.local-rebuild=true and use a stage0 compiler built from in-tree sources." + ); + exit!(1); + } + }; + + // Now check that the selected stage makes sense, and if not, print an error and end match (stage, &flags_cmd) { (0, Subcommand::Build { .. }) => { - eprintln!("ERROR: cannot build anything on stage 0. Use at least stage 1."); - exit!(1); + check_stage0("build"); } (0, Subcommand::Check { .. }) => { - eprintln!("ERROR: cannot check anything on stage 0. Use at least stage 1."); - exit!(1); + check_stage0("check"); } (0, Subcommand::Doc { .. }) => { - eprintln!("ERROR: cannot document anything on stage 0. Use at least stage 1."); - exit!(1); + check_stage0("doc"); } (0, Subcommand::Clippy { .. }) => { - eprintln!("ERROR: cannot run clippy on stage 0. Use at least stage 1."); - exit!(1); + check_stage0("clippy"); + } + (0, Subcommand::Dist) => { + check_stage0("dist"); + } + (0, Subcommand::Install) => { + check_stage0("install"); } _ => {} } @@ -1101,7 +1115,11 @@ impl Config { let rustfmt_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rustfmt")); let optimized_compiler_builtins = - build_optimized_compiler_builtins.unwrap_or(channel != "dev"); + build_optimized_compiler_builtins.unwrap_or(if channel == "dev" { + CompilerBuiltins::BuildRustOnly + } else { + CompilerBuiltins::BuildLLVMFuncs + }); let vendor = build_vendor.unwrap_or( rust_info.is_from_tarball() && src.join("vendor").exists() @@ -1223,7 +1241,7 @@ impl Config { llvm_use_libcxx: llvm_use_libcxx.unwrap_or(false), llvm_use_linker, llvm_version_suffix, - local_rebuild: build_local_rebuild.unwrap_or(false), + local_rebuild, locked_deps: build_locked_deps.unwrap_or(false), low_priority: build_low_priority.unwrap_or(false), mandir: install_mandir.map(PathBuf::from), @@ -1652,8 +1670,9 @@ impl Config { /// Returns the codegen backend that should be configured as the *default* codegen backend /// for a rustc compiled by bootstrap. - pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<&CodegenBackendKind> { - self.enabled_codegen_backends(target).first() + pub fn default_codegen_backend(&self, target: TargetSelection) -> &CodegenBackendKind { + // We're guaranteed to have always at least one codegen backend listed. + self.enabled_codegen_backends(target).first().unwrap() } pub fn jemalloc(&self, target: TargetSelection) -> bool { @@ -1664,11 +1683,11 @@ impl Config { self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath) } - pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool { + pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> &CompilerBuiltins { self.target_config .get(&target) - .and_then(|t| t.optimized_compiler_builtins) - .unwrap_or(self.optimized_compiler_builtins) + .and_then(|t| t.optimized_compiler_builtins.as_ref()) + .unwrap_or(&self.optimized_compiler_builtins) } pub fn llvm_enabled(&self, target: TargetSelection) -> bool { diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index dbd05fd2519..5999348a7fe 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -218,6 +218,33 @@ impl<T> Merge for Option<T> { } } +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub enum CompilerBuiltins { + #[default] + // Only build native rust intrinsic compiler functions. + BuildRustOnly, + // Some intrinsic functions have a C implementation provided by LLVM's + // compiler-rt builtins library. Build them from the LLVM source included + // with Rust. + BuildLLVMFuncs, + // Similar to BuildLLVMFuncs, but specify a path to an existing library + // containing LLVM's compiler-rt builtins instead of compiling them. + LinkLLVMBuiltinsLib(String), +} + +impl<'de> Deserialize<'de> for CompilerBuiltins { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + Ok(match Deserialize::deserialize(deserializer)? { + StringOrBool::Bool(false) => Self::BuildRustOnly, + StringOrBool::Bool(true) => Self::BuildLLVMFuncs, + StringOrBool::String(path) => Self::LinkLLVMBuiltinsLib(path), + }) + } +} + #[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] pub enum DebuginfoLevel { #[default] diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 50eba12aba7..e93525fbd09 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -17,7 +17,7 @@ use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; use crate::core::config::toml::TomlConfig; -use crate::core::config::{LldMode, Target, TargetSelection}; +use crate::core::config::{CompilerBuiltins, LldMode, StringOrBool, Target, TargetSelection}; use crate::utils::tests::git::git_test; pub(crate) fn parse(config: &str) -> Config { @@ -183,7 +183,11 @@ runner = "x86_64-runner" ); assert_eq!(config.gdb, Some("bar".into()), "setting string value with quotes"); assert!(!config.deny_warnings, "setting boolean value"); - assert!(config.optimized_compiler_builtins, "setting boolean value"); + assert_eq!( + config.optimized_compiler_builtins, + CompilerBuiltins::BuildLLVMFuncs, + "setting boolean value" + ); assert_eq!( config.tools, Some(["cargo".to_string()].into_iter().collect()), @@ -212,7 +216,7 @@ runner = "x86_64-runner" let darwin = TargetSelection::from_user("aarch64-apple-darwin"); let darwin_values = Target { runner: Some("apple".into()), - optimized_compiler_builtins: Some(false), + optimized_compiler_builtins: Some(CompilerBuiltins::BuildRustOnly), ..Default::default() }; assert_eq!( diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 728367b3972..25c19f1070a 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use serde::{Deserialize, Deserializer}; use crate::core::config::toml::ReplaceOpt; -use crate::core::config::{Merge, StringOrBool}; +use crate::core::config::{CompilerBuiltins, Merge, StringOrBool}; use crate::{HashSet, PathBuf, define_config, exit}; define_config! { @@ -65,7 +65,7 @@ define_config! { // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally metrics: Option<bool> = "metrics", android_ndk: Option<PathBuf> = "android-ndk", - optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins", + optimized_compiler_builtins: Option<CompilerBuiltins> = "optimized-compiler-builtins", jobs: Option<u32> = "jobs", compiletest_diff_tool: Option<String> = "compiletest-diff-tool", compiletest_allow_stage0: Option<bool> = "compiletest-allow-stage0", diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 3dab8d1d96d..c54df456d52 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -269,9 +269,9 @@ pub fn check_incompatible_options_for_ci_rustc( err!(current_profiler, profiler, "build"); let current_optimized_compiler_builtins = - current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins.clone()); let optimized_compiler_builtins = - ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins.clone()); err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build"); // We always build the in-tree compiler on cross targets, so we only care @@ -415,6 +415,10 @@ pub(crate) fn parse_codegen_backends( }; found_backends.push(backend); } + if found_backends.is_empty() { + eprintln!("ERROR: `{section}.codegen-backends` should not be set to `[]`"); + exit!(1); + } found_backends } diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 2c06fd083a8..020602e6a19 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -11,7 +11,9 @@ use serde::{Deserialize, Deserializer}; -use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool}; +use crate::core::config::{ + CompilerBuiltins, LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool, +}; use crate::{CodegenBackendKind, HashSet, PathBuf, define_config, exit}; define_config! { @@ -39,7 +41,7 @@ define_config! { no_std: Option<bool> = "no-std", codegen_backends: Option<Vec<String>> = "codegen-backends", runner: Option<String> = "runner", - optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins", + optimized_compiler_builtins: Option<CompilerBuiltins> = "optimized-compiler-builtins", jemalloc: Option<bool> = "jemalloc", } } @@ -71,7 +73,7 @@ pub struct Target { pub runner: Option<String>, pub no_std: bool, pub codegen_backends: Option<Vec<CodegenBackendKind>>, - pub optimized_compiler_builtins: Option<bool>, + pub optimized_compiler_builtins: Option<CompilerBuiltins>, pub jemalloc: Option<bool>, } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index de7cada93f2..099ec488397 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -18,7 +18,7 @@ use crate::builder::Builder; use crate::builder::Kind; #[cfg(not(test))] use crate::core::build_steps::tool; -use crate::core::config::Target; +use crate::core::config::{CompilerBuiltins, Target}; use crate::utils::exec::command; use crate::{Build, Subcommand}; @@ -34,6 +34,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ "armv7a-vex-v5", + "riscv64a23-unknown-linux-gnu", // just a dummy comment so the list doesn't get onelined "aarch64_be-unknown-hermit", "aarch64_be-unknown-none-softfloat", @@ -330,7 +331,8 @@ than building it. // compiler-rt c fallbacks for wasm cannot be built with gcc if target.contains("wasm") - && (build.config.optimized_compiler_builtins(*target) + && (*build.config.optimized_compiler_builtins(*target) + != CompilerBuiltins::BuildRustOnly || build.config.rust_std_features.contains("compiler-builtins-c")) { let cc_tool = build.cc_tool(*target); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ec7edbf7531..b8ee83b20e4 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1950,6 +1950,20 @@ impl Build { t!(fs::remove_dir_all(dir)) } + /// Make sure that `dir` will be an empty existing directory after this function ends. + /// If it existed before, it will be first deleted. + fn clear_dir(&self, dir: &Path) { + if self.config.dry_run() { + return; + } + + #[cfg(feature = "tracing")] + let _span = trace_io!("dir-clear", ?dir); + + let _ = std::fs::remove_dir_all(dir); + self.create_dir(dir); + } + fn read_dir(&self, dir: &Path) -> impl Iterator<Item = fs::DirEntry> { let iter = match fs::read_dir(dir) { Ok(v) => v, diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index 6c79385190e..4c35388a181 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -136,13 +136,13 @@ pub fn codegen_backend_stamp( } /// Cargo's output path for the standard library in a given stage, compiled -/// by a particular compiler for the specified target. +/// by a particular `build_compiler` for the specified `target`. pub fn libstd_stamp( builder: &Builder<'_>, - compiler: Compiler, + build_compiler: Compiler, target: TargetSelection, ) -> BuildStamp { - BuildStamp::new(&builder.cargo_out(compiler, Mode::Std, target)).with_prefix("libstd") + BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Std, target)).with_prefix("libstd") } /// Cargo's output path for librustc in a given stage, compiled by a particular diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 4fb5891ed18..606d88d3db4 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -516,4 +516,19 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Build/check now supports forwarding `--timings` flag to cargo.", }, + ChangeInfo { + change_id: 145472, + severity: ChangeSeverity::Warning, + summary: "It is no longer possible to `x dist` or `x install` with stage 0. All dist and install commands have to be on stage 1+.", + }, + ChangeInfo { + change_id: 143689, + severity: ChangeSeverity::Info, + summary: "The `optimized-compiler-builtins` option now accepts a path to an existing compiler-rt builtins library.", + }, + ChangeInfo { + change_id: 145876, + severity: ChangeSeverity::Info, + summary: "It is now possible to `check/build/dist` the standard stage 0 library if you use a stage0 rustc built from in-tree sources. This is useful for quickly cross-compiling the standard library. You have to enable build.local-rebuild for this to work.", + }, ]; diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 9a536f75ab7..e09f3086b77 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -264,8 +264,11 @@ impl<'a> BootstrapCommand { self } - pub fn do_not_cache(&mut self) -> &mut Self { - self.should_cache = false; + /// Cache the command. If it will be executed multiple times with the exact same arguments + /// and environment variables in the same bootstrap invocation, the previous result will be + /// loaded from memory. + pub fn cached(&mut self) -> &mut Self { + self.should_cache = true; self } @@ -425,7 +428,7 @@ impl From<Command> for BootstrapCommand { fn from(command: Command) -> Self { let program = command.get_program().to_owned(); Self { - should_cache: true, + should_cache: false, command, failure_behavior: BehaviorOnFailure::Exit, run_in_dry_run: false, diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 451482717b6..e802c0214dd 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -510,6 +510,8 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { #[track_caller] pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { let mut git = command("git"); + // git commands are almost always read-only, so cache them by default + git.cached(); if let Some(source_dir) = source_dir { git.current_dir(source_dir); diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index 983680b0385..3332187e2a8 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -31,6 +31,10 @@ impl TestCtx { Self { directory } } + pub fn dir(&self) -> &Path { + self.directory.path() + } + /// Starts a new invocation of bootstrap that executes `kind` as its top level command /// (i.e. `x <kind>`). Returns a builder that configures the created config through CLI flags. pub fn config(&self, kind: &str) -> ConfigBuilder { diff --git a/src/build_helper/src/npm.rs b/src/build_helper/src/npm.rs index 86cf6183bd0..5a7df0999bd 100644 --- a/src/build_helper/src/npm.rs +++ b/src/build_helper/src/npm.rs @@ -27,7 +27,7 @@ pub fn install(src_root_path: &Path, out_dir: &Path, npm: &Path) -> Result<PathB } // disable a bunch of things we don't want. // this makes tidy output less noisy, and also significantly improves runtime - // of repeated tidy invokations. + // of repeated tidy invocations. cmd.args(&["--audit=false", "--save=false", "--fund=false"]); cmd.current_dir(out_dir); let exit_status = cmd.spawn()?.wait()?; diff --git a/src/ci/docker/host-x86_64/dist-aarch64-windows-gnullvm/Dockerfile b/src/ci/docker/host-x86_64/dist-aarch64-windows-gnullvm/Dockerfile index cdbc1cda025..0bb51af817a 100644 --- a/src/ci/docker/host-x86_64/dist-aarch64-windows-gnullvm/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-aarch64-windows-gnullvm/Dockerfile @@ -26,23 +26,10 @@ ENV CC_aarch64_pc_windows_gnullvm=aarch64-w64-mingw32-clang \ ENV HOST=aarch64-pc-windows-gnullvm -# We are bootstrapping this target and cannot use previously built artifacts. -# Without this option Clang is given `"-I/checkout/obj/build/aarch64-pc-windows-gnullvm/ci-llvm/include"` -# despite no such directory existing: -# $ ls obj/dist-windows-gnullvm/build/aarch64-pc-windows-gnullvm/ -1 -# llvm -# stage2 -ENV NO_DOWNLOAD_CI_LLVM 1 - ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ + --enable-full-tools \ --enable-profiler \ --enable-sanitizers \ - --disable-docs \ - --set llvm.download-ci-llvm=false \ - --set rust.llvm-tools=false -# LLVM cross tools are not installed into expected location so copying fails. -# Probably will solve itself once this target can host itself on Windows. -# --enable-full-tools \ + --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOST --target $HOST diff --git a/src/ci/docker/host-x86_64/dist-x86_64-windows-gnullvm/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-windows-gnullvm/Dockerfile index 1ee3951beb5..da0c065c854 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-windows-gnullvm/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-windows-gnullvm/Dockerfile @@ -28,23 +28,10 @@ ENV CC_i686_pc_windows_gnullvm=i686-w64-mingw32-clang \ ENV HOST=x86_64-pc-windows-gnullvm ENV TARGETS=i686-pc-windows-gnullvm,x86_64-pc-windows-gnullvm -# We are bootstrapping this target and cannot use previously built artifacts. -# Without this option Clang is given `"-I/checkout/obj/build/aarch64-pc-windows-gnullvm/ci-llvm/include"` -# despite no such directory existing: -# $ ls obj/dist-windows-gnullvm/build/aarch64-pc-windows-gnullvm/ -1 -# llvm -# stage2 -ENV NO_DOWNLOAD_CI_LLVM 1 - ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ + --enable-full-tools \ --enable-profiler \ --enable-sanitizers \ - --disable-docs \ - --set llvm.download-ci-llvm=false \ - --set rust.llvm-tools=false -# LLVM cross tools are not installed into expected location so copying fails. -# Probably will solve itself once these targets can host themselves on Windows. -# --enable-full-tools \ + --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOST --target $TARGETS diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index b97568b0819..5052d86f0ac 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -38,11 +38,15 @@ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ --enable-lld \ + --set rust.debuginfo-level-tests=1 \ --set llvm.use-linker=lld \ --set target.x86_64-unknown-linux-gnu.linker=clang \ --set target.x86_64-unknown-linux-gnu.cc=clang \ --set target.x86_64-unknown-linux-gnu.cxx=clang++ +# This job checks: +# - That ui tests can be built with `-Cdebuginfo=1` + # This job appears to be checking two separate things: # - That we can build the compiler with `--enable-debug` # (without necessarily testing the result). @@ -51,4 +55,5 @@ ENV RUST_CONFIGURE_ARGS \ ENV SCRIPT \ python3 ../x.py --stage 2 build && \ + python3 ../x.py --stage 2 test tests/ui && \ python3 ../x.py --stage 2 test tests/run-make diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 98fd31a22e9..5bafd89cfd9 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -33,9 +33,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -# We are disabling CI LLVM since distcheck is an offline build. -ENV NO_DOWNLOAD_CI_LLVM 1 +# Make distcheck builds faster +ENV DISTCHECK_CONFIGURE_ARGS "--enable-sccache" -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.omit-git-hash=false -ENV SCRIPT python3 ../x.py --stage 2 test distcheck -ENV DIST_SRC 1 +ENV SCRIPT python3 ../x.py test distcheck diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 409d2cba821..35b9456d37d 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -104,10 +104,10 @@ jobs: # These jobs automatically inherit envs.pr, to avoid repeating it in each job # definition. # -# PR CI jobs will be automatically registered as Auto CI jobs or overriden. When +# PR CI jobs will be automatically registered as Auto CI jobs or overridden. When # automatically registered, the PR CI job configuration will be copied as an -# Auto CI job but with `continue_on_error` overriden to `false` (to fail-fast). -# When overriden, `citool` will check for equivalence between the PR and CI job +# Auto CI job but with `continue_on_error` overridden to `false` (to fail-fast). +# When overridden, `citool` will check for equivalence between the PR and CI job # of the same name modulo `continue_on_error` and `env`. pr: - name: pr-check-1 @@ -166,7 +166,7 @@ optional: # # Auto jobs may not specify `continue_on_error: true`, and thus will fail-fast. # -# Unless explicitly overriden, PR CI jobs will be automatically registered as +# Unless explicitly overridden, PR CI jobs will be automatically registered as # Auto CI jobs. auto: ############################# diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh index 32649fe0d9b..ac3c9cfb28b 100755 --- a/src/ci/scripts/free-disk-space-linux.sh +++ b/src/ci/scripts/free-disk-space-linux.sh @@ -221,10 +221,13 @@ cleanPackages() { ) fi - sudo apt-get -qq remove -y --fix-missing "${packages[@]}" + WAIT_DPKG_LOCK="-o DPkg::Lock::Timeout=60" + sudo apt-get ${WAIT_DPKG_LOCK} -qq remove -y --fix-missing "${packages[@]}" - sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed" - sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed failed" + sudo apt-get ${WAIT_DPKG_LOCK} autoremove -y \ + || echo "::warning::The command [sudo apt-get autoremove -y] failed" + sudo apt-get ${WAIT_DPKG_LOCK} clean \ + || echo "::warning::The command [sudo apt-get clean] failed" } # Remove Docker images. diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 3ff384320598bbe8d8cfe5cb8f18f78a3a3e6b1 +Subproject 57ed4473660565d9357fcae176b358d7e8724eb diff --git a/src/doc/reference b/src/doc/reference -Subproject 59b8af811886313577615c2cf0e045f01faed88 +Subproject 89f67b3c1b904cbcd9ed55e443d6fc67c8ca276 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject adc1f3b9012ad3255eea2054ca30596a953d053 +Subproject ad27f82c18464525c761a4a8db2e01785da59e1 diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index a399b5cd77e..f412399cc8c 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -425a9c0a0e365c0b8c6cfd00c2ded83a73bed9a0 +a1dbb443527bd126452875eb5d5860c1d001d761 diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 025a078ae5b..a1612738537 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -103,6 +103,7 @@ - [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md) - [GPU offload internals](./offload/internals.md) - [Installation](./offload/installation.md) + - [Usage](./offload/usage.md) - [Autodiff internals](./autodiff/internals.md) - [Installation](./autodiff/installation.md) - [How to debug](./autodiff/debugging.md) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index da425d8d39b..bfd75ebda40 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -23,7 +23,7 @@ Note that this documentation mostly covers user-facing information. See ### Overview -- Stage 0: the pre-compiled compiler +- Stage 0: the pre-compiled compiler and standard library - Stage 1: from current code, by an earlier compiler - Stage 2: the truly current compiler - Stage 3: the same-result test @@ -192,7 +192,7 @@ include, but are not limited to: artifacts'). If you're working on the standard library, this is normally the test command you want. - `./x build --stage 0` means to build with the stage0 `rustc`. -- `./x doc --stage 0` means to document using the stage0 `rustdoc`. +- `./x doc --stage 1` means to document using the stage0 `rustdoc`. #### Examples of what *not* to do @@ -211,7 +211,7 @@ include, but are not limited to: In short, _stage 0 uses the `stage0` compiler to create `stage0` artifacts which will later be uplifted to be the stage1 compiler_. -In each stage, two major steps are performed: +In each stage besides 0, two major steps are performed: 1. `std` is compiled by the stage N compiler. 2. That `std` is linked to programs built by the stage N compiler, including the diff --git a/src/doc/rustc-dev-guide/src/img/coverage-branch-counting-01.png b/src/doc/rustc-dev-guide/src/img/coverage-branch-counting-01.png index c445f3552a6..7c6c845f2cb 100644 --- a/src/doc/rustc-dev-guide/src/img/coverage-branch-counting-01.png +++ b/src/doc/rustc-dev-guide/src/img/coverage-branch-counting-01.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/dataflow-graphviz-example.png b/src/doc/rustc-dev-guide/src/img/dataflow-graphviz-example.png index 718411a8c42..7baa37e4323 100644 --- a/src/doc/rustc-dev-guide/src/img/dataflow-graphviz-example.png +++ b/src/doc/rustc-dev-guide/src/img/dataflow-graphviz-example.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/github-cli.png b/src/doc/rustc-dev-guide/src/img/github-cli.png index c3b0e7707eb..88ba95f90a8 100644 --- a/src/doc/rustc-dev-guide/src/img/github-cli.png +++ b/src/doc/rustc-dev-guide/src/img/github-cli.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/github-whitespace-changes.png b/src/doc/rustc-dev-guide/src/img/github-whitespace-changes.png index 9a19a10aace..e235a30b33e 100644 --- a/src/doc/rustc-dev-guide/src/img/github-whitespace-changes.png +++ b/src/doc/rustc-dev-guide/src/img/github-whitespace-changes.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/llvm-cov-show-01.png b/src/doc/rustc-dev-guide/src/img/llvm-cov-show-01.png index 35f04594347..ce4dec128b6 100644 --- a/src/doc/rustc-dev-guide/src/img/llvm-cov-show-01.png +++ b/src/doc/rustc-dev-guide/src/img/llvm-cov-show-01.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/other-peoples-commits.png b/src/doc/rustc-dev-guide/src/img/other-peoples-commits.png index e4fc2c7972e..0c949d8844d 100644 --- a/src/doc/rustc-dev-guide/src/img/other-peoples-commits.png +++ b/src/doc/rustc-dev-guide/src/img/other-peoples-commits.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/rustbot-submodules.png b/src/doc/rustc-dev-guide/src/img/rustbot-submodules.png index c2e6937cbeb..c099fdfcb46 100644 --- a/src/doc/rustc-dev-guide/src/img/rustbot-submodules.png +++ b/src/doc/rustc-dev-guide/src/img/rustbot-submodules.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/submodule-conflicts.png b/src/doc/rustc-dev-guide/src/img/submodule-conflicts.png index e90a6bbe8fd..5d4caf0b142 100644 --- a/src/doc/rustc-dev-guide/src/img/submodule-conflicts.png +++ b/src/doc/rustc-dev-guide/src/img/submodule-conflicts.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/wpa-initial-memory.png b/src/doc/rustc-dev-guide/src/img/wpa-initial-memory.png index b6020667ef0..177d92c794c 100644 --- a/src/doc/rustc-dev-guide/src/img/wpa-initial-memory.png +++ b/src/doc/rustc-dev-guide/src/img/wpa-initial-memory.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/img/wpa-stack.png b/src/doc/rustc-dev-guide/src/img/wpa-stack.png index 29eb5a54b5d..a4a71358ac1 100644 --- a/src/doc/rustc-dev-guide/src/img/wpa-stack.png +++ b/src/doc/rustc-dev-guide/src/img/wpa-stack.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md index 54d6d2b4e81..96f12b76416 100644 --- a/src/doc/rustc-dev-guide/src/macro-expansion.md +++ b/src/doc/rustc-dev-guide/src/macro-expansion.md @@ -517,8 +517,9 @@ We use these items in macro parser: are about to ask the MBE parser to parse. We will consume the raw stream of tokens and output a binding of metavariables to corresponding token trees. The parsing session can be used to report parser errors. -- a `matcher` variable is a sequence of [`MatcherLoc`]s that we want to match - the token stream against. They're converted from token trees before matching. +- a `matcher` variable is a sequence of [`MatcherLoc`]s that we want to match the token stream + against. They're converted from the original token trees in the macro's definition before + matching. [`MatcherLoc`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/mbe/macro_parser/enum.MatcherLoc.html @@ -544,41 +545,26 @@ The full interface is defined [here][code_parse_int]. The macro parser does pretty much exactly the same as a normal regex parser with one exception: in order to parse different types of metavariables, such as `ident`, `block`, `expr`, etc., the macro parser must call back to the normal -Rust parser. Both the definition and invocation of macros are parsed using -the parser in a process which is non-intuitively self-referential. - -The code to parse macro _definitions_ is in -[`compiler/rustc_expand/src/mbe/macro_rules.rs`][code_mr]. It defines the -pattern for matching a macro definition as `$( $lhs:tt => $rhs:tt );+`. In -other words, a `macro_rules` definition should have in its body at least one -occurrence of a token tree followed by `=>` followed by another token tree. -When the compiler comes to a `macro_rules` definition, it uses this pattern to -match the two token trees per the rules of the definition of the macro, _thereby -utilizing the macro parser itself_. In our example definition, the -metavariable `$lhs` would match the patterns of both arms: `(print -$mvar:ident)` and `(print twice $mvar:ident)`. And `$rhs` would match the -bodies of both arms: `{ println!("{}", $mvar); }` and `{ println!("{}", $mvar); -println!("{}", $mvar); }`. The parser keeps this knowledge around for when it -needs to expand a macro invocation. - -When the compiler comes to a macro invocation, it parses that invocation using -a NFA-based macro parser described above. However, the matcher variable -used is the first token tree (`$lhs`) extracted from the arms of the macro -_definition_. Using our example, we would try to match the token stream `print -foo` from the invocation against the matchers `print $mvar:ident` and `print -twice $mvar:ident` that we previously extracted from the definition. The -algorithm is exactly the same, but when the macro parser comes to a place in the -current matcher where it needs to match a _non-terminal_ (e.g. `$mvar:ident`), -it calls back to the normal Rust parser to get the contents of that -non-terminal. In this case, the Rust parser would look for an `ident` token, -which it finds (`foo`) and returns to the macro parser. Then, the macro parser -proceeds in parsing as normal. Also, note that exactly one of the matchers from -the various arms should match the invocation; if there is more than one match, -the parse is ambiguous, while if there are no matches at all, there is a syntax +Rust parser. + +The code to parse macro definitions is in [`compiler/rustc_expand/src/mbe/macro_rules.rs`][code_mr]. +For more information about the macro parser's implementation, see the comments in +[`compiler/rustc_expand/src/mbe/macro_parser.rs`][code_mp]. + +Using our example, we would try to match the token stream `print foo` from the invocation against +the matchers `print $mvar:ident` and `print twice $mvar:ident` that we previously extracted from the +rules in the macro definition. When the macro parser comes to a place in the current matcher where +it needs to match a _non-terminal_ (e.g. `$mvar:ident`), it calls back to the normal Rust parser to +get the contents of that non-terminal. In this case, the Rust parser would look for an `ident` +token, which it finds (`foo`) and returns to the macro parser. Then, the macro parser continues +parsing. + +Note that exactly one of the matchers from the various rules should match the invocation; if there is +more than one match, the parse is ambiguous, while if there are no matches at all, there is a syntax error. -For more information about the macro parser's implementation, see the comments -in [`compiler/rustc_expand/src/mbe/macro_parser.rs`][code_mp]. +Assuming exactly one rule matches, macro expansion will then *transcribe* the right-hand side of the +rule, substituting the values of any matches it captured when matching against the left-hand side. ## Procedural Macros diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md index b376e962ff6..d1ebf33ac17 100644 --- a/src/doc/rustc-dev-guide/src/offload/installation.md +++ b/src/doc/rustc-dev-guide/src/offload/installation.md @@ -1,6 +1,6 @@ # Installation -In the future, `std::offload` should become available in nightly builds for users. For now, everyone still needs to build rustc from source. +`std::offload` is partly available in nightly builds for users. For now, everyone however still needs to build rustc from source to use all features of it. ## Build instructions @@ -42,30 +42,3 @@ run ``` ./x test --stage 1 tests/codegen-llvm/gpu_offload ``` - -## Usage -It is important to use a clang compiler build on the same llvm as rustc. Just calling clang without the full path will likely use your system clang, which probably will be incompatible. -``` -/absolute/path/to/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc --edition=2024 --crate-type cdylib src/main.rs --emit=llvm-ir -O -C lto=fat -Cpanic=abort -Zoffload=Enable -/absolute/path/to/rust/build/x86_64-unknown-linux-gnu/llvm/bin/clang++ -fopenmp --offload-arch=native -g -O3 main.ll -o main -save-temps -LIBOMPTARGET_INFO=-1 ./main -``` -The first step will generate a `main.ll` file, which has enough instructions to cause the offload runtime to move data to and from a gpu. -The second step will use clang as the compilation driver to compile our IR file down to a working binary. Only a very small Rust subset will work out of the box here, unless -you use features like build-std, which are not covered by this guide. Look at the codegen test to get a feeling for how to write a working example. -In the last step you can run your binary, if all went well you will see a data transfer being reported: -``` -omptarget device 0 info: Entering OpenMP data region with being_mapper at unknown:0:0 with 1 arguments: -omptarget device 0 info: tofrom(unknown)[1024] -omptarget device 0 info: Creating new map entry with HstPtrBase=0x00007fffffff9540, HstPtrBegin=0x00007fffffff9540, TgtAllocBegin=0x0000155547200000, TgtPtrBegin=0x0000155547200000, Size=1024, DynRefCount=1, HoldRefCount=0, Name=unknown -omptarget device 0 info: Copying data from host to device, HstPtr=0x00007fffffff9540, TgtPtr=0x0000155547200000, Size=1024, Name=unknown -omptarget device 0 info: OpenMP Host-Device pointer mappings after block at unknown:0:0: -omptarget device 0 info: Host Ptr Target Ptr Size (B) DynRefCount HoldRefCount Declaration -omptarget device 0 info: 0x00007fffffff9540 0x0000155547200000 1024 1 0 unknown at unknown:0:0 -// some other output -omptarget device 0 info: Exiting OpenMP data region with end_mapper at unknown:0:0 with 1 arguments: -omptarget device 0 info: tofrom(unknown)[1024] -omptarget device 0 info: Mapping exists with HstPtrBegin=0x00007fffffff9540, TgtPtrBegin=0x0000155547200000, Size=1024, DynRefCount=0 (decremented, delayed deletion), HoldRefCount=0 -omptarget device 0 info: Copying data from device to host, TgtPtr=0x0000155547200000, HstPtr=0x00007fffffff9540, Size=1024, Name=unknown -omptarget device 0 info: Removing map entry with HstPtrBegin=0x00007fffffff9540, TgtPtrBegin=0x0000155547200000, Size=1024, Name=unknown -``` diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md new file mode 100644 index 00000000000..9f519984d9b --- /dev/null +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -0,0 +1,112 @@ +# Usage + +This feature is work-in-progress, and not ready for usage. The instructions here are for contributors, or people interested in following the latest progress. +We currently work on launching the following Rust kernel on the GPU. To follow along, copy it to a `src/lib.rs` file. + +```rust +#![feature(abi_gpu_kernel)] +#![no_std] + +#[cfg(target_os = "linux")] +extern crate libc; +#[cfg(target_os = "linux")] +use libc::c_char; + +use core::mem; + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[cfg(target_os = "linux")] +#[unsafe(no_mangle)] +#[inline(never)] +fn main() { + let array_c: *mut [f64; 256] = + unsafe { libc::calloc(256, (mem::size_of::<f64>()) as libc::size_t) as *mut [f64; 256] }; + let output = c"The first element is zero %f\n"; + let output2 = c"The first element is NOT zero %f\n"; + let output3 = c"The second element is %f\n"; + unsafe { + let val: *const c_char = if (*array_c)[0] < 0.1 { + output.as_ptr() + } else { + output2.as_ptr() + }; + libc::printf(val, (*array_c)[0]); + } + + unsafe { + kernel_1(array_c); + } + core::hint::black_box(&array_c); + unsafe { + let val: *const c_char = if (*array_c)[0] < 0.1 { + output.as_ptr() + } else { + output2.as_ptr() + }; + libc::printf(val, (*array_c)[0]); + libc::printf(output3.as_ptr(), (*array_c)[1]); + } +} + +#[cfg(target_os = "linux")] +unsafe extern "C" { + pub fn kernel_1(array_b: *mut [f64; 256]); +} +``` + +## Compile instructions +It is important to use a clang compiler build on the same llvm as rustc. Just calling clang without the full path will likely use your system clang, which probably will be incompatible. So either substitute clang/lld invocations below with absolute path, or set your `PATH` accordingly. + +First we generate the host (cpu) code. The first build is just to compile libc, take note of the hashed path. Then we call rustc directly to build our host code, while providing the libc artifact to rustc. +``` +cargo +offload build -r -v +rustc +offload --edition 2024 src/lib.rs -g --crate-type cdylib -C opt-level=3 -C panic=abort -C lto=fat -L dependency=/absolute_path_to/target/release/deps --extern libc=/absolute_path_to/target/release/deps/liblibc-<HASH>.rlib --emit=llvm-bc,llvm-ir -Zoffload=Enable -Zunstable-options +``` + +Now we generate the device code. Replace the target-cpu with the right code for your gpu. +``` +RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core +``` + +Now find the <libname>.ll under target/amdgcn-amd-amdhsa folder and copy it to a device.ll file (or adjust the file names below). +If you work on an NVIDIA or Intel gpu, please adjust the names acordingly and open an issue to share your results (either if you succeed or fail). +First we compile our .ll files (good for manual inspections) to .bc files and clean up leftover artifacts. The cleanup is important, otherwise caching might interfere on following runs. +``` +opt lib.ll -o lib.bc +opt device.ll -o device.bc +rm *.o +rm bare.amdgcn.gfx90a.img* +``` + +``` +clang-offload-packager" "-o" "host.out" "--image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp" + +clang-21" "-cc1" "-triple" "x86_64-unknown-linux-gnu" "-S" "-save-temps=cwd" "-disable-free" "-clear-ast-before-backend" "-main-file-name" "lib.rs" "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie" "-mframe-pointer=all" "-fmath-errno" "-ffp-contract=on" "-fno-rounding-math" "-mconstructor-aliases" "-funwind-tables=2" "-target-cpu" "x86-64" "-tune-cpu" "generic" "-resource-dir" "/<ABSOLUTE_PATH_TO>/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21" "-ferror-limit" "19" "-fopenmp" "-fopenmp-offload-mandatory" "-fgnuc-version=4.2.1" "-fskip-odr-check-in-gmf" "-fembed-offload-object=host.out" "-fopenmp-targets=amdgcn-amd-amdhsa" "-faddrsig" "-D__GCC_HAVE_DWARF2_CFI_ASM=1" "-o" "host.s" "-x" "ir" "lib.bc" + +clang-21" "-cc1as" "-triple" "x86_64-unknown-linux-gnu" "-filetype" "obj" "-main-file-name" "lib.rs" "-target-cpu" "x86-64" "-mrelocation-model" "pic" "-o" "host.o" "host.s" + +clang-linker-wrapper" "--should-extract=gfx90a" "--device-compiler=amdgcn-amd-amdhsa=-g" "--device-compiler=amdgcn-amd-amdhsa=-save-temps=cwd" "--device-linker=amdgcn-amd-amdhsa=-lompdevice" "--host-triple=x86_64-unknown-linux-gnu" "--save-temps" "--linker-path=/ABSOlUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/lld/bin/ld.lld" "--hash-style=gnu" "--eh-frame-hdr" "-m" "elf_x86_64" "-pie" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "bare" "/lib/../lib64/Scrt1.o" "/lib/../lib64/crti.o" "/ABSOLUTE_PATH_TO/crtbeginS.o" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/bin/../lib/x86_64-unknown-linux-gnu" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21/lib/x86_64-unknown-linux-gnu" "-L/lib/../lib64" "-L/usr/lib64" "-L/lib" "-L/usr/lib" "host.o" "-lstdc++" "-lm" "-lomp" "-lomptarget" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib" "-lgcc_s" "-lgcc" "-lpthread" "-lc" "-lgcc_s" "-lgcc" "/ABSOLUTE_PATH_TO/crtendS.o" "/lib/../lib64/crtn.o" +``` + +Especially for the last command I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. By adding `-###` to your clang invocation, you can see the invidual steps. +``` +myclang++ -fuse-ld=lld -O3 -fopenmp -fopenmp-offload-mandatory --offload-arch=gfx90a omp_bare.cpp -o main -### +``` + +In the final step, you can now run your binary + +``` +./main +The first element is zero 0.000000 +The first element is NOT zero 21.000000 +The second element is 0.000000 +``` + +To receive more information about the memory transfer, you can enable info printing with +``` +LIBOMPTARGET_INFO=-1 ./main +``` diff --git a/src/doc/rustc-dev-guide/src/queries/example-0.png b/src/doc/rustc-dev-guide/src/queries/example-0.png index 14b46c44f7d..dd67d5f2ef1 100644 --- a/src/doc/rustc-dev-guide/src/queries/example-0.png +++ b/src/doc/rustc-dev-guide/src/queries/example-0.png Binary files differdiff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 750e4fa1a0f..a8cc959124f 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -84,16 +84,15 @@ resources to run the full test suite for each commit on every PR. > Thus, it is a good idea to run `./x doc xxx` locally for any doc comment > changes to help catch these early. -PR jobs are defined in the `pr` section of [`jobs.yml`]. They run under the -`rust-lang/rust` repository, and their results can be observed directly on the -PR, in the "CI checks" section at the bottom of the PR page. +PR jobs are defined in the `pr` section of [`jobs.yml`]. Their results can be observed +directly on the PR, in the "CI checks" section at the bottom of the PR page. ### Auto builds Before a commit can be merged into the `master` branch, it needs to pass our complete test suite. We call this an `auto` build. This build runs tens of CI jobs that exercise various tests across operating systems and targets. The full -test suite is quite slow; it can take two hours or more until all the `auto` CI +test suite is quite slow; it can take several hours until all the `auto` CI jobs finish. Most platforms only run the build steps, some run a restricted set of tests, @@ -136,14 +135,21 @@ By default, if you send a comment with `@bors try`, the jobs defined in the `try [`jobs.yml`] will be executed. We call this mode a "fast try build". Such a try build will not execute any tests, and it will allow compilation warnings. It is useful when you want to get an optimized toolchain as fast as possible, for a crater run or performance benchmarks, -even if it might not be working fully correctly. - -If you want to run a custom CI job in a try build and make sure that it passes all tests and does -not produce any compilation warnings, you can select CI jobs to be executed by adding lines -containing `try-job: <job pattern>` to the PR description. All such specified jobs will be executed -in the try build once the `@bors try` command is used on the PR. - -Each pattern can either be an exact name of a job or a glob pattern that matches multiple jobs, +even if it might not be working fully correctly. If you want to do a full build for the default try job, +specify its job name in a job pattern (explained below). + +If you want to run custom CI job(s) in a try build and make sure that they pass all tests and do +not produce any compilation warnings, you can select CI jobs to be executed by specifying a *job pattern*, +which can be used in one of two ways: +- You can add a set of `try-job: <job pattern>` directives to the PR description (described below) and then + simply run `@bors try`. CI will read these directives and run the jobs that you have specified. This is + useful if you want to rerun the same set of try jobs multiple times, after incrementally modifying a PR. +- You can specify the job pattern using the `jobs` parameter of the try command: `@bors try jobs=<job pattern>`. + This is useful for one-off try builds with specific jobs. Note that the `jobs` parameter has a higher priority + than the PR description directives. + - There can also be multiple patterns specified, e.g. `@bors try jobs=job1,job2,job3`. + +Each job pattern can either be an exact name of a job or a glob pattern that matches multiple jobs, for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using glob patterns, you might want to wrap them in backticks (`` ` ``) to avoid GitHub rendering the pattern as Markdown. @@ -182,26 +188,19 @@ of [`jobs.yml`]: > However, it can be less flexible because you cannot adjust the set of tests > that are exercised this way. -Try jobs are defined in the `try` section of [`jobs.yml`]. They are executed on -the `try` branch under the `rust-lang/rust` repository and +Try builds are executed on the `try` branch under the `rust-lang/rust` repository and their results can be seen [here](https://github.com/rust-lang/rust/actions), although usually you will be notified of the result by a comment made by bors on the corresponding PR. -Note that if you start the default try job using `@bors try`, it will skip building several `dist` components and running post-optimization tests, to make the build duration shorter. If you want to execute the full build as it would happen before a merge, add an explicit `try-job` pattern with the name of the default try job (currently `dist-x86_64-linux`). +Multiple try builds can execute concurrently across different PRs, but there can be at most +a single try build running on a single PR at any given time. -Multiple try builds can execute concurrently across different PRs. - -<div class="warning"> - -Bors identifies try jobs by commit hash. This means that if you have two PRs -containing the same (latest) commits, running `@bors try` will result in the -*same* try job and it really confuses `bors`. Please refrain from doing so. - -</div> +Note that try builds are handled using the new [bors][new-bors] implementation. [rustc-perf]: https://github.com/rust-lang/rustc-perf [crater]: https://github.com/rust-lang/crater +[new-bors]: https://github.com/rust-lang/bors ### Modifying CI jobs diff --git a/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/fuchsia.md b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/fuchsia.md index b19d94d6ff7..75cf782a770 100644 --- a/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/fuchsia.md +++ b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/fuchsia.md @@ -18,12 +18,8 @@ Fuchsia builds as part of the suite of bors tests that run before a pull request is merged. If you are worried that a pull request might break the Fuchsia builder and want -to test it out before submitting it to the bors queue, simply add this line to -your PR description: - -> try-job: x86_64-fuchsia - -Then when you `@bors try` it will pick the job that builds Fuchsia. +to test it out before submitting it to the bors queue, simply ask bors to run +the try job that builds the Fuchsia integration: `@bors try jobs=x86_64-fuchsia`. ## Building Fuchsia locally diff --git a/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/rust-for-linux.md b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/rust-for-linux.md index d549ec6fca5..a6a7374b811 100644 --- a/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/rust-for-linux.md +++ b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/rust-for-linux.md @@ -40,12 +40,8 @@ this sysroot. RfL uses several unstable compiler/language features, therefore this workflow notifies us if a given compiler change would break it. If you are worried that a pull request might break the Rust for Linux builder -and want to test it out before submitting it to the bors queue, simply add this -line to your PR description: - -> try-job: x86_64-rust-for-linux - -Then when you `@bors try` it will pick the job that builds the Rust for Linux -integration. +and want to test it out before submitting it to the bors queue, simply ask +bors to run the try job that builds the Rust for Linux integration: +`@bors try jobs=x86_64-rust-for-linux`. [rfl-ping]: ../../notification-groups/rust-for-linux.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index b53494ed98d..e0d637a2a67 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -49,6 +49,7 @@ - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md) - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) + - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md) - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) @@ -106,6 +107,7 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md) + - [riscv64a23-unknown-linux-gnu](platform-support/riscv64a23-unknown-linux-gnu.md) - [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md) - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) diff --git a/src/doc/rustc/src/command-line-arguments/print-options.md b/src/doc/rustc/src/command-line-arguments/print-options.md index 1f33e91e5d1..fed19d6b667 100644 --- a/src/doc/rustc/src/command-line-arguments/print-options.md +++ b/src/doc/rustc/src/command-line-arguments/print-options.md @@ -32,7 +32,7 @@ The names of the files created by the `link` emit kind. ## `sysroot` -Abosulte path to the sysroot. +Absolute path to the sysroot. Example (with rustup and the stable toolchain): diff --git a/src/doc/rustc/src/images/image1.png b/src/doc/rustc/src/images/image1.png index 0da45e56620..3aad6359389 100644 --- a/src/doc/rustc/src/images/image1.png +++ b/src/doc/rustc/src/images/image1.png Binary files differdiff --git a/src/doc/rustc/src/images/image2.png b/src/doc/rustc/src/images/image2.png index a9cf23f8737..085b1c490b8 100644 --- a/src/doc/rustc/src/images/image2.png +++ b/src/doc/rustc/src/images/image2.png Binary files differdiff --git a/src/doc/rustc/src/images/image3.png b/src/doc/rustc/src/images/image3.png index 844a2fe6747..ee332f51055 100644 --- a/src/doc/rustc/src/images/image3.png +++ b/src/doc/rustc/src/images/image3.png Binary files differdiff --git a/src/doc/rustc/src/images/llvm-cov-show-01.png b/src/doc/rustc/src/images/llvm-cov-show-01.png index 35f04594347..ce4dec128b6 100644 --- a/src/doc/rustc/src/images/llvm-cov-show-01.png +++ b/src/doc/rustc/src/images/llvm-cov-show-01.png Binary files differdiff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 3bf87994297..2f815bcd141 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -273,6 +273,7 @@ target | std | host | notes [`aarch64_be-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit (big-endian) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) +[`aarch64_be-unknown-linux-musl`](platform-support/aarch64_be-unknown-linux-musl.md) | ✓ | ✓ | ARM64 Linux (big-endian) with musl-libc 1.2.5 [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) [`aarch64_be-unknown-none-softfloat`](platform-support/aarch64_be-unknown-none-softfloat.md) | * | | Bare big-endian ARM64, softfloat [`amdgcn-amd-amdhsa`](platform-support/amdgcn-amd-amdhsa.md) | * | | `-Ctarget-cpu=gfx...` to specify [the AMD GPU] to compile for @@ -327,8 +328,8 @@ target | std | host | notes [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] [^win32-msvc-alignment] [`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [^x86_32-floats-return-ABI] [`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | LoongArch64 OpenHarmony -[`loongarch32-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch32 Bare-metal (ILP32D ABI) -[`loongarch32-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch32 Bare-metal (ILP32S ABI) +[`loongarch32-unknown-none`](platform-support/loongarch-none.md) | * | | LoongArch32 Bare-metal (ILP32D ABI) +[`loongarch32-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | | LoongArch32 Bare-metal (ILP32S ABI) [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux [`m68k-unknown-none-elf`](platform-support/m68k-unknown-none-elf.md) | | | Motorola 680x0 `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23) @@ -391,6 +392,7 @@ target | std | host | notes [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | ✓ | | RISC-V 64bit with NuttX [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | ✓ | | RISC-V 64bit with NuttX +[`riscv64a23-unknown-linux-gnu`](platform-support/riscv64a23-unknown-linux-gnu.md) | ✓ | ✓ | RISC-V Linux (kernel 6.8.0+, glibc 2.39) [`s390x-unknown-linux-musl`](platform-support/s390x-unknown-linux-musl.md) | ✓ | | S390x Linux (kernel 3.2, musl 1.2.3) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ diff --git a/src/doc/rustc/src/platform-support/aarch64_be-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/aarch64_be-unknown-linux-musl.md new file mode 100644 index 00000000000..3e816dc8bfb --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64_be-unknown-linux-musl.md @@ -0,0 +1,49 @@ +# aarch64_be-unknown-linux-musl + +**Tier: 3** + +ARM64 Linux (big-endian) with musl-libc. + +## Target maintainers + +[@neuschaefer](https://github.com/neuschaefer) +[@Gelbpunkt](https://github.com/Gelbpunkt) + +## Requirements + +The target requires a `aarch64_be-*-linux-musl` toolchain, which likely has to +be built from source because this is a rare combination. [Buildroot] provides +a way of doing so: + +- select _Target options_ → _Target Architecture_ → _AArch64 (big endian)_ +- select _Toolchain_ → _C library_ → _musl_ +- select _Toolchain_ → _Enable C++ support_ + +Host tools are supported. + +[Buildroot]: https://buildroot.org/ + + +## Building the target + +The target can be enabled in bootstrap.toml: + +```toml +[build] +target = ["aarch64_be-unknown-linux-musl"] + +[target.aarch64_be-unknown-linux-musl] +cc = "/path/to/buildroot/host/bin/aarch64_be-buildroot-linux-musl-cc" +cxx = "/path/to/buildroot/host/bin/aarch64_be-buildroot-linux-musl-c++" +linker = "/path/to/buildroot/host/bin/aarch64_be-buildroot-linux-musl-cc" +ar = "/path/to/buildroot/host/bin/aarch64_be-buildroot-linux-musl-ar" +ranlib = "/path/to/buildroot/host/bin/aarch64_be-buildroot-linux-musl-ranlib" +musl-root = "/path/to/buildroot/staging" +runner = "qemu-aarch64_be -L /path/to/buildroot/target" +crt-static = "/path/to/buildroot/target" +``` + + +## Testing + +Binaries can be run under `qemu-aarch64_be` or under a big-endian Linux kernel. diff --git a/src/doc/rustc/src/platform-support/riscv64a23-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/riscv64a23-unknown-linux-gnu.md new file mode 100644 index 00000000000..2cbaaa86654 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv64a23-unknown-linux-gnu.md @@ -0,0 +1,41 @@ +# `riscv64a23-unknown-linux-gnu` + +**Tier: 3** + +RISC-V target using the ratified [RVA23 Profile](https://github.com/riscv/riscv-profiles/blob/main/src/rva23-profile.adoc). +This target will enable all mandary features of rva23u64 by default. + +## Target maintainers + +[@ZhongyaoChen](https://github.com/ZhongyaoChen) +[@CaiWeiran](https://github.com/CaiWeiran) + +## Requirements + +This target can be sucessfully build on the following platform: ubuntu 24.04 (Linux Kernel version 6.8.0, glibc 2.39). + +Other platforms may work, but are not tested. Please contanct if you encounter any issues. + +## Building the target + +Tier-3 target is not distributed through `rustup`. + +You need to build your own Rust, the target can be build with: + +```bash +./x build --target riscv64a23-unknown-linux-gnu +``` + +## Building Rust programs + +Add the toolchain: + +```bash +rustup toolchain link rva23-toolchain {path-to-rust}/build/host/stage2 +``` + +Then cross compile crates with: + +```bash +RUSTFLAGS="-C linker=riscv64-linux-gnu-gcc" cargo +rva23-toolchain build --target=riscv64a23-unknown-linux-gnu +``` diff --git a/src/doc/rustdoc/src/images/collapsed-long-item.png b/src/doc/rustdoc/src/images/collapsed-long-item.png index c382870c64a..6de759fbeb9 100644 --- a/src/doc/rustdoc/src/images/collapsed-long-item.png +++ b/src/doc/rustdoc/src/images/collapsed-long-item.png Binary files differdiff --git a/src/doc/rustdoc/src/images/collapsed-trait-impls.png b/src/doc/rustdoc/src/images/collapsed-trait-impls.png index f685656e09a..96cc7db6798 100644 --- a/src/doc/rustdoc/src/images/collapsed-trait-impls.png +++ b/src/doc/rustdoc/src/images/collapsed-trait-impls.png Binary files differdiff --git a/src/etc/installer/gfx/rust-logo.png b/src/etc/installer/gfx/rust-logo.png index 99ee7507fa2..49d8d0d9485 100644 --- a/src/etc/installer/gfx/rust-logo.png +++ b/src/etc/installer/gfx/rust-logo.png Binary files differdiff --git a/src/gcc b/src/gcc -Subproject 04ce66d8c918de9273bd7101638ad8724edf5e2 +Subproject 4e995bd73c4490edfe5080ec6014d63aa9abed5 diff --git a/src/librustdoc/html/static/images/favicon-32x32.png b/src/librustdoc/html/static/images/favicon-32x32.png index 69b8613ce15..0670c4dabb0 100644 --- a/src/librustdoc/html/static/images/favicon-32x32.png +++ b/src/librustdoc/html/static/images/favicon-32x32.png Binary files differdiff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d891d1fba25..e2682045ab4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -11,6 +11,7 @@ #![feature(file_buffered)] #![feature(format_args_nl)] #![feature(if_let_guard)] +#![feature(iter_advance_by)] #![feature(iter_intersperse)] #![feature(round_char_boundary)] #![feature(rustc_private)] diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 19cf15d40a3..da09117b1bb 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -1,9 +1,11 @@ //! Detects invalid HTML (like an unclosed `<span>`) in doc comments. +use std::borrow::Cow; use std::iter::Peekable; use std::ops::Range; use std::str::CharIndices; +use itertools::Itertools as _; use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag, TagEnd}; use rustc_hir::HirId; use rustc_resolve::rustdoc::source_span_for_markdown_range; @@ -101,7 +103,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & }); }; - let mut tags = Vec::new(); + let mut tagp = TagParser::new(); let mut is_in_comment = None; let mut in_code_block = false; @@ -126,70 +128,65 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & }; let p = Parser::new_with_broken_link_callback(dox, main_body_opts(), Some(&mut replacer)) - .into_offset_iter(); + .into_offset_iter() + .coalesce(|a, b| { + // for some reason, pulldown-cmark splits html blocks into separate events for each line. + // we undo this, in order to handle multi-line tags. + match (a, b) { + ((Event::Html(_), ra), (Event::Html(_), rb)) if ra.end == rb.start => { + let merged = ra.start..rb.end; + Ok((Event::Html(Cow::Borrowed(&dox[merged.clone()]).into()), merged)) + } + x => Err(x), + } + }); for (event, range) in p { match event { Event::Start(Tag::CodeBlock(_)) => in_code_block = true, Event::Html(text) | Event::InlineHtml(text) if !in_code_block => { - extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) + tagp.extract_tags(&text, range, &mut is_in_comment, &report_diag) } Event::End(TagEnd::CodeBlock) => in_code_block = false, _ => {} } } - for (tag, range) in tags.iter().filter(|(t, _)| { - let t = t.to_lowercase(); - !ALLOWED_UNCLOSED.contains(&t.as_str()) - }) { - report_diag(format!("unclosed HTML tag `{tag}`"), range, true); - } - if let Some(range) = is_in_comment { report_diag("Unclosed HTML comment".to_string(), &range, false); + } else if let &Some(quote_pos) = &tagp.quote_pos { + let qr = Range { start: quote_pos, end: quote_pos }; + report_diag( + format!("unclosed quoted HTML attribute on tag `{}`", &tagp.tag_name), + &qr, + false, + ); + } else { + if !tagp.tag_name.is_empty() { + report_diag( + format!("incomplete HTML tag `{}`", &tagp.tag_name), + &(tagp.tag_start_pos..dox.len()), + false, + ); + } + for (tag, range) in tagp.tags.iter().filter(|(t, _)| { + let t = t.to_lowercase(); + !is_implicitly_self_closing(&t) + }) { + report_diag(format!("unclosed HTML tag `{tag}`"), range, true); + } } } +/// These tags are interpreted as self-closing if they lack an explicit closing tag. const ALLOWED_UNCLOSED: &[&str] = &[ "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr", ]; -fn drop_tag( - tags: &mut Vec<(String, Range<usize>)>, - tag_name: String, - range: Range<usize>, - f: &impl Fn(String, &Range<usize>, bool), -) { - let tag_name_low = tag_name.to_lowercase(); - if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) { - // If the tag is nested inside a "<script>" or a "<style>" tag, no warning should - // be emitted. - let should_not_warn = tags.iter().take(pos + 1).any(|(at, _)| { - let at = at.to_lowercase(); - at == "script" || at == "style" - }); - for (last_tag_name, last_tag_span) in tags.drain(pos + 1..) { - if should_not_warn { - continue; - } - let last_tag_name_low = last_tag_name.to_lowercase(); - if ALLOWED_UNCLOSED.contains(&last_tag_name_low.as_str()) { - continue; - } - // `tags` is used as a queue, meaning that everything after `pos` is included inside it. - // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still - // have `h3`, meaning the tag wasn't closed as it should have. - f(format!("unclosed HTML tag `{last_tag_name}`"), &last_tag_span, true); - } - // Remove the `tag_name` that was originally closed - tags.pop(); - } else { - // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required - // but it helps for the visualization). - f(format!("unopened HTML tag `{tag_name}`"), &range, false); - } +/// Allows constructs like `<img>`, but not `<img`. +fn is_implicitly_self_closing(tag_name: &str) -> bool { + ALLOWED_UNCLOSED.contains(&tag_name) } fn extract_path_backwards(text: &str, end_pos: usize) -> Option<usize> { @@ -252,151 +249,292 @@ fn is_valid_for_html_tag_name(c: char, is_empty: bool) -> bool { c.is_ascii_alphabetic() || !is_empty && (c == '-' || c.is_ascii_digit()) } -fn extract_html_tag( - tags: &mut Vec<(String, Range<usize>)>, - text: &str, - range: &Range<usize>, - start_pos: usize, - iter: &mut Peekable<CharIndices<'_>>, - f: &impl Fn(String, &Range<usize>, bool), -) { - let mut tag_name = String::new(); - let mut is_closing = false; - let mut prev_pos = start_pos; +/// Parse html tags to ensure they are well-formed +#[derive(Debug, Clone)] +struct TagParser { + tags: Vec<(String, Range<usize>)>, + /// Name of the tag that is being parsed, if we are within a tag. + /// + /// Since the `<` and name of a tag must appear on the same line with no whitespace, + /// if this is the empty string, we are not in a tag. + tag_name: String, + tag_start_pos: usize, + is_closing: bool, + /// `true` if we are within a tag, but not within its name. + in_attrs: bool, + /// If we are in a quoted attribute, what quote char does it use? + /// + /// This needs to be stored in the struct since HTML5 allows newlines in quoted attrs. + quote: Option<char>, + quote_pos: Option<usize>, + after_eq: bool, +} - loop { - let (pos, c) = match iter.peek() { - Some((pos, c)) => (*pos, *c), - // In case we reached the of the doc comment, we want to check that it's an - // unclosed HTML tag. For example "/// <h3". - None => (prev_pos, '\0'), - }; - prev_pos = pos; - // Checking if this is a closing tag (like `</a>` for `<a>`). - if c == '/' && tag_name.is_empty() { - is_closing = true; - } else if is_valid_for_html_tag_name(c, tag_name.is_empty()) { - tag_name.push(c); - } else { - if !tag_name.is_empty() { - let mut r = Range { start: range.start + start_pos, end: range.start + pos }; - if c == '>' { - // In case we have a tag without attribute, we can consider the span to - // refer to it fully. - r.end += 1; +impl TagParser { + fn new() -> Self { + Self { + tags: Vec::new(), + tag_name: String::with_capacity(8), + tag_start_pos: 0, + is_closing: false, + in_attrs: false, + quote: None, + quote_pos: None, + after_eq: false, + } + } + + fn drop_tag(&mut self, range: Range<usize>, f: &impl Fn(String, &Range<usize>, bool)) { + let tag_name_low = self.tag_name.to_lowercase(); + if let Some(pos) = self.tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) { + // If the tag is nested inside a "<script>" or a "<style>" tag, no warning should + // be emitted. + let should_not_warn = self.tags.iter().take(pos + 1).any(|(at, _)| { + let at = at.to_lowercase(); + at == "script" || at == "style" + }); + for (last_tag_name, last_tag_span) in self.tags.drain(pos + 1..) { + if should_not_warn { + continue; } - if is_closing { - // In case we have "</div >" or even "</div >". - if c != '>' { - if !c.is_whitespace() { - // It seems like it's not a valid HTML tag. - break; - } - let mut found = false; - for (new_pos, c) in text[pos..].char_indices() { + let last_tag_name_low = last_tag_name.to_lowercase(); + if is_implicitly_self_closing(&last_tag_name_low) { + continue; + } + // `tags` is used as a queue, meaning that everything after `pos` is included inside it. + // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still + // have `h3`, meaning the tag wasn't closed as it should have. + f(format!("unclosed HTML tag `{last_tag_name}`"), &last_tag_span, true); + } + // Remove the `tag_name` that was originally closed + self.tags.pop(); + } else { + // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required + // but it helps for the visualization). + f(format!("unopened HTML tag `{}`", &self.tag_name), &range, false); + } + } + + /// Handle a `<` that appeared while parsing a tag. + fn handle_lt_in_tag( + &mut self, + range: Range<usize>, + lt_pos: usize, + f: &impl Fn(String, &Range<usize>, bool), + ) { + let global_pos = range.start + lt_pos; + // is this check needed? + if global_pos == self.tag_start_pos { + // `<` is in the tag because it is the start. + return; + } + // tried to start a new tag while in a tag + f( + format!("incomplete HTML tag `{}`", &self.tag_name), + &(self.tag_start_pos..global_pos), + false, + ); + self.tag_parsed(); + } + + fn extract_html_tag( + &mut self, + text: &str, + range: &Range<usize>, + start_pos: usize, + iter: &mut Peekable<CharIndices<'_>>, + f: &impl Fn(String, &Range<usize>, bool), + ) { + let mut prev_pos = start_pos; + + 'outer_loop: loop { + let (pos, c) = match iter.peek() { + Some((pos, c)) => (*pos, *c), + // In case we reached the of the doc comment, we want to check that it's an + // unclosed HTML tag. For example "/// <h3". + None if self.tag_name.is_empty() => (prev_pos, '\0'), + None => break, + }; + prev_pos = pos; + if c == '/' && self.tag_name.is_empty() { + // Checking if this is a closing tag (like `</a>` for `<a>`). + self.is_closing = true; + } else if !self.in_attrs && is_valid_for_html_tag_name(c, self.tag_name.is_empty()) { + self.tag_name.push(c); + } else { + if !self.tag_name.is_empty() { + self.in_attrs = true; + let mut r = Range { start: range.start + start_pos, end: range.start + pos }; + if c == '>' { + // In case we have a tag without attribute, we can consider the span to + // refer to it fully. + r.end += 1; + } + if self.is_closing { + // In case we have "</div >" or even "</div >". + if c != '>' { if !c.is_whitespace() { - if c == '>' { - r.end = range.start + new_pos + 1; - found = true; - } + // It seems like it's not a valid HTML tag. break; } - } - if !found { - break; - } - } - drop_tag(tags, tag_name, r, f); - } else { - let mut is_self_closing = false; - let mut quote_pos = None; - if c != '>' { - let mut quote = None; - let mut after_eq = false; - for (i, c) in text[pos..].char_indices() { - if !c.is_whitespace() { - if let Some(q) = quote { - if c == q { - quote = None; - quote_pos = None; - after_eq = false; + let mut found = false; + for (new_pos, c) in text[pos..].char_indices() { + if !c.is_whitespace() { + if c == '>' { + r.end = range.start + new_pos + 1; + found = true; + } else if c == '<' { + self.handle_lt_in_tag(range.clone(), pos + new_pos, f); } - } else if c == '>' { break; - } else if c == '/' && !after_eq { - is_self_closing = true; - } else { - if is_self_closing { - is_self_closing = false; - } - if (c == '"' || c == '\'') && after_eq { - quote = Some(c); - quote_pos = Some(pos + i); - } else if c == '=' { - after_eq = true; - } } - } else if quote.is_none() { - after_eq = false; + } + if !found { + break 'outer_loop; } } - } - if let Some(quote_pos) = quote_pos { - let qr = Range { start: quote_pos, end: quote_pos }; - f( - format!("unclosed quoted HTML attribute on tag `{tag_name}`"), - &qr, - false, - ); - } - if is_self_closing { - // https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus - let valid = ALLOWED_UNCLOSED.contains(&&tag_name[..]) - || tags.iter().take(pos + 1).any(|(at, _)| { - let at = at.to_lowercase(); - at == "svg" || at == "math" - }); - if !valid { - f(format!("invalid self-closing HTML tag `{tag_name}`"), &r, false); - } + self.drop_tag(r, f); + self.tag_parsed(); } else { - tags.push((tag_name, r)); + self.extract_opening_tag(text, range, r, pos, c, iter, f) } } + break; } - break; + iter.next(); } - iter.next(); } -} - -fn extract_tags( - tags: &mut Vec<(String, Range<usize>)>, - text: &str, - range: Range<usize>, - is_in_comment: &mut Option<Range<usize>>, - f: &impl Fn(String, &Range<usize>, bool), -) { - let mut iter = text.char_indices().peekable(); - while let Some((start_pos, c)) = iter.next() { - if is_in_comment.is_some() { - if text[start_pos..].starts_with("-->") { - *is_in_comment = None; + fn extract_opening_tag( + &mut self, + text: &str, + range: &Range<usize>, + r: Range<usize>, + pos: usize, + c: char, + iter: &mut Peekable<CharIndices<'_>>, + f: &impl Fn(String, &Range<usize>, bool), + ) { + // we can store this as a local, since html5 does require the `/` and `>` + // to not be separated by whitespace. + let mut is_self_closing = false; + if c != '>' { + 'parse_til_gt: { + for (i, c) in text[pos..].char_indices() { + if !c.is_whitespace() { + debug_assert_eq!(self.quote_pos.is_some(), self.quote.is_some()); + if let Some(q) = self.quote { + if c == q { + self.quote = None; + self.quote_pos = None; + self.after_eq = false; + } + } else if c == '>' { + break 'parse_til_gt; + } else if c == '<' { + self.handle_lt_in_tag(range.clone(), pos + i, f); + } else if c == '/' && !self.after_eq { + is_self_closing = true; + } else { + if is_self_closing { + is_self_closing = false; + } + if (c == '"' || c == '\'') && self.after_eq { + self.quote = Some(c); + self.quote_pos = Some(pos + i); + } else if c == '=' { + self.after_eq = true; + } + } + } else if self.quote.is_none() { + self.after_eq = false; + } + if !is_self_closing && !self.tag_name.is_empty() { + iter.next(); + } + } + // if we've run out of text but still haven't found a `>`, + // return early without calling `tag_parsed` or emitting lints. + // this allows us to either find the `>` in a later event + // or emit a lint about it being missing. + return; } - } else if c == '<' { - if text[start_pos..].starts_with("<!--") { - // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!) - iter.next(); - iter.next(); - iter.next(); - *is_in_comment = Some(Range { - start: range.start + start_pos, - end: range.start + start_pos + 3, + } + if is_self_closing { + // https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus + let valid = ALLOWED_UNCLOSED.contains(&&self.tag_name[..]) + || self.tags.iter().take(pos + 1).any(|(at, _)| { + let at = at.to_lowercase(); + at == "svg" || at == "math" }); - } else { - extract_html_tag(tags, text, &range, start_pos, &mut iter, f); + if !valid { + f(format!("invalid self-closing HTML tag `{}`", self.tag_name), &r, false); + } + } else if !self.tag_name.is_empty() { + self.tags.push((std::mem::take(&mut self.tag_name), r)); + } + self.tag_parsed(); + } + /// Finished parsing a tag, reset related data. + fn tag_parsed(&mut self) { + self.tag_name.clear(); + self.is_closing = false; + self.in_attrs = false; + } + + fn extract_tags( + &mut self, + text: &str, + range: Range<usize>, + is_in_comment: &mut Option<Range<usize>>, + f: &impl Fn(String, &Range<usize>, bool), + ) { + let mut iter = text.char_indices().peekable(); + let mut prev_pos = 0; + loop { + if self.quote.is_some() { + debug_assert!(self.in_attrs && self.quote_pos.is_some()); + } + if self.in_attrs + && let Some(&(start_pos, _)) = iter.peek() + { + self.extract_html_tag(text, &range, start_pos, &mut iter, f); + // if no progress is being made, move forward forcefully. + if prev_pos == start_pos { + iter.next(); + } + prev_pos = start_pos; + continue; + } + let Some((start_pos, c)) = iter.next() else { break }; + if is_in_comment.is_some() { + if text[start_pos..].starts_with("-->") { + *is_in_comment = None; + } + } else if c == '<' { + // "<!--" is a valid attribute name under html5, so don't treat it as a comment if we're in a tag. + if self.tag_name.is_empty() && text[start_pos..].starts_with("<!--") { + // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!) + iter.next(); + iter.next(); + iter.next(); + *is_in_comment = Some(Range { + start: range.start + start_pos, + end: range.start + start_pos + 4, + }); + } else { + if self.tag_name.is_empty() { + self.tag_start_pos = range.start + start_pos; + } + self.extract_html_tag(text, &range, start_pos, &mut iter, f); + } + } else if !self.tag_name.is_empty() { + // partially inside html tag that spans across events + self.extract_html_tag(text, &range, start_pos, &mut iter, f); } } } } + +#[cfg(test)] +mod tests; diff --git a/src/librustdoc/passes/lint/html_tags/tests.rs b/src/librustdoc/passes/lint/html_tags/tests.rs new file mode 100644 index 00000000000..81c1d21a55d --- /dev/null +++ b/src/librustdoc/passes/lint/html_tags/tests.rs @@ -0,0 +1,73 @@ +use std::cell::RefCell; + +use super::*; + +#[test] +fn test_extract_tags_nested_unclosed() { + let mut tagp = TagParser::new(); + let diags = RefCell::new(Vec::new()); + let dox = "<div>\n<br</div>"; + tagp.extract_tags(dox, 0..dox.len(), &mut None, &|s, r, b| { + diags.borrow_mut().push((s, r.clone(), b)); + }); + assert_eq!(diags.borrow().len(), 1, "did not get expected diagnostics: {diags:?}"); + assert_eq!(diags.borrow()[0].1, 6..9) +} + +#[test] +fn test_extract_tags_taglike_in_attr() { + let mut tagp = TagParser::new(); + let diags = RefCell::new(Vec::new()); + let dox = "<img src='<div>'>"; + tagp.extract_tags(dox, 0..dox.len(), &mut None, &|s, r, b| { + diags.borrow_mut().push((s, r.clone(), b)); + }); + assert_eq!(diags.borrow().len(), 0, "unexpected diagnostics: {diags:?}"); +} + +#[test] +fn test_extract_tags_taglike_in_multiline_attr() { + let mut tagp = TagParser::new(); + let diags = RefCell::new(Vec::new()); + let dox = "<img src=\"\nasd\n<div>\n\">"; + tagp.extract_tags(dox, 0..dox.len(), &mut None, &|s, r, b| { + diags.borrow_mut().push((s, r.clone(), b)); + }); + assert_eq!(diags.borrow().len(), 0, "unexpected diagnostics: {diags:?}"); +} + +#[test] +fn test_extract_tags_taglike_in_multievent_attr() { + let mut tagp = TagParser::new(); + let diags = RefCell::new(Vec::new()); + let dox = "<img src='<div>'>"; + let split_point = 10; + let mut p = |range: Range<usize>| { + tagp.extract_tags(&dox[range.clone()], range, &mut None, &|s, r, b| { + diags.borrow_mut().push((s, r.clone(), b)); + }) + }; + p(0..split_point); + p(split_point..dox.len()); + assert_eq!(diags.borrow().len(), 0, "unexpected diagnostics: {diags:?}"); +} + +#[test] +fn test_extract_tags_taglike_in_multiline_multievent_attr() { + let mut tagp = TagParser::new(); + let diags = RefCell::new(Vec::new()); + let dox = "<img src='\n foo:\n </div>\n <p/>\n <div>\n'>"; + let mut p = |range: Range<usize>| { + tagp.extract_tags(&dox[range.clone()], range, &mut None, &|s, r, b| { + diags.borrow_mut().push((s, r.clone(), b)); + }) + }; + let mut offset = 0; + for ln in dox.split_inclusive('\n') { + let new_offset = offset + ln.len(); + p(offset..new_offset); + offset = new_offset; + } + assert_eq!(diags.borrow().len(), 0, "unexpected diagnostics: {diags:?}"); + assert_eq!(tagp.tags.len(), 1); +} diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index b16924babd1..d02952eb487 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -190,5 +190,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { /// and a rustc warning would be triggered, see #15301 fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool { let attrs = cx.tcx.codegen_fn_attrs(def_id); - attrs.contains_extern_indicator(cx.tcx, def_id) + attrs.contains_extern_indicator() } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 739db8fa095..c533293e791 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -412,7 +412,7 @@ impl<'test> TestCx<'test> { cmdline: format!("{cmd:?}"), }; self.dump_output( - self.config.verbose, + self.config.verbose || !proc_res.status.success(), &cmd.get_program().to_string_lossy(), &proc_res.stdout, &proc_res.stderr, @@ -1486,7 +1486,7 @@ impl<'test> TestCx<'test> { }; self.dump_output( - self.config.verbose, + self.config.verbose || (!result.status.success() && self.config.mode != TestMode::Ui), &command.get_program().to_string_lossy(), &result.stdout, &result.stderr, @@ -2987,6 +2987,7 @@ struct ProcArgs { args: Vec<OsString>, } +#[derive(Debug)] pub struct ProcRes { status: ExitStatus, stdout: String, diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index d9e374c414c..ae1b25f8857 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -279,7 +279,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { return None; } let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id); - if codegen_fn_attrs.contains_extern_indicator(tcx, local_def_id.into()) + if codegen_fn_attrs.contains_extern_indicator() || codegen_fn_attrs .flags .contains(CodegenFnAttrFlags::USED_COMPILER) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 1b5d9d50996..e0c077e9931 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -134,8 +134,7 @@ pub fn iter_exported_symbols<'tcx>( for def_id in crate_items.definitions() { let exported = tcx.def_kind(def_id).has_codegen_attrs() && { let codegen_attrs = tcx.codegen_fn_attrs(def_id); - codegen_attrs.contains_extern_indicator(tcx, def_id.into()) - || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + codegen_attrs.contains_extern_indicator() || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) }; diff --git a/src/tools/rustfmt/tests/source/frontmatter_compact.rs b/src/tools/rustfmt/tests/source/frontmatter_compact.rs new file mode 100644 index 00000000000..21d4c6f4b61 --- /dev/null +++ b/src/tools/rustfmt/tests/source/frontmatter_compact.rs @@ -0,0 +1,8 @@ +#!/usr/bin/env cargo +---identifier +[dependencies] +regex = "1" +--- +#![feature(frontmatter)] + +fn main() {} diff --git a/src/tools/rustfmt/tests/source/frontmatter_escaped.rs b/src/tools/rustfmt/tests/source/frontmatter_escaped.rs new file mode 100644 index 00000000000..0d026377566 --- /dev/null +++ b/src/tools/rustfmt/tests/source/frontmatter_escaped.rs @@ -0,0 +1,13 @@ +#!/usr/bin/env cargo +------------ +package.description = """ +Header +----- + +Body +""" +------------ + +#![feature(frontmatter)] + +fn main() {} diff --git a/src/tools/rustfmt/tests/source/frontmatter_spaced.rs b/src/tools/rustfmt/tests/source/frontmatter_spaced.rs new file mode 100644 index 00000000000..ee0bb81705c --- /dev/null +++ b/src/tools/rustfmt/tests/source/frontmatter_spaced.rs @@ -0,0 +1,16 @@ +#!/usr/bin/env cargo + + +--- identifier +[dependencies] +regex = "1" + +--- + + + + + +#![feature(frontmatter)] + +fn main() {} diff --git a/src/tools/rustfmt/tests/target/frontmatter_compact.rs b/src/tools/rustfmt/tests/target/frontmatter_compact.rs new file mode 100644 index 00000000000..21d4c6f4b61 --- /dev/null +++ b/src/tools/rustfmt/tests/target/frontmatter_compact.rs @@ -0,0 +1,8 @@ +#!/usr/bin/env cargo +---identifier +[dependencies] +regex = "1" +--- +#![feature(frontmatter)] + +fn main() {} diff --git a/src/tools/rustfmt/tests/target/frontmatter_escaped.rs b/src/tools/rustfmt/tests/target/frontmatter_escaped.rs new file mode 100644 index 00000000000..0d026377566 --- /dev/null +++ b/src/tools/rustfmt/tests/target/frontmatter_escaped.rs @@ -0,0 +1,13 @@ +#!/usr/bin/env cargo +------------ +package.description = """ +Header +----- + +Body +""" +------------ + +#![feature(frontmatter)] + +fn main() {} diff --git a/src/tools/rustfmt/tests/target/frontmatter_spaced.rs b/src/tools/rustfmt/tests/target/frontmatter_spaced.rs new file mode 100644 index 00000000000..ee0bb81705c --- /dev/null +++ b/src/tools/rustfmt/tests/target/frontmatter_spaced.rs @@ -0,0 +1,16 @@ +#!/usr/bin/env cargo + + +--- identifier +[dependencies] +regex = "1" + +--- + + + + + +#![feature(frontmatter)] + +fn main() {} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 80b6d54ce1c..18d97a748ba 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -361,7 +361,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "scoped-tls", "scopeguard", "self_cell", - "semver", "serde", "serde_derive", "serde_json", diff --git a/src/tools/tidy/src/gcc_submodule.rs b/src/tools/tidy/src/gcc_submodule.rs index 5d726c3ea48..217eaf1758c 100644 --- a/src/tools/tidy/src/gcc_submodule.rs +++ b/src/tools/tidy/src/gcc_submodule.rs @@ -24,6 +24,12 @@ pub fn check(root_path: &Path, compiler_path: &Path, bad: &mut bool) { .output() .expect("Cannot determine git SHA of the src/gcc checkout"); + // Git is not available or we are in a tarball + if !git_output.status.success() { + eprintln!("Cannot figure out the SHA of the GCC submodule"); + return; + } + // This can return e.g. // -e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc // e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc (master-e607be166673a8de9fc07f6f02c60426e556c5f2.e607be) diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index ce718902b29..23dc86998e8 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.14" +wasm-component-ld = "0.5.16" diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index 79347d0bbf6..c935a75a690 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -10,6 +10,9 @@ //@ revisions: aarch64_be_unknown_linux_gnu_ilp32 //@ [aarch64_be_unknown_linux_gnu_ilp32] compile-flags: --target aarch64_be-unknown-linux-gnu_ilp32 //@ [aarch64_be_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 +//@ revisions: aarch64_be_unknown_linux_musl +//@ [aarch64_be_unknown_linux_musl] compile-flags: --target aarch64_be-unknown-linux-musl +//@ [aarch64_be_unknown_linux_musl] needs-llvm-components: aarch64 //@ revisions: aarch64_be_unknown_netbsd //@ [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd //@ [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64 @@ -481,6 +484,9 @@ //@ revisions: riscv64gc_unknown_linux_gnu //@ [riscv64gc_unknown_linux_gnu] compile-flags: --target riscv64gc-unknown-linux-gnu //@ [riscv64gc_unknown_linux_gnu] needs-llvm-components: riscv +//@ revisions: riscv64a23_unknown_linux_gnu +//@ [riscv64a23_unknown_linux_gnu] compile-flags: --target riscv64a23-unknown-linux-gnu +//@ [riscv64a23_unknown_linux_gnu] needs-llvm-components: riscv //@ revisions: riscv64gc_unknown_linux_musl //@ [riscv64gc_unknown_linux_musl] compile-flags: --target riscv64gc-unknown-linux-musl //@ [riscv64gc_unknown_linux_musl] needs-llvm-components: riscv diff --git a/tests/crashes/124352.rs b/tests/crashes/124352.rs deleted file mode 100644 index e9eb4419e6a..00000000000 --- a/tests/crashes/124352.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #124352 -#![rustc_never_type_options(: Unsize<U> = "hi")] - -fn main() {} diff --git a/tests/rustdoc-ui/lints/invalid-html-tags.rs b/tests/rustdoc-ui/lints/invalid-html-tags.rs index 317f1fd1d46..8003e5efdd5 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags.rs +++ b/tests/rustdoc-ui/lints/invalid-html-tags.rs @@ -43,7 +43,7 @@ pub fn b() {} /// <h3> //~^ ERROR unclosed HTML tag `h3` /// <script -//~^ ERROR unclosed HTML tag `script` +//~^ ERROR incomplete HTML tag `script` pub fn c() {} // Unclosed tags shouldn't warn if they are nested inside a <script> elem. @@ -72,6 +72,7 @@ pub fn e() {} /// <div></div > /// <div></div //~^ ERROR unclosed HTML tag `div` +//~| ERROR incomplete HTML tag `div` pub fn f() {} /// <!----> @@ -105,7 +106,7 @@ pub fn j() {} /// uiapp.run(&env::args().collect::<Vec<_>>()); /// ``` /// -/// <Vec<_> shouldn't warn! +// <Vec<_> shouldn't warn! /// `````` pub fn k() {} @@ -121,3 +122,92 @@ pub fn no_error_1() {} /// backslashed \<<a href=""> //~^ ERROR unclosed HTML tag `a` pub fn p() {} + +/// <svg width="512" height="512" viewBox="0 0 512" fill="none" xmlns="http://www.w3.org/2000/svg"> +/// <rect +/// width="256" +/// height="256" +/// fill="#5064C8" +/// stroke="black" +/// /> +/// </svg> +pub fn no_error_2() {} + +/// <div> +/// <img +/// src="https://example.com/ferris.png" +/// width="512" +/// height="512" +/// /> +/// </div> +pub fn no_error_3() {} + +/// > <div +/// > class="foo"> +/// > </div> +pub fn no_error_4() {} + +/// unfinished ALLOWED_UNCLOSED +/// +/// note: CommonMark doesn't allow an html block to start with a multiline tag, +/// so we use `<br>` a bunch to force these to be parsed as html blocks. +/// +/// <br> +/// <img +//~^ ERROR incomplete HTML tag `img` +pub fn q() {} + +/// nested unfinished ALLOWED_UNCLOSED +/// <p><img</p> +//~^ ERROR incomplete HTML tag `img` +pub fn r() {} + +/// > <br> +/// > <img +//~^ ERROR incomplete HTML tag `img` +/// > href="#broken" +pub fn s() {} + +/// <br> +/// <br<br> +//~^ ERROR incomplete HTML tag `br` +pub fn t() {} + +/// <br> +/// <br +//~^ ERROR incomplete HTML tag `br` +pub fn u() {} + +/// <a href=">" alt="<">html5 allows this</a> +pub fn no_error_5() {} + +/// <br> +/// <img title=" +/// html5 +/// allows +/// multiline +/// attr +/// values +/// these are just text, not tags: +/// </div> +/// <p/> +/// <div> +/// "> +pub fn no_error_6() {} + +/// <br> +/// <a href="data:text/html,<!DOCTYPE> +/// <html> +/// <body><b>this is allowed for some reason</b></body> +/// </html> +/// ">what</a> +pub fn no_error_7() {} + +/// Technically this is allowed per the html5 spec, +/// but there's basically no legitemate reason to do it, +/// so we don't allow it. +/// +/// <p <!-->foobar</p> +//~^ ERROR Unclosed HTML comment +//~| ERROR incomplete HTML tag `p` +pub fn v() {} diff --git a/tests/rustdoc-ui/lints/invalid-html-tags.stderr b/tests/rustdoc-ui/lints/invalid-html-tags.stderr index 9c2bfcf2c3d..b6ec22c2479 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags.stderr +++ b/tests/rustdoc-ui/lints/invalid-html-tags.stderr @@ -52,6 +52,12 @@ error: unclosed HTML tag `p` LL | /// <br/> <p> | ^^^ +error: incomplete HTML tag `script` + --> $DIR/invalid-html-tags.rs:45:5 + | +LL | /// <script + | ^^^^^^^ + error: unclosed HTML tag `div` --> $DIR/invalid-html-tags.rs:41:5 | @@ -64,11 +70,11 @@ error: unclosed HTML tag `h3` LL | /// <h3> | ^^^^ -error: unclosed HTML tag `script` - --> $DIR/invalid-html-tags.rs:45:5 +error: incomplete HTML tag `div` + --> $DIR/invalid-html-tags.rs:73:10 | -LL | /// <script - | ^^^^^^ +LL | /// <div></div + | ^^^^^ error: unclosed HTML tag `div` --> $DIR/invalid-html-tags.rs:73:5 @@ -77,28 +83,73 @@ LL | /// <div></div | ^^^^^ error: Unclosed HTML comment - --> $DIR/invalid-html-tags.rs:87:5 + --> $DIR/invalid-html-tags.rs:88:5 | LL | /// <!-- - | ^^^ + | ^^^^ error: unopened HTML tag `unopened-tag` - --> $DIR/invalid-html-tags.rs:114:26 + --> $DIR/invalid-html-tags.rs:115:26 | LL | /// Web Components style </unopened-tag> | ^^^^^^^^^^^^^^^ error: unclosed HTML tag `dashed-tags` - --> $DIR/invalid-html-tags.rs:112:26 + --> $DIR/invalid-html-tags.rs:113:26 | LL | /// Web Components style <dashed-tags> | ^^^^^^^^^^^^^ error: unclosed HTML tag `a` - --> $DIR/invalid-html-tags.rs:121:19 + --> $DIR/invalid-html-tags.rs:122:19 | LL | /// backslashed \<<a href=""> | ^^ -error: aborting due to 16 previous errors +error: incomplete HTML tag `img` + --> $DIR/invalid-html-tags.rs:156:5 + | +LL | /// <img + | ^^^^ + +error: incomplete HTML tag `img` + --> $DIR/invalid-html-tags.rs:161:8 + | +LL | /// <p><img</p> + | ^^^^ + +error: incomplete HTML tag `img` + --> $DIR/invalid-html-tags.rs:166:7 + | +LL | /// > <img + | _______^ +LL | | +LL | | /// > href="#broken" + | |____________________^ + +error: incomplete HTML tag `br` + --> $DIR/invalid-html-tags.rs:172:5 + | +LL | /// <br<br> + | ^^^ + +error: incomplete HTML tag `br` + --> $DIR/invalid-html-tags.rs:177:5 + | +LL | /// <br + | ^^^ + +error: incomplete HTML tag `p` + --> $DIR/invalid-html-tags.rs:210:5 + | +LL | /// <p <!-->foobar</p> + | ^^^ + +error: Unclosed HTML comment + --> $DIR/invalid-html-tags.rs:210:8 + | +LL | /// <p <!-->foobar</p> + | ^^^^ + +error: aborting due to 24 previous errors diff --git a/tests/ui/attributes/attr-on-mac-call.rs b/tests/ui/attributes/attr-on-mac-call.rs new file mode 100644 index 00000000000..a23ced123ef --- /dev/null +++ b/tests/ui/attributes/attr-on-mac-call.rs @@ -0,0 +1,73 @@ +//@ check-pass +// Regression test for https://github.com/rust-lang/rust/issues/145779 +#![warn(unused_attributes)] + +fn main() { + #[export_name = "x"] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[unsafe(naked)] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[track_caller] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[used] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[target_feature(enable = "x")] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[deprecated] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[inline] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[link_name = "x"] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[link_section = "x"] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[link_ordinal(42)] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[non_exhaustive] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[proc_macro] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[cold] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[no_mangle] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[deprecated] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[automatically_derived] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[macro_use] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[must_use] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[no_implicit_prelude] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[path = ""] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[ignore] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + #[should_panic] + //~^ WARN attribute cannot be used on macro calls + //~| WARN previously accepted + unreachable!(); +} diff --git a/tests/ui/attributes/attr-on-mac-call.stderr b/tests/ui/attributes/attr-on-mac-call.stderr new file mode 100644 index 00000000000..a08d3059168 --- /dev/null +++ b/tests/ui/attributes/attr-on-mac-call.stderr @@ -0,0 +1,205 @@ +warning: `#[export_name]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:6:5 + | +LL | #[export_name = "x"] + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[export_name]` can be applied to functions and statics +note: the lint level is defined here + --> $DIR/attr-on-mac-call.rs:3:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +warning: `#[naked]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:9:5 + | +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[naked]` can only be applied to functions + +warning: `#[track_caller]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:12:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[track_caller]` can only be applied to functions + +warning: `#[used]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:15:5 + | +LL | #[used] + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[used]` can only be applied to statics + +warning: `#[target_feature]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:18:5 + | +LL | #[target_feature(enable = "x")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[target_feature]` can only be applied to functions + +warning: `#[deprecated]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:21:5 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, and crates + +warning: `#[inline]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:24:5 + | +LL | #[inline] + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[inline]` can only be applied to functions + +warning: `#[link_name]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:27:5 + | +LL | #[link_name = "x"] + | ^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[link_name]` can be applied to foreign functions and foreign statics + +warning: `#[link_section]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:30:5 + | +LL | #[link_section = "x"] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[link_section]` can be applied to statics and functions + +warning: `#[link_ordinal]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:33:5 + | +LL | #[link_ordinal(42)] + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[link_ordinal]` can be applied to foreign functions and foreign statics + +warning: `#[non_exhaustive]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:36:5 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[non_exhaustive]` can be applied to data types and enum variants + +warning: `#[proc_macro]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:39:5 + | +LL | #[proc_macro] + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[proc_macro]` can only be applied to functions + +warning: `#[cold]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:42:5 + | +LL | #[cold] + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[cold]` can only be applied to functions + +warning: `#[no_mangle]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:45:5 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_mangle]` can be applied to functions and statics + +warning: `#[deprecated]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:48:5 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, and crates + +warning: `#[automatically_derived]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:51:5 + | +LL | #[automatically_derived] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[automatically_derived]` can only be applied to trait impl blocks + +warning: `#[macro_use]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:54:5 + | +LL | #[macro_use] + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[macro_use]` can be applied to modules, extern crates, and crates + +warning: `#[must_use]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:57:5 + | +LL | #[must_use] + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[must_use]` can be applied to functions, data types, unions, and traits + +warning: `#[no_implicit_prelude]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:60:5 + | +LL | #[no_implicit_prelude] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_implicit_prelude]` can be applied to modules and crates + +warning: `#[path]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:63:5 + | +LL | #[path = ""] + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[path]` can only be applied to modules + +warning: `#[ignore]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:66:5 + | +LL | #[ignore] + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[ignore]` can only be applied to functions + +warning: `#[should_panic]` attribute cannot be used on macro calls + --> $DIR/attr-on-mac-call.rs:69:5 + | +LL | #[should_panic] + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[should_panic]` can only be applied to functions + +warning: 22 warnings emitted + diff --git a/tests/ui/attributes/crate-only-as-outer.rs b/tests/ui/attributes/crate-only-as-outer.rs new file mode 100644 index 00000000000..5a7d916c90d --- /dev/null +++ b/tests/ui/attributes/crate-only-as-outer.rs @@ -0,0 +1,10 @@ +#![deny(unused)] +#[crate_name = "owo"] +//~^ ERROR: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` + +fn main() {} + +mod inner { + #![crate_name = "iwi"] + //~^ ERROR: the `#![crate_name]` attribute can only be used at the crate root +} diff --git a/tests/ui/attributes/crate-only-as-outer.stderr b/tests/ui/attributes/crate-only-as-outer.stderr new file mode 100644 index 00000000000..270f02af987 --- /dev/null +++ b/tests/ui/attributes/crate-only-as-outer.stderr @@ -0,0 +1,26 @@ +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` + --> $DIR/crate-only-as-outer.rs:2:1 + | +LL | #[crate_name = "owo"] + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this function + --> $DIR/crate-only-as-outer.rs:5:1 + | +LL | fn main() {} + | ^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/crate-only-as-outer.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` + +error: the `#![crate_name]` attribute can only be used at the crate root + --> $DIR/crate-only-as-outer.rs:8:5 + | +LL | #![crate_name = "iwi"] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/attributes/malformed-never-type-options.rs b/tests/ui/attributes/malformed-never-type-options.rs new file mode 100644 index 00000000000..0c384be0e22 --- /dev/null +++ b/tests/ui/attributes/malformed-never-type-options.rs @@ -0,0 +1,8 @@ +//! Regression test for #124352 +//! The `rustc_*` attribute is malformed, but ICEing without a `feature(rustc_attrs)` is still bad. + +#![rustc_never_type_options(: Unsize<U> = "hi")] +//~^ ERROR expected unsuffixed literal, found `:` +//~| ERROR use of an internal attribute + +fn main() {} diff --git a/tests/ui/attributes/malformed-never-type-options.stderr b/tests/ui/attributes/malformed-never-type-options.stderr new file mode 100644 index 00000000000..0d2ff4881f2 --- /dev/null +++ b/tests/ui/attributes/malformed-never-type-options.stderr @@ -0,0 +1,19 @@ +error: expected unsuffixed literal, found `:` + --> $DIR/malformed-never-type-options.rs:4:29 + | +LL | #![rustc_never_type_options(: Unsize<U> = "hi")] + | ^ + +error[E0658]: use of an internal attribute + --> $DIR/malformed-never-type-options.rs:4:1 + | +LL | #![rustc_never_type_options(: Unsize<U> = "hi")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `#[rustc_never_type_options]` attribute is an internal implementation detail that will never be stable + = note: `rustc_never_type_options` is used to experiment with never type fallback and work on never type stabilization + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index f6448147392..258f2132466 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -243,6 +243,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `relax` `relaxed-simd` `rtm` +`rva23u64` `sb` `scq` `sha` @@ -304,6 +305,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `ssve-fp8dot2` `ssve-fp8dot4` `ssve-fp8fma` +`supm` `sve` `sve-b16b16` `sve2` diff --git a/tests/ui/coercion/fake-sized-ptr-cast.rs b/tests/ui/coercion/fake-sized-ptr-cast.rs new file mode 100644 index 00000000000..4b6bf0eb516 --- /dev/null +++ b/tests/ui/coercion/fake-sized-ptr-cast.rs @@ -0,0 +1,16 @@ +// Make sure borrowck doesn't ICE because it thinks a pointer cast is a metadata-preserving +// wide-to-wide ptr cast when it's actually (falsely) a wide-to-thin ptr cast due to an +// impossible dyn sized bound. + +//@ check-pass + +trait Trait<T> {} + +fn func<'a>(x: *const (dyn Trait<()> + 'a)) +where + dyn Trait<u8> + 'a: Sized, +{ + let _x: *const dyn Trait<u8> = x as _; +} + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr index 4c8a5e46751..c05584ef909 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -32,8 +32,9 @@ LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this closure | -LL | check(|| {}()); - | ++ +LL - check(|| {}); +LL + check((|| {})()); + | error[E0277]: `fn()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:9:11 diff --git a/tests/ui/consts/ptr_comparisons.rs b/tests/ui/consts/ptr_comparisons.rs index e142ab3a754..b8d809475cf 100644 --- a/tests/ui/consts/ptr_comparisons.rs +++ b/tests/ui/consts/ptr_comparisons.rs @@ -1,43 +1,205 @@ //@ compile-flags: --crate-type=lib //@ check-pass +//@ edition: 2024 +#![feature(const_raw_ptr_comparison)] +#![feature(fn_align)] +// Generally: +// For any `Some` return, `None` would also be valid, unless otherwise noted. +// For any `None` return, only `None` is valid, unless otherwise noted. -#![feature( - core_intrinsics, - const_raw_ptr_comparison, -)] +macro_rules! do_test { + ($a:expr, $b:expr, $expected:pat) => { + const _: () = { + let a: *const _ = $a; + let b: *const _ = $b; + assert!(matches!(<*const u8>::guaranteed_eq(a.cast(), b.cast()), $expected)); + }; + }; +} -const FOO: &usize = &42; +#[repr(align(2))] +struct T(#[allow(unused)] u16); -macro_rules! check { - (eq, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 1); - }; - (ne, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 0); +#[repr(align(2))] +struct AlignedZst; + +static A: T = T(42); +static B: T = T(42); +static mut MUT_STATIC: T = T(42); +static ZST: () = (); +static ALIGNED_ZST: AlignedZst = AlignedZst; +static LARGE_WORD_ALIGNED: [usize; 2] = [0, 1]; +static mut MUT_LARGE_WORD_ALIGNED: [usize; 2] = [0, 1]; + +const FN_PTR: *const () = { + fn foo() {} + unsafe { std::mem::transmute(foo as fn()) } +}; + +const ALIGNED_FN_PTR: *const () = { + #[rustc_align(2)] + fn aligned_foo() {} + unsafe { std::mem::transmute(aligned_foo as fn()) } +}; + +trait Trait { + #[allow(unused)] + fn method(&self) -> u8; +} +impl Trait for u32 { + fn method(&self) -> u8 { 1 } +} +impl Trait for i32 { + fn method(&self) -> u8 { 2 } +} + +const VTABLE_PTR_1: *const () = { + let [_data, vtable] = unsafe { + std::mem::transmute::<&dyn Trait, [*const (); 2]>(&42_u32 as &dyn Trait) }; - (!, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 2); + vtable +}; +const VTABLE_PTR_2: *const () = { + let [_data, vtable] = unsafe { + std::mem::transmute::<&dyn Trait, [*const (); 2]>(&42_i32 as &dyn Trait) }; -} + vtable +}; -check!(eq, 0, 0); -check!(ne, 0, 1); -check!(ne, FOO as *const _, 0); -check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0); -check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0); +// Cannot be `None`: `is_null` is stable with strong guarantees about integer-valued pointers. +do_test!(0 as *const u8, 0 as *const u8, Some(true)); +do_test!(0 as *const u8, 1 as *const u8, Some(false)); -// We want pointers to be equal to themselves, but aren't checking this yet because -// there are some open questions (e.g. whether function pointers to the same function -// compare equal: they don't necessarily do at runtime). -check!(!, FOO as *const _, FOO as *const _); +// Integer-valued pointers can always be compared. +do_test!(1 as *const u8, 1 as *const u8, Some(true)); +do_test!(1 as *const u8, 2 as *const u8, Some(false)); + +// Cannot be `None`: `static`s' addresses, references, (and within and one-past-the-end of those), +// and `fn` pointers cannot be null, and `is_null` is stable with strong guarantees, and +// `is_null` is implemented using `guaranteed_cmp`. +do_test!(&A, 0 as *const u8, Some(false)); +do_test!((&raw const A).cast::<u8>().wrapping_add(1), 0 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_add(1), 0 as *const u8, Some(false)); +do_test!(&ZST, 0 as *const u8, Some(false)); +do_test!(&(), 0 as *const u8, Some(false)); +do_test!(const { &() }, 0 as *const u8, Some(false)); +do_test!(FN_PTR, 0 as *const u8, Some(false)); + +// This pointer is out-of-bounds, but still cannot be equal to 0 because of alignment. +do_test!((&raw const A).cast::<u8>().wrapping_add(size_of::<T>() + 1), 0 as *const u8, Some(false)); // aside from 0, these pointers might end up pretty much anywhere. -check!(!, FOO as *const _, 1); // this one could be `ne` by taking into account alignment -check!(!, FOO as *const _, 1024); +do_test!(&A, align_of::<T>() as *const u8, None); +do_test!((&raw const A).wrapping_byte_add(1), (align_of::<T>() + 1) as *const u8, None); + +// except that they must still be aligned +do_test!(&A, 1 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(1), align_of::<T>() as *const u8, Some(false)); + +// If `ptr.wrapping_sub(int)` cannot be null (because it is in-bounds or one-past-the-end of +// `ptr`'s allocation, or because it is misaligned from `ptr`'s allocation), then we know that +// `ptr != int`, even if `ptr` itself is out-of-bounds or one-past-the-end of its allocation. +do_test!((&raw const A).wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(2), 2 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(3), 1 as *const u8, Some(false)); +do_test!((&raw const ZST).wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(VTABLE_PTR_1.wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(FN_PTR.wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(&A, size_of::<T>().wrapping_neg() as *const u8, Some(false)); +do_test!(&LARGE_WORD_ALIGNED, size_of::<usize>().wrapping_neg() as *const u8, Some(false)); +// (`ptr - int != 0` due to misalignment) +do_test!((&raw const A).wrapping_byte_add(2), 1 as *const u8, Some(false)); +do_test!((&raw const ALIGNED_ZST).wrapping_byte_add(2), 1 as *const u8, Some(false)); // When pointers go out-of-bounds, they *might* become null, so these comparions cannot work. -check!(!, unsafe { (FOO as *const usize).wrapping_add(2) }, 0); -check!(!, unsafe { (FOO as *const usize).wrapping_sub(1) }, 0); +do_test!((&raw const A).wrapping_add(2), 0 as *const u8, None); +do_test!((&raw const A).wrapping_sub(1), 0 as *const u8, None); + +// Statics cannot be duplicated +do_test!(&A, &A, Some(true)); + +// Two non-ZST statics cannot have the same address +do_test!(&A, &B, Some(false)); +do_test!(&A, &raw const MUT_STATIC, Some(false)); + +// One-past-the-end of one static can be equal to the address of another static. +do_test!(&A, (&raw const B).wrapping_add(1), None); + +// Cannot know if ZST static is at the same address with anything non-null (if alignment allows). +do_test!(&A, &ZST, None); +do_test!(&A, &ALIGNED_ZST, None); + +// Unclear if ZST statics can be placed "in the middle of" non-ZST statics. +// For now, we conservatively say they could, and return None here. +do_test!(&ZST, (&raw const A).wrapping_byte_add(1), None); + +// As per https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness +// immutable statics are allowed to overlap with const items and promoteds. +do_test!(&A, &T(42), None); +do_test!(&A, const { &T(42) }, None); +do_test!(&A, { const X: T = T(42); &X }, None); + +// These could return Some(false), since only immutable statics can overlap with const items +// and promoteds. +do_test!(&raw const MUT_STATIC, &T(42), None); +do_test!(&raw const MUT_STATIC, const { &T(42) }, None); +do_test!(&raw const MUT_STATIC, { const X: T = T(42); &X }, None); + +// An odd offset from a 2-aligned allocation can never be equal to an even offset from a +// 2-aligned allocation, even if the offsets are out-of-bounds. +do_test!(&A, (&raw const B).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&raw const B).wrapping_byte_add(5), Some(false)); +do_test!(&A, (&raw const ALIGNED_ZST).wrapping_byte_add(1), Some(false)); +do_test!(&ALIGNED_ZST, (&raw const A).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&T(42) as *const T).wrapping_byte_add(1), Some(false)); +do_test!(&A, (const { &T(42) } as *const T).wrapping_byte_add(1), Some(false)); +do_test!(&A, ({ const X: T = T(42); &X } as *const T).wrapping_byte_add(1), Some(false)); + +// We could return `Some(false)` for these, as pointers to different statics can never be equal if +// that would require the statics to overlap, even if the pointers themselves are offset out of +// bounds or one-past-the-end. We currently only check strictly in-bounds pointers when comparing +// pointers to different statics, however. +do_test!((&raw const A).wrapping_add(1), (&raw const B).wrapping_add(1), None); +do_test!( + (&raw const LARGE_WORD_ALIGNED).cast::<usize>().wrapping_add(2), + (&raw const MUT_LARGE_WORD_ALIGNED).cast::<usize>().wrapping_add(1), + None +); + +// Pointers into the same static are equal if and only if their offset is the same, +// even if either is out-of-bounds. +do_test!(&A, &A, Some(true)); +do_test!(&A, &A.0, Some(true)); +do_test!(&A, (&raw const A).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&raw const A).wrapping_byte_add(2), Some(false)); +do_test!(&A, (&raw const A).wrapping_byte_add(51), Some(false)); +do_test!((&raw const A).wrapping_byte_add(51), (&raw const A).wrapping_byte_add(51), Some(true)); + +// Pointers to the same fn may be unequal, since `fn`s can be duplicated. +do_test!(FN_PTR, FN_PTR, None); +do_test!(ALIGNED_FN_PTR, ALIGNED_FN_PTR, None); + +// Pointers to different fns may be equal, since `fn`s can be deduplicated. +do_test!(FN_PTR, ALIGNED_FN_PTR, None); + +// Pointers to the same vtable may be unequal, since vtables can be duplicated. +do_test!(VTABLE_PTR_1, VTABLE_PTR_1, None); + +// Pointers to different vtables may be equal, since vtables can be deduplicated. +do_test!(VTABLE_PTR_1, VTABLE_PTR_2, None); + +// Function pointers to aligned function allocations are not necessarily actually aligned, +// due to platform-specific semantics. +// See https://github.com/rust-lang/rust/issues/144661 +// FIXME: This could return `Some` on platforms where function pointers' addresses actually +// correspond to function addresses including alignment, or on platforms where all functions +// are aligned to some amount (e.g. ARM where a32 function pointers are at least 4-aligned, +// and t32 function pointers are 2-aligned-offset-by-1). +do_test!(ALIGNED_FN_PTR, ALIGNED_FN_PTR.wrapping_byte_offset(1), None); + +// Conservatively say we don't know. +do_test!(FN_PTR, VTABLE_PTR_1, None); +do_test!((&raw const LARGE_WORD_ALIGNED).cast::<usize>().wrapping_add(1), VTABLE_PTR_1, None); +do_test!((&raw const MUT_LARGE_WORD_ALIGNED).cast::<usize>().wrapping_add(1), VTABLE_PTR_1, None); +do_test!((&raw const LARGE_WORD_ALIGNED).cast::<usize>().wrapping_add(1), FN_PTR, None); +do_test!((&raw const MUT_LARGE_WORD_ALIGNED).cast::<usize>().wrapping_add(1), FN_PTR, None); diff --git a/tests/ui/diagnostic-flags/colored-session-opt-error.rs b/tests/ui/diagnostic-flags/colored-session-opt-error.rs index e850345fbf1..1c411048385 100644 --- a/tests/ui/diagnostic-flags/colored-session-opt-error.rs +++ b/tests/ui/diagnostic-flags/colored-session-opt-error.rs @@ -1,4 +1,8 @@ //@ check-pass //@ ignore-windows //@ compile-flags: -Cremark=foo --error-format=human --color=always + +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo-level=0 +//@ compile-flags: -Cdebuginfo=0 + fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 60666481bec..3d814700d98 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -482,21 +482,26 @@ mod no_implicit_prelude { #[reexport_test_harness_main = "2900"] //~^ WARN crate-level attribute should be +//~| HELP add a `!` mod reexport_test_harness_main { mod inner { #![reexport_test_harness_main="2900"] } //~^ WARN crate-level attribute should be #[reexport_test_harness_main = "2900"] fn f() { } //~^ WARN crate-level attribute should be + //~| HELP add a `!` #[reexport_test_harness_main = "2900"] struct S; //~^ WARN crate-level attribute should be + //~| HELP add a `!` #[reexport_test_harness_main = "2900"] type T = S; //~^ WARN crate-level attribute should be + //~| HELP add a `!` #[reexport_test_harness_main = "2900"] impl S { } //~^ WARN crate-level attribute should be + //~| HELP add a `!` } // Cannot feed "2700" to `#[macro_escape]` without signaling an error. @@ -534,21 +539,26 @@ mod macro_escape { #[no_std] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod no_std { mod inner { #![no_std] } //~^ WARN crate-level attribute should be in the root module #[no_std] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_std] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_std] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_std] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } // At time of authorship, #[proc_macro_derive = "2500"] signals error @@ -760,21 +770,26 @@ mod must_use { #[windows_subsystem = "windows"] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod windows_subsystem { mod inner { #![windows_subsystem="windows"] } //~^ WARN crate-level attribute should be in the root module #[windows_subsystem = "windows"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[windows_subsystem = "windows"] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[windows_subsystem = "windows"] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[windows_subsystem = "windows"] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } // BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES @@ -782,135 +797,170 @@ mod windows_subsystem { #[crate_name = "0900"] //~^ WARN crate-level attribute should be an inner attribute mod crate_name { +//~^ NOTE This attribute does not have an `!`, which means it is applied to this module mod inner { #![crate_name="0900"] } -//~^ WARN crate-level attribute should be in the root module +//~^ WARN the `#![crate_name]` attribute can only be used at the crate root #[crate_name = "0900"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| NOTE This attribute does not have an `!`, which means it is applied to this function #[crate_name = "0900"] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| NOTE This attribute does not have an `!`, which means it is applied to this struct #[crate_name = "0900"] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias #[crate_name = "0900"] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block } #[crate_type = "0800"] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod crate_type { mod inner { #![crate_type="0800"] } //~^ WARN crate-level attribute should be in the root module #[crate_type = "0800"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[crate_type = "0800"] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[crate_type = "0800"] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[crate_type = "0800"] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } #[feature(x0600)] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod feature { mod inner { #![feature(x0600)] } //~^ WARN crate-level attribute should be in the root module #[feature(x0600)] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[feature(x0600)] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[feature(x0600)] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[feature(x0600)] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } #[no_main] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod no_main_1 { mod inner { #![no_main] } //~^ WARN crate-level attribute should be in the root module #[no_main] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_main] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_main] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_main] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } #[no_builtins] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod no_builtins { mod inner { #![no_builtins] } //~^ WARN crate-level attribute should be in the root module #[no_builtins] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_builtins] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_builtins] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[no_builtins] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } #[recursion_limit="0200"] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod recursion_limit { mod inner { #![recursion_limit="0200"] } //~^ WARN crate-level attribute should be in the root module #[recursion_limit="0200"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[recursion_limit="0200"] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[recursion_limit="0200"] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[recursion_limit="0200"] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } #[type_length_limit="0100"] //~^ WARN crate-level attribute should be an inner attribute +//~| HELP add a `!` mod type_length_limit { mod inner { #![type_length_limit="0100"] } //~^ WARN crate-level attribute should be in the root module #[type_length_limit="0100"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[type_length_limit="0100"] struct S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[type_length_limit="0100"] type T = S; //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` #[type_length_limit="0100"] impl S { } //~^ WARN crate-level attribute should be an inner attribute + //~| HELP add a `!` } fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 7488c68b59f..65e3d29e269 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -1,5 +1,5 @@ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:506:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ @@ -198,20 +198,30 @@ note: the lint level is defined here LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` +warning: crate-level attribute should be an inner attribute --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![reexport_test_harness_main = "2900"] + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:535:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:1 | LL | #[no_std] | ^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_std] + | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:1 | LL | #[link()] | ^^^^^^^^^ @@ -226,53 +236,82 @@ LL | | } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1 | -LL | #[crate_name = "0900"] - | ^^^^^^^^^^^^^^^^^^^^^^ +help: add a `!` + | +LL | #![windows_subsystem = "windows"] + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![crate_type = "0800"] + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:845:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![feature(x0600)] + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:870:1 | LL | #[no_main] | ^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_main] + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:894:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_builtins] + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:878:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![recursion_limit="0200"] + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:897:1 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![type_length_limit="0100"] + | + warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 @@ -321,67 +360,107 @@ LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:490:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![reexport_test_harness_main = "2900"] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![reexport_test_harness_main = "2900"] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:498:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![reexport_test_harness_main = "2900"] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:498:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![reexport_test_harness_main = "2900"] impl S { } + | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:538:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_std] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5 | LL | #[no_std] struct S; | ^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_std] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_std] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_std] impl S { } + | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17 | LL | mod inner { #![link()] } | ------------^^^^^^^^^^-- not an `extern` block @@ -389,7 +468,7 @@ LL | mod inner { #![link()] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 | LL | #[link()] fn f() { } | ^^^^^^^^^ ---------- not an `extern` block @@ -397,7 +476,7 @@ LL | #[link()] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5 | LL | #[link()] struct S; | ^^^^^^^^^ --------- not an `extern` block @@ -405,7 +484,7 @@ LL | #[link()] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[link()] type T = S; | ^^^^^^^^^ ----------- not an `extern` block @@ -413,7 +492,7 @@ LL | #[link()] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 | LL | #[link()] impl S { } | ^^^^^^^^^ ---------- not an `extern` block @@ -421,7 +500,7 @@ LL | #[link()] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[link()] extern "Rust" {} | ^^^^^^^^^ @@ -429,244 +508,354 @@ LL | #[link()] extern "Rust" {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![windows_subsystem = "windows"] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5 | -LL | #[windows_subsystem = "windows"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a `!` + | +LL | #![windows_subsystem = "windows"] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:5 | -LL | #[windows_subsystem = "windows"] impl S { } +LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:17 | -LL | mod inner { #![crate_name="0900"] } - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5 +help: add a `!` | -LL | #[crate_name = "0900"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![windows_subsystem = "windows"] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 | -LL | #[crate_name = "0900"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 +LL | #[windows_subsystem = "windows"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | #[crate_name = "0900"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 +help: add a `!` | -LL | #[crate_name = "0900"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![windows_subsystem = "windows"] impl S { } + | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:825:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![crate_type = "0800"] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![crate_type = "0800"] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![crate_type = "0800"] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![crate_type = "0800"] impl S { } + | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:849:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![feature(x0600)] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:829:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![feature(x0600)] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![feature(x0600)] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![feature(x0600)] impl S { } + | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:874:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:877:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_main] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:849:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_main] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_main] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_main] impl S { } + | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:862:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:898:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:865:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:901:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_builtins] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:868:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:905:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_builtins] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_builtins] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:874:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:913:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![no_builtins] impl S { } + | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:922:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:884:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![recursion_limit="0200"] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:887:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![recursion_limit="0200"] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:890:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![recursion_limit="0200"] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:893:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![recursion_limit="0200"] impl S { } + | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:946:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:903:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![type_length_limit="0100"] fn f() { } + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:906:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![type_length_limit="0100"] struct S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![type_length_limit="0100"] type T = S; + | + -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:912:5 +warning: crate-level attribute should be an inner attribute + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![type_length_limit="0100"] impl S { } + | + warning: `#[macro_use]` attribute cannot be used on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5 @@ -993,7 +1182,7 @@ LL | #[no_implicit_prelude] impl S { } = help: `#[no_implicit_prelude]` can be applied to modules and crates warning: `#[macro_escape]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:510:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ @@ -1002,7 +1191,7 @@ LL | #[macro_escape] fn f() { } = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[macro_escape]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:521:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ @@ -1011,7 +1200,7 @@ LL | #[macro_escape] struct S; = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[macro_escape]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:522:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:527:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ @@ -1020,7 +1209,7 @@ LL | #[macro_escape] type T = S; = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ @@ -1029,7 +1218,7 @@ LL | #[macro_escape] impl S { } = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:571:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:1 | LL | #[cold] | ^^^^^^^ @@ -1038,7 +1227,7 @@ LL | #[cold] = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:578:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:17 | LL | mod inner { #![cold] } | ^^^^^^^^ @@ -1047,7 +1236,7 @@ LL | mod inner { #![cold] } = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:586:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:596:5 | LL | #[cold] struct S; | ^^^^^^^ @@ -1056,7 +1245,7 @@ LL | #[cold] struct S; = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:592:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:5 | LL | #[cold] type T = S; | ^^^^^^^ @@ -1065,7 +1254,7 @@ LL | #[cold] type T = S; = help: `#[cold]` can only be applied to functions warning: `#[cold]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:608:5 | LL | #[cold] impl S { } | ^^^^^^^ @@ -1074,7 +1263,7 @@ LL | #[cold] impl S { } = help: `#[cold]` can only be applied to functions warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -1083,7 +1272,7 @@ LL | #[link_name = "1900"] = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on foreign modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:621:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -1092,7 +1281,7 @@ LL | #[link_name = "1900"] = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:618:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:628:17 | LL | mod inner { #![link_name="1900"] } | ^^^^^^^^^^^^^^^^^^^^ @@ -1101,7 +1290,7 @@ LL | mod inner { #![link_name="1900"] } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:624:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -1110,7 +1299,7 @@ LL | #[link_name = "1900"] fn f() { } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -1119,7 +1308,7 @@ LL | #[link_name = "1900"] struct S; = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:636:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ @@ -1128,7 +1317,7 @@ LL | #[link_name = "1900"] type T = S; = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ @@ -1137,7 +1326,7 @@ LL | #[link_name = "1900"] impl S { } = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1146,7 +1335,7 @@ LL | #[link_section = "1800"] = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:17 | LL | mod inner { #![link_section="1800"] } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -1155,7 +1344,7 @@ LL | mod inner { #![link_section="1800"] } = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 | LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1164,7 +1353,7 @@ LL | #[link_section = "1800"] struct S; = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1173,7 +1362,7 @@ LL | #[link_section = "1800"] type T = S; = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 | LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1182,7 +1371,7 @@ LL | #[link_section = "1800"] impl S { } = help: `#[link_section]` can be applied to statics and functions warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -1191,7 +1380,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ @@ -1200,7 +1389,7 @@ LL | mod inner { #![must_use] } = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: `#[must_use]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ @@ -1209,7 +1398,7 @@ LL | #[must_use] type T = S; = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: `#[must_use]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ @@ -1217,6 +1406,76 @@ LL | #[must_use] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[must_use]` can be applied to functions, data types, unions, and traits +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:1 + | +LL | #[crate_name = "0900"] + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:1 + | +LL | / mod crate_name { +LL | | +LL | | mod inner { #![crate_name="0900"] } +... | +LL | | } + | |_^ + +warning: the `#![crate_name]` attribute can only be used at the crate root + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:17 + | +LL | mod inner { #![crate_name="0900"] } + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:5 + | +LL | #[crate_name = "0900"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:28 + | +LL | #[crate_name = "0900"] fn f() { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:5 + | +LL | #[crate_name = "0900"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this struct + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:28 + | +LL | #[crate_name = "0900"] struct S; + | ^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:5 + | +LL | #[crate_name = "0900"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this type alias + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:28 + | +LL | #[crate_name = "0900"] type T = S; + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:5 + | +LL | #[crate_name = "0900"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:28 + | +LL | #[crate_name = "0900"] impl S { } + | ^^^^^^^^^^ + warning: `#[should_panic]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 | diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr index d624fb1e42b..d6294efbd28 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr @@ -1,30 +1,14 @@ -error[E0283]: type annotations needed - --> $DIR/ambig-hr-projection-issue-93340.rs:17:5 +error[E0282]: type annotations needed + --> $DIR/ambig-hr-projection-issue-93340.rs:16:5 | LL | cmp_eq | ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq` | - = note: cannot satisfy `_: Scalar` -note: required by a bound in `cmp_eq` - --> $DIR/ambig-hr-projection-issue-93340.rs:10:22 - | -LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O { - | ^^^^^^ required by this bound in `cmp_eq` help: consider specifying the generic arguments | LL | cmp_eq::<A, B, O> | +++++++++++ -error[E0277]: expected a `Fn(<A as Scalar>::RefType<'_>, <B as Scalar>::RefType<'_>)` closure, found `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::<O, _, O>}` - --> $DIR/ambig-hr-projection-issue-93340.rs:14:1 - | -LL | / fn build_expression<A: Scalar, B: Scalar, O: Scalar>( -LL | | ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { - | |_________________________________________________^ expected an `Fn(<A as Scalar>::RefType<'_>, <B as Scalar>::RefType<'_>)` closure, found `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::<O, _, O>}` - | - = help: the trait `for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>)` is not implemented for fn item `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> O {cmp_eq::<O, _, O>}` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0283. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr index 4a293d44e0e..d913b2e91ca 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr @@ -1,5 +1,5 @@ error[E0283]: type annotations needed - --> $DIR/ambig-hr-projection-issue-93340.rs:17:5 + --> $DIR/ambig-hr-projection-issue-93340.rs:16:5 | LL | cmp_eq | ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq` diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs index 6ba3c4c65d0..acfebad38db 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs @@ -13,7 +13,6 @@ fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefT fn build_expression<A: Scalar, B: Scalar, O: Scalar>( ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { - //[next]~^^ ERROR expected a `Fn(<A as Scalar>::RefType<'_>, <B as Scalar>::RefType<'_>)` closure cmp_eq //~^ ERROR type annotations needed } diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr index 5caf0eb2fd4..7170efc8638 100644 --- a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr @@ -1,17 +1,9 @@ -error[E0283]: type annotations needed +error[E0282]: type annotations needed --> $DIR/auto-trait-selection-freeze.rs:19:16 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^ ----- type must be known at this point - | | - | cannot infer type of the type parameter `T` declared on the function `is_trait` + | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_trait` | - = note: cannot satisfy `_: Trait<_>` -note: required by a bound in `is_trait` - --> $DIR/auto-trait-selection-freeze.rs:11:16 - | -LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U { - | ^^^^^^^^ required by this bound in `is_trait` help: consider specifying the generic arguments | LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } @@ -19,4 +11,4 @@ LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr index d34fdcc4496..0f33aca3019 100644 --- a/tests/ui/impl-trait/auto-trait-selection.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr @@ -1,17 +1,9 @@ -error[E0283]: type annotations needed +error[E0282]: type annotations needed --> $DIR/auto-trait-selection.rs:15:16 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^ ----- type must be known at this point - | | - | cannot infer type of the type parameter `T` declared on the function `is_trait` + | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_trait` | - = note: cannot satisfy `_: Trait<_>` -note: required by a bound in `is_trait` - --> $DIR/auto-trait-selection.rs:7:16 - | -LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U { - | ^^^^^^^^ required by this bound in `is_trait` help: consider specifying the generic arguments | LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } @@ -19,4 +11,4 @@ LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/non-defining-uses/as-projection-term.next.stderr b/tests/ui/impl-trait/non-defining-uses/as-projection-term.next.stderr deleted file mode 100644 index 96e242d5d48..00000000000 --- a/tests/ui/impl-trait/non-defining-uses/as-projection-term.next.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: non-defining use of `impl Sized + '_` in the defining scope - --> $DIR/as-projection-term.rs:14:19 - | -LL | prove_proj(|| recur()); - | ^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs b/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs index f0cf333b6a1..19f983bab70 100644 --- a/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs +++ b/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs @@ -1,7 +1,7 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver //@ ignore-compare-mode-next-solver (explicit revisions) -//@[current] check-pass +//@ check-pass fn prove_proj<R>(_: impl FnOnce() -> R) {} fn recur<'a>() -> impl Sized + 'a { @@ -12,6 +12,6 @@ fn recur<'a>() -> impl Sized + 'a { // inference variable at this point, we unify it with `opaque<'1>` and // end up ignoring that defining use as the hidden type is equal to its key. prove_proj(|| recur()); - //[next]~^ ERROR non-defining use of `impl Sized + '_` in the defining scope } + fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.current.stderr b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.current.stderr new file mode 100644 index 00000000000..30424ec58f9 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.current.stderr @@ -0,0 +1,17 @@ +error[E0792]: expected generic type parameter, found `impl Foo` + --> $DIR/double-wrap-with-defining-use.rs:12:26 + | +LL | fn a<T: Foo>(x: T) -> impl Foo { + | - this generic parameter must be used with a generic type parameter +LL | if true { x } else { a(a(x)) } + | ^^^^^^^ + +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/double-wrap-with-defining-use.rs:12:26 + | +LL | if true { x } else { a(a(x)) } + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs index 339277fec37..734b1920772 100644 --- a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs +++ b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs @@ -1,12 +1,17 @@ // Regression test for ICE from issue #140545 // The error message is confusing and wrong, but that's a different problem (#139350) + //@ edition:2018 +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] check-pass trait Foo {} -fn a(x: impl Foo) -> impl Foo { +fn a<T: Foo>(x: T) -> impl Foo { if true { x } else { a(a(x)) } - //~^ ERROR: expected generic type parameter, found `impl Foo` [E0792] - //~| ERROR: type parameter `impl Foo` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //[current]~^ ERROR: expected generic type parameter, found `impl Foo` [E0792] + //[current]~| ERROR: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias } fn main(){} diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr deleted file mode 100644 index 1b02811e31b..00000000000 --- a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0792]: expected generic type parameter, found `impl Foo` - --> $DIR/double-wrap-with-defining-use.rs:7:26 - | -LL | fn a(x: impl Foo) -> impl Foo { - | -------- this generic parameter must be used with a generic type parameter -LL | if true { x } else { a(a(x)) } - | ^^^^^^^ - -error: type parameter `impl Foo` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/double-wrap-with-defining-use.rs:7:26 - | -LL | if true { x } else { a(a(x)) } - | ^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/non-defining-uses/recursive-call.rs b/tests/ui/impl-trait/non-defining-uses/recursive-call.rs new file mode 100644 index 00000000000..ecddf2cec47 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/recursive-call.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for the non-defining use error in `gll`. + +struct Foo; +impl Foo { + fn recur(&self, b: bool) -> impl Sized + '_ { + if b { + let temp = Foo; + temp.recur(false); + // desugars to `Foo::recur(&temp);` + } + + self + } + + fn in_closure(&self) -> impl Sized + '_ { + let _ = || { + let temp = Foo; + temp.in_closure(); + // desugars to `Foo::in_closure(&temp);` + }; + + self + } +} +fn main() {} diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr index 080c3284641..11a88b0918c 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr @@ -11,7 +11,7 @@ LL | fn build2<T>(x: T) -> impl Sized { | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type - --> $DIR/recursive-in-exhaustiveness.rs:39:23 + --> $DIR/recursive-in-exhaustiveness.rs:37:23 | LL | fn build3<T>(x: T) -> impl Sized { | ^^^^^^^^^^ diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr index db57be73acc..45df8cc9c0c 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr @@ -1,80 +1,21 @@ -error[E0284]: type annotations needed: cannot normalize `build<_>::{opaque#0}` - --> $DIR/recursive-in-exhaustiveness.rs:20:5 +error[E0282]: type annotations needed + --> $DIR/recursive-in-exhaustiveness.rs:19:17 | -LL | build(x) - | ^^^^^^^^ cannot normalize `build<_>::{opaque#0}` +LL | let (x,) = (build(x),); + | ^^^^^^^^ cannot infer type -error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:30:6 +error[E0282]: type annotations needed + --> $DIR/recursive-in-exhaustiveness.rs:29:17 | -LL | (build2(x),) - | ^^^^^^^^^ types differ +LL | let (x,) = (build2(x),); + | ^^^^^^^^^ cannot infer type -error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:30:5 +error[E0282]: type annotations needed + --> $DIR/recursive-in-exhaustiveness.rs:40:5 | -LL | (build2(x),) - | ^^^^^^^^^^^^ types differ +LL | build3(x) + | ^^^^^^^^^ cannot infer type -error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time - --> $DIR/recursive-in-exhaustiveness.rs:30:5 - | -LL | (build2(x),) - | ^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(impl Sized,)` - = note: tuples must have a statically known size to be initialized - -error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:41:17 - | -LL | let (x,) = (build3((x,)),); - | ^^^^^^^^^^^^ types differ - -error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time - --> $DIR/recursive-in-exhaustiveness.rs:41:16 - | -LL | let (x,) = (build3((x,)),); - | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(impl Sized,)` - = note: tuples must have a statically known size to be initialized - -error[E0308]: mismatched types - --> $DIR/recursive-in-exhaustiveness.rs:41:16 - | -LL | fn build3<T>(x: T) -> impl Sized { - | ---------- the found opaque type -LL | -LL | let (x,) = (build3((x,)),); - | ^^^^^^^^^^^^^^^ types differ - | - = note: expected type `_` - found tuple `(impl Sized,)` - -error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:41:17 - | -LL | let (x,) = (build3((x,)),); - | ^^^^^^^^^^^^ types differ - | - = note: the return type of a function must have a statically known size - -error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:41:16 - | -LL | let (x,) = (build3((x,)),); - | ^^^^^^^^^^^^^^^ types differ - -error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:41:17 - | -LL | let (x,) = (build3((x,)),); - | ^^^^^^^^^^^^ types differ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 10 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0271, E0277, E0284, E0308. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs index dabef22af86..7aee8a630a5 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs @@ -17,8 +17,8 @@ fn build<T>(x: T) -> impl Sized { //[current]~^ ERROR cannot resolve opaque type let (x,) = (build(x),); + //[next]~^ ERROR type annotations needed build(x) - //[next]~^ ERROR type annotations needed: cannot normalize `build<_>::{opaque#0}` } // Opaque<T> = (Opaque<T>,) @@ -27,10 +27,8 @@ fn build<T>(x: T) -> impl Sized { fn build2<T>(x: T) -> impl Sized { //[current]~^ ERROR cannot resolve opaque type let (x,) = (build2(x),); + //[next]~^ ERROR type annotations needed (build2(x),) - //[next]~^ ERROR type mismatch resolving - //[next]~| ERROR type mismatch resolving - //[next]~| ERROR the size for values of type } // Opaque<T> = Opaque<(T,)> @@ -39,13 +37,8 @@ fn build2<T>(x: T) -> impl Sized { fn build3<T>(x: T) -> impl Sized { //[current]~^ ERROR cannot resolve opaque type let (x,) = (build3((x,)),); - //[next]~^ ERROR type mismatch resolving - //[next]~| ERROR type mismatch resolving - //[next]~| ERROR type mismatch resolving - //[next]~| ERROR type mismatch resolving - //[next]~| ERROR the size for values of type - //[next]~| ERROR mismatched types build3(x) + //[next]~^ ERROR type annotations needed } fn main() {} diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr index fac4776905d..785e5fdeb64 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr @@ -1,9 +1,15 @@ error[E0282]: type annotations needed - --> $DIR/two_tait_defining_each_other2.rs:12:11 + --> $DIR/two_tait_defining_each_other2.rs:12:8 | LL | fn muh(x: A) -> B { - | ^ cannot infer type + | ^ cannot infer type -error: aborting due to 1 previous error +error[E0282]: type annotations needed + --> $DIR/two_tait_defining_each_other2.rs:14:5 + | +LL | x // B's hidden type is A (opaquely) + | ^ cannot infer type + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs index ec2963249f9..99262f4bc4b 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs @@ -12,7 +12,8 @@ trait Foo {} fn muh(x: A) -> B { //[next]~^ ERROR: type annotations needed x // B's hidden type is A (opaquely) - //[current]~^ ERROR opaque type's hidden type cannot be another opaque type + //[next]~^ ERROR: type annotations needed + //[current]~^^ ERROR opaque type's hidden type cannot be another opaque type } struct Bar; diff --git a/tests/ui/issues/issue-29466.rs b/tests/ui/issues/issue-29466.rs index dbc37506a17..3962940e848 100644 --- a/tests/ui/issues/issue-29466.rs +++ b/tests/ui/issues/issue-29466.rs @@ -2,6 +2,9 @@ // //@ run-pass +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo-level=0 +//@ compile-flags: -Cdebuginfo=0 + #![allow(unused_variables)] macro_rules! m( diff --git a/tests/ui/limits/huge-enum.rs b/tests/ui/limits/huge-enum.rs index 66c5be20693..6d5b86411f3 100644 --- a/tests/ui/limits/huge-enum.rs +++ b/tests/ui/limits/huge-enum.rs @@ -2,6 +2,9 @@ //@ normalize-stderr: "std::option::Option<\[u32; \d+\]>" -> "TYPE" //@ normalize-stderr: "\[u32; \d+\]" -> "TYPE" +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo-level=0 +//@ compile-flags: -Cdebuginfo=0 + #[cfg(target_pointer_width = "32")] type BIG = Option<[u32; (1<<29)-1]>; diff --git a/tests/ui/limits/huge-enum.stderr b/tests/ui/limits/huge-enum.stderr index 18168b3fa5c..5b97a2104a3 100644 --- a/tests/ui/limits/huge-enum.stderr +++ b/tests/ui/limits/huge-enum.stderr @@ -1,5 +1,5 @@ error: values of the type `Option<TYPE>` are too big for the target architecture - --> $DIR/huge-enum.rs:12:9 + --> $DIR/huge-enum.rs:15:9 | LL | let big: BIG = None; | ^^^ diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs index d345cbc0f07..c2ccba7f9ba 100644 --- a/tests/ui/lint/inert-attr-macro.rs +++ b/tests/ui/lint/inert-attr-macro.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(rustc_attrs)] #![warn(unused)] macro_rules! foo { @@ -8,16 +7,18 @@ macro_rules! foo { } fn main() { - #[rustc_dummy] foo!(); //~ WARN unused attribute `rustc_dummy` + #[inline] foo!(); //~ WARN `#[inline]` attribute cannot be used on macro calls + //~^ WARN previously accepted // This does nothing, since `#[allow(warnings)]` is itself // an inert attribute on a macro call - #[allow(warnings)] #[rustc_dummy] foo!(); //~ WARN unused attribute `allow` - //~^ WARN unused attribute `rustc_dummy` + #[allow(warnings)] #[inline] foo!(); //~ WARN unused attribute `allow` + //~^ WARN `#[inline]` attribute cannot be used on macro calls + //~| WARN previously accepted // This does work, since the attribute is on a parent // of the macro invocation. - #[allow(warnings)] { #[rustc_dummy] foo!(); } + #[allow(warnings)] { #[inline] foo!(); } // Ok, `cfg` and `cfg_attr` are expanded eagerly and do not warn. #[cfg(true)] foo!(); diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr index fc02ee34ae6..9ab6e3ddc74 100644 --- a/tests/ui/lint/inert-attr-macro.stderr +++ b/tests/ui/lint/inert-attr-macro.stderr @@ -1,16 +1,13 @@ -warning: unused attribute `rustc_dummy` - --> $DIR/inert-attr-macro.rs:11:5 +warning: `#[inline]` attribute cannot be used on macro calls + --> $DIR/inert-attr-macro.rs:10:5 | -LL | #[rustc_dummy] foo!(); - | ^^^^^^^^^^^^^^ +LL | #[inline] foo!(); + | ^^^^^^^^^ | -note: the built-in attribute `rustc_dummy` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:11:20 - | -LL | #[rustc_dummy] foo!(); - | ^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[inline]` can only be applied to functions note: the lint level is defined here - --> $DIR/inert-attr-macro.rs:4:9 + --> $DIR/inert-attr-macro.rs:3:9 | LL | #![warn(unused)] | ^^^^^^ @@ -19,26 +16,23 @@ LL | #![warn(unused)] warning: unused attribute `allow` --> $DIR/inert-attr-macro.rs:15:5 | -LL | #[allow(warnings)] #[rustc_dummy] foo!(); +LL | #[allow(warnings)] #[inline] foo!(); | ^^^^^^^^^^^^^^^^^^ | note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:15:39 + --> $DIR/inert-attr-macro.rs:15:34 | -LL | #[allow(warnings)] #[rustc_dummy] foo!(); - | ^^^ +LL | #[allow(warnings)] #[inline] foo!(); + | ^^^ -warning: unused attribute `rustc_dummy` +warning: `#[inline]` attribute cannot be used on macro calls --> $DIR/inert-attr-macro.rs:15:24 | -LL | #[allow(warnings)] #[rustc_dummy] foo!(); - | ^^^^^^^^^^^^^^ - | -note: the built-in attribute `rustc_dummy` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:15:39 +LL | #[allow(warnings)] #[inline] foo!(); + | ^^^^^^^^^ | -LL | #[allow(warnings)] #[rustc_dummy] foo!(); - | ^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[inline]` can only be applied to functions warning: 3 warnings emitted diff --git a/tests/ui/lint/linker-warning.stderr b/tests/ui/lint/linker-warning.stderr index c678562ab54..ae5f6b3adec 100644 --- a/tests/ui/lint/linker-warning.stderr +++ b/tests/ui/lint/linker-warning.stderr @@ -1,4 +1,4 @@ -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` +warning: crate-level attribute should be an inner attribute --> $DIR/linker-warning.rs:7:1 | LL | #[allow(linker_messages)] @@ -9,6 +9,10 @@ note: the lint level is defined here | LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ +help: add a `!` + | +LL | #![allow(linker_messages)] + | + warning: unused attribute --> $DIR/linker-warning.rs:4:1 diff --git a/tests/ui/lint/lint-misplaced-attr.stderr b/tests/ui/lint/lint-misplaced-attr.stderr index abaf4620e6f..bcfda170080 100644 --- a/tests/ui/lint/lint-misplaced-attr.stderr +++ b/tests/ui/lint/lint-misplaced-attr.stderr @@ -10,11 +10,16 @@ note: the lint level is defined here LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` +error: crate-level attribute should be an inner attribute --> $DIR/lint-misplaced-attr.rs:10:1 | LL | #[crate_type = "bin"] fn main() {} | ^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `!` + | +LL | #![crate_type = "bin"] fn main() {} + | + error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs index 37fbf93ffa1..c507b6590c2 100644 --- a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs +++ b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs @@ -1,7 +1,7 @@ #![deny(unused)] #[crate_name = concat !()] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo] +//~^ ERROR crate-level attribute should be an inner attribute macro_rules! a { //~^ ERROR unused macro definition () => {}; diff --git a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr index 4ffb55d493a..b06e65af7bc 100644 --- a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr +++ b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr @@ -11,12 +11,20 @@ LL | #![deny(unused)] | ^^^^^^ = note: `#[deny(unused_macros)]` implied by `#[deny(unused)]` -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` --> $DIR/concat-in-crate-name-issue-137687.rs:3:1 | LL | #[crate_name = concat !()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: This attribute does not have an `!`, which means it is applied to this macro def + --> $DIR/concat-in-crate-name-issue-137687.rs:5:1 + | +LL | / macro_rules! a { +LL | | +LL | | () => {}; +LL | | } + | |_^ = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.stderr b/tests/ui/lint/unused/unused-attr-macro-rules.stderr index 9d61120463c..af64be8f6e9 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.stderr +++ b/tests/ui/lint/unused/unused-attr-macro-rules.stderr @@ -1,4 +1,4 @@ -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` +error: crate-level attribute should be an inner attribute --> $DIR/unused-attr-macro-rules.rs:11:1 | LL | #[recursion_limit="1"] @@ -9,6 +9,10 @@ note: the lint level is defined here | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ +help: add a `!` + | +LL | #![recursion_limit="1"] + | + error: `#[macro_use]` attribute cannot be used on macro defs --> $DIR/unused-attr-macro-rules.rs:7:1 diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed index 6bc63c8ee5b..fa596da95cc 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.fixed +++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed @@ -65,7 +65,6 @@ extern "Rust" { fn foreign_foo() -> i64; } - //~ ERROR unused attribute //~^ ERROR `#[must_use]` attribute cannot be used on macro calls //~| WARN this was previously accepted by the compiler but is being phased out global_asm!(""); diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs index 3c0d76e619f..3e72dd1e438 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.rs +++ b/tests/ui/lint/unused/unused_attributes-must_use.rs @@ -65,7 +65,7 @@ extern "Rust" { fn foreign_foo() -> i64; } -#[must_use] //~ ERROR unused attribute +#[must_use] //~^ ERROR `#[must_use]` attribute cannot be used on macro calls //~| WARN this was previously accepted by the compiler but is being phased out global_asm!(""); diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 231d799057c..001ec52ddd9 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -12,18 +12,6 @@ note: the lint level is defined here LL | #![deny(unused_attributes, unused_must_use)] | ^^^^^^^^^^^^^^^^^ -error: unused attribute `must_use` - --> $DIR/unused_attributes-must_use.rs:68:1 - | -LL | #[must_use] - | ^^^^^^^^^^^ - | -note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm` - --> $DIR/unused_attributes-must_use.rs:71:1 - | -LL | global_asm!(""); - | ^^^^^^^^^^ - error: `#[must_use]` attribute cannot be used on extern crates --> $DIR/unused_attributes-must_use.rs:7:1 | @@ -295,5 +283,5 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = ().get_four(); | +++++++ -error: aborting due to 30 previous errors +error: aborting due to 29 previous errors diff --git a/tests/ui/panics/issue-47429-short-backtraces.rs b/tests/ui/panics/issue-47429-short-backtraces.rs index 378ade67bfd..21428d876e2 100644 --- a/tests/ui/panics/issue-47429-short-backtraces.rs +++ b/tests/ui/panics/issue-47429-short-backtraces.rs @@ -6,6 +6,9 @@ //@ check-run-results //@ exec-env:RUST_BACKTRACE=1 +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo-level=0 +//@ compile-flags: -Cdebuginfo=0 + // This is needed to avoid test output differences across std being built with v0 symbols vs legacy // symbols. //@ normalize-stderr: "begin_panic::<&str>" -> "begin_panic" diff --git a/tests/ui/panics/issue-47429-short-backtraces.run.stderr b/tests/ui/panics/issue-47429-short-backtraces.run.stderr index 13b59a7c7af..32aa6a3502e 100644 --- a/tests/ui/panics/issue-47429-short-backtraces.run.stderr +++ b/tests/ui/panics/issue-47429-short-backtraces.run.stderr @@ -1,5 +1,5 @@ -thread 'main' ($TID) panicked at $DIR/issue-47429-short-backtraces.rs:24:5: +thread 'main' ($TID) panicked at $DIR/issue-47429-short-backtraces.rs:27:5: explicit panic stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/panics/runtime-switch.rs b/tests/ui/panics/runtime-switch.rs index 7d5b4169340..61c07a97c70 100644 --- a/tests/ui/panics/runtime-switch.rs +++ b/tests/ui/panics/runtime-switch.rs @@ -6,6 +6,9 @@ //@ check-run-results //@ exec-env:RUST_BACKTRACE=0 +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo-level=0 +//@ compile-flags: -Cdebuginfo=0 + // This is needed to avoid test output differences across std being built with v0 symbols vs legacy // symbols. //@ normalize-stderr: "begin_panic::<&str>" -> "begin_panic" diff --git a/tests/ui/panics/runtime-switch.run.stderr b/tests/ui/panics/runtime-switch.run.stderr index f3f60445952..48a12b59b69 100644 --- a/tests/ui/panics/runtime-switch.run.stderr +++ b/tests/ui/panics/runtime-switch.run.stderr @@ -1,5 +1,5 @@ -thread 'main' ($TID) panicked at $DIR/runtime-switch.rs:28:5: +thread 'main' ($TID) panicked at $DIR/runtime-switch.rs:31:5: explicit panic stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/resolve/issue-102946.rs b/tests/ui/resolve/issue-102946.rs index c6feca6f32f..8d90e61bb5d 100644 --- a/tests/ui/resolve/issue-102946.rs +++ b/tests/ui/resolve/issue-102946.rs @@ -1,7 +1,6 @@ impl Error for str::Utf8Error { //~^ ERROR cannot find trait `Error` in this scope //~| ERROR ambiguous associated type - fn description(&self) {} } fn main() {} diff --git a/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.fixed b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.fixed new file mode 100644 index 00000000000..2835743fca2 --- /dev/null +++ b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.fixed @@ -0,0 +1,13 @@ +//@ run-rustfix + +use std::fmt::Display; + +struct S; + +impl S { + fn call(&self, _: impl Display) {} +} + +fn main() { + S.call((|| "hello")()); //~ ERROR [E0277] +} diff --git a/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.rs b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.rs new file mode 100644 index 00000000000..848629a6700 --- /dev/null +++ b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.rs @@ -0,0 +1,13 @@ +//@ run-rustfix + +use std::fmt::Display; + +struct S; + +impl S { + fn call(&self, _: impl Display) {} +} + +fn main() { + S.call(|| "hello"); //~ ERROR [E0277] +} diff --git a/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.stderr b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.stderr new file mode 100644 index 00000000000..cb6df5af7fb --- /dev/null +++ b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.stderr @@ -0,0 +1,23 @@ +error[E0277]: `{closure@$DIR/use-parentheses-to-call-closure-issue-145404.rs:12:12: 12:14}` doesn't implement `std::fmt::Display` + --> $DIR/use-parentheses-to-call-closure-issue-145404.rs:12:12 + | +LL | S.call(|| "hello"); + | ---- ^^^^^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | + = help: the trait `std::fmt::Display` is not implemented for closure `{closure@$DIR/use-parentheses-to-call-closure-issue-145404.rs:12:12: 12:14}` +note: required by a bound in `S::call` + --> $DIR/use-parentheses-to-call-closure-issue-145404.rs:8:28 + | +LL | fn call(&self, _: impl Display) {} + | ^^^^^^^ required by this bound in `S::call` +help: use parentheses to call this closure + | +LL - S.call(|| "hello"); +LL + S.call((|| "hello")()); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/opaques/different-bound-vars.current.stderr b/tests/ui/traits/next-solver/opaques/different-bound-vars.current.stderr new file mode 100644 index 00000000000..32e92e46a88 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/different-bound-vars.current.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/different-bound-vars.rs:13:37 + | +LL | let _: for<'b> fn(&'b ()) = foo::<U, T>(false); + | ^^^^^^^^^^^^^^^^^^ expected `for<'a> fn(&'a ())`, got `for<'b> fn(&'b ())` + | +note: previous use here + --> $DIR/different-bound-vars.rs:12:37 + | +LL | let _: for<'a> fn(&'a ()) = foo::<T, U>(false); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/next-solver/opaques/different-bound-vars.rs b/tests/ui/traits/next-solver/opaques/different-bound-vars.rs new file mode 100644 index 00000000000..5801a5edeb4 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/different-bound-vars.rs @@ -0,0 +1,20 @@ +// Check whether we support defining uses with different bound vars. +// This needs to handle both mismatches for the same opaque type storage +// entry, but also between different entries. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +fn foo<T, U>(b: bool) -> impl Sized { + if b { + let _: for<'a> fn(&'a ()) = foo::<T, U>(false); + let _: for<'b> fn(&'b ()) = foo::<U, T>(false); + //[current]~^ ERROR concrete type differs from previous defining opaque type use + } + + (|&()| ()) as for<'c> fn(&'c ()) +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr index 6d2bbd8b08b..a188629a475 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr @@ -1,16 +1,9 @@ -error[E0283]: type annotations needed: cannot satisfy `Foo: Send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 +error[E0282]: type annotations needed + --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:12 | -LL | needs_send::<Foo>(); - | ^^^ - | - = note: cannot satisfy `Foo: Send` -note: required by a bound in `needs_send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 - | -LL | fn needs_send<T: Send>() {} - | ^^^^ required by this bound in `needs_send` +LL | fn test(_: Foo) { + | ^^^ cannot infer type error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr index 6d2bbd8b08b..a188629a475 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -1,16 +1,9 @@ -error[E0283]: type annotations needed: cannot satisfy `Foo: Send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 +error[E0282]: type annotations needed + --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:12 | -LL | needs_send::<Foo>(); - | ^^^ - | - = note: cannot satisfy `Foo: Send` -note: required by a bound in `needs_send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 - | -LL | fn needs_send<T: Send>() {} - | ^^^^ required by this bound in `needs_send` +LL | fn test(_: Foo) { + | ^^^ cannot infer type error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs index fddf892e1ef..8ff99d32f06 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs @@ -13,8 +13,8 @@ fn needs_send<T: Send>() {} #[define_opaque(Foo)] fn test(_: Foo) { - needs_send::<Foo>(); //~^ ERROR type annotations needed + needs_send::<Foo>(); } #[define_opaque(Foo)] diff --git a/tests/ui/traits/next-solver/opaques/non-defining-use-hir-typeck.rs b/tests/ui/traits/next-solver/opaques/non-defining-use-hir-typeck.rs new file mode 100644 index 00000000000..a55be5fde9e --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/non-defining-use-hir-typeck.rs @@ -0,0 +1,28 @@ +//@ ignore-compare-mode-next-solver +//@ compile-flags: -Znext-solver +//@ check-pass +#![feature(type_alias_impl_trait)] + +// Make sure that we support non-defining uses in HIR typeck. +// Regression test for trait-system-refactor-initiative#135. + +fn non_defining_recurse<T>(b: bool) -> impl Sized { + if b { + // This results in an opaque type use `opaque<()> = ?unconstrained` + // during HIR typeck. + non_defining_recurse::<()>(false); + } +} + +trait Eq<T, U> {} +impl<T> Eq<T, T> for () {} +fn is_eq<T: Eq<U, V>, U, V>() {} +type Tait<T> = impl Sized; +#[define_opaque(Tait)] +fn non_defining_explicit<T>() { + is_eq::<(), Tait<_>, u32>(); // constrains opaque type args via hidden type + is_eq::<(), Tait<u64>, _>(); // constraints hidden type via args + is_eq::<(), Tait<T>, T>(); // actually defines +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs b/tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs new file mode 100644 index 00000000000..5e7e9738616 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs @@ -0,0 +1,16 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// The recursive call to `foo` results in the opaque type use `opaque<U, T> = ?unconstrained`. +// This needs to be supported and treated as a revealing use. + +fn foo<T, U>(b: bool) -> impl Sized { + if b { + foo::<U, T>(b); + } + 1u16 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr index 72a253c4be8..b50d1b60c43 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr @@ -1,24 +1,9 @@ -error[E0283]: type annotations needed: cannot satisfy `Foo: Trait<Bar>` - --> $DIR/constrain_in_projection2.rs:28:14 +error[E0282]: type annotations needed + --> $DIR/constrain_in_projection2.rs:28:13 | LL | let x = <Foo as Trait<Bar>>::Assoc::default(); - | ^^^ - | -note: multiple `impl`s satisfying `Foo: Trait<Bar>` found - --> $DIR/constrain_in_projection2.rs:18:1 - | -LL | impl Trait<()> for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^ -... -LL | impl Trait<u32> for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl` -help: use the fully qualified path to an implementation - | -LL - let x = <Foo as Trait<Bar>>::Assoc::default(); -LL + let x = <<Type as Trait>::Assoc as Trait<Bar>>::Assoc::default(); - | + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs b/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs index 61773cf59d4..c4aa6f32eab 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.rs @@ -26,7 +26,7 @@ impl Trait<u32> for Foo { #[define_opaque(Bar)] fn bop() { let x = <Foo as Trait<Bar>>::Assoc::default(); - //[next]~^ ERROR: cannot satisfy `Foo: Trait<Bar>` + //[next]~^ ERROR: type annotations needed //[current]~^^ ERROR: `Foo: Trait<Bar>` is not satisfied //[current]~| ERROR: `Foo: Trait<Bar>` is not satisfied } diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.current.stderr index 71e415271ee..2a78860689b 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.current.stderr @@ -1,5 +1,5 @@ error[E0792]: expected generic type parameter, found `u32` - --> $DIR/generic_nondefining_use.rs:16:21 + --> $DIR/generic_nondefining_use.rs:20:21 | LL | type OneTy<T> = impl Debug; | - this generic parameter must be used with a generic type parameter @@ -8,7 +8,7 @@ LL | fn concrete_ty() -> OneTy<u32> { | ^^^^^^^^^^ error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/generic_nondefining_use.rs:23:5 + --> $DIR/generic_nondefining_use.rs:29:5 | LL | type OneLifetime<'a> = impl Debug; | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type @@ -17,7 +17,7 @@ LL | 6u32 | ^^^^ error[E0792]: expected generic constant parameter, found `123` - --> $DIR/generic_nondefining_use.rs:28:24 + --> $DIR/generic_nondefining_use.rs:35:24 | LL | type OneConst<const X: usize> = impl Debug; | -------------- this generic parameter must be used with a generic constant parameter diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.next.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.next.stderr new file mode 100644 index 00000000000..2b53614ee3f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.next.stderr @@ -0,0 +1,44 @@ +error: item does not constrain `OneTy::{opaque#0}` + --> $DIR/generic_nondefining_use.rs:20:4 + | +LL | fn concrete_ty() -> OneTy<u32> { + | ^^^^^^^^^^^ + | + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/generic_nondefining_use.rs:11:17 + | +LL | type OneTy<T> = impl Debug; + | ^^^^^^^^^^ +note: this use of `OneTy<u32>` does not have unique universal generic arguments + --> $DIR/generic_nondefining_use.rs:23:5 + | +LL | 5u32 + | ^^^^ + +error: non-defining use of `OneLifetime<'_>` in the defining scope + --> $DIR/generic_nondefining_use.rs:27:1 + | +LL | fn concrete_lifetime() -> OneLifetime<'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: item does not constrain `OneConst::{opaque#0}` + --> $DIR/generic_nondefining_use.rs:35:4 + | +LL | fn concrete_const() -> OneConst<{ 123 }> { + | ^^^^^^^^^^^^^^ + | + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/generic_nondefining_use.rs:15:33 + | +LL | type OneConst<const X: usize> = impl Debug; + | ^^^^^^^^^^ +note: this use of `OneConst<123>` does not have unique universal generic arguments + --> $DIR/generic_nondefining_use.rs:38:5 + | +LL | 7u32 + | ^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs index cf38c93bd92..7250a9ac0b3 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs @@ -1,5 +1,9 @@ #![feature(type_alias_impl_trait)] +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + use std::fmt::Debug; fn main() {} @@ -14,18 +18,22 @@ type OneConst<const X: usize> = impl Debug; #[define_opaque(OneTy)] fn concrete_ty() -> OneTy<u32> { - //~^ ERROR: expected generic type parameter, found `u32` + //[current]~^ ERROR: expected generic type parameter, found `u32` + //[next]~^^ ERROR: item does not constrain `OneTy::{opaque#0}` 5u32 } #[define_opaque(OneLifetime)] fn concrete_lifetime() -> OneLifetime<'static> { + //[next]~^ ERROR: non-defining use of `OneLifetime<'_>` in the defining scope 6u32 - //~^ ERROR: expected generic lifetime parameter, found `'static` + //[current]~^ ERROR: expected generic lifetime parameter, found `'static` + } #[define_opaque(OneConst)] fn concrete_const() -> OneConst<{ 123 }> { - //~^ ERROR: expected generic constant parameter, found `123` + //[current]~^ ERROR: expected generic constant parameter, found `123` + //[next]~^^ ERROR: item does not constrain `OneConst::{opaque#0}` 7u32 } diff --git a/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs b/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs index 987fad2efea..476babdfb05 100644 --- a/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs +++ b/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs @@ -1,6 +1,6 @@ //@ check-pass -use std::error::Error as StdError; +use std::error::Error; use std::pin::Pin; use std::task::{Context, Poll}; @@ -51,7 +51,7 @@ impl<S> Stream for SseKeepAlive<S> where S: TryStream + Send + 'static, S::Ok: ServerSentEvent, - S::Error: StdError + Send + Sync + 'static, + S::Error: Error + Send + Sync + 'static, { type Item = Result<SseComment<&'static str>, ()>; fn poll_next(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Option<Self::Item>> { @@ -65,7 +65,7 @@ pub fn keep<S>( where S: TryStream + Send + 'static, S::Ok: ServerSentEvent + Send, - S::Error: StdError + Send + Sync + 'static, + S::Error: Error + Send + Sync + 'static, { SseKeepAlive { event_stream } } diff --git a/tests/ui/type-alias-impl-trait/normalize-args-before-defining-use-check.rs b/tests/ui/type-alias-impl-trait/normalize-args-before-defining-use-check.rs new file mode 100644 index 00000000000..2879b8fe94c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/normalize-args-before-defining-use-check.rs @@ -0,0 +1,33 @@ +#![feature(type_alias_impl_trait)] + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#49. + +trait Mirror<'a> { + type Assoc; +} +impl<'a, T> Mirror<'a> for T { + type Assoc = T; +} + +type HrAmbigAlias<T> = impl Sized; +fn ret_tait<T>() -> for<'a> fn(HrAmbigAlias<<T as Mirror<'a>>::Assoc>) { + |_| () +} + +#[define_opaque(HrAmbigAlias)] +fn define_hr_ambig_alias<T>() { + let _: fn(T) = ret_tait::<T>(); +} + +type InUserType<T> = impl Sized; +#[define_opaque(InUserType)] +fn in_user_type<T>() { + let x: InUserType<<T as Mirror<'static>>::Assoc> = (); +} + +fn main() {} |
