Rollup merge of #143066 - compiler-errors:let-chain-solver, r=lcnr
Use let chains in the new solver
Self-explanatory
Let chains are stable as of today
r? lcnr
diff --git a/Cargo.lock b/Cargo.lock
index e95cacf..110d171 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -367,6 +367,26 @@
]
[[package]]
+name = "capstone"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
+dependencies = [
+ "capstone-sys",
+ "libc",
+]
+
+[[package]]
+name = "capstone-sys"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
name = "cargo-miri"
version = "0.1.0"
dependencies = [
@@ -537,7 +557,7 @@
[[package]]
name = "clippy"
-version = "0.1.89"
+version = "0.1.90"
dependencies = [
"anstream",
"askama",
@@ -547,6 +567,7 @@
"clippy_lints_internal",
"clippy_utils",
"color-print",
+ "declare_clippy_lint",
"filetime",
"futures",
"if_chain",
@@ -569,7 +590,7 @@
[[package]]
name = "clippy_config"
-version = "0.1.89"
+version = "0.1.90"
dependencies = [
"clippy_utils",
"itertools",
@@ -592,12 +613,13 @@
[[package]]
name = "clippy_lints"
-version = "0.1.89"
+version = "0.1.90"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.1",
"clippy_config",
"clippy_utils",
+ "declare_clippy_lint",
"itertools",
"quine-mc_cluskey",
"regex-syntax 0.8.5",
@@ -622,7 +644,7 @@
[[package]]
name = "clippy_utils"
-version = "0.1.89"
+version = "0.1.90"
dependencies = [
"arrayvec",
"itertools",
@@ -736,7 +758,7 @@
"tracing-subscriber",
"unified-diff",
"walkdir",
- "windows",
+ "windows 0.61.3",
]
[[package]]
@@ -932,6 +954,10 @@
]
[[package]]
+name = "declare_clippy_lint"
+version = "0.1.90"
+
+[[package]]
name = "derive-where"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1586,7 +1612,7 @@
"js-sys",
"log",
"wasm-bindgen",
- "windows-core",
+ "windows-core 0.61.2",
]
[[package]]
@@ -1911,6 +1937,25 @@
]
[[package]]
+name = "ipc-channel"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fb8251fb7bcd9ccd3725ed8deae9fe7db8e586495c9eb5b0c52e6233e5e75ea"
+dependencies = [
+ "bincode",
+ "crossbeam-channel",
+ "fnv",
+ "lazy_static",
+ "libc",
+ "mio",
+ "rand 0.8.5",
+ "serde",
+ "tempfile",
+ "uuid",
+ "windows 0.58.0",
+]
+
+[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2296,6 +2341,18 @@
]
[[package]]
+name = "mio"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "miow"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2310,18 +2367,22 @@
dependencies = [
"aes",
"bitflags",
+ "capstone",
"chrono",
"chrono-tz",
"colored",
"directories",
"getrandom 0.3.3",
+ "ipc-channel",
"libc",
"libffi",
"libloading",
"measureme",
+ "nix",
"rand 0.9.1",
"regex",
"rustc_version",
+ "serde",
"smallvec",
"tempfile",
"tikv-jemalloc-sys",
@@ -3513,7 +3574,7 @@
"thorin-dwp",
"tracing",
"wasm-encoder 0.219.2",
- "windows",
+ "windows 0.61.3",
]
[[package]]
@@ -3572,7 +3633,7 @@
"tempfile",
"thin-vec",
"tracing",
- "windows",
+ "windows 0.61.3",
]
[[package]]
@@ -3635,7 +3696,7 @@
"shlex",
"stable_mir",
"tracing",
- "windows",
+ "windows 0.61.3",
]
[[package]]
@@ -3690,7 +3751,7 @@
"termcolor",
"termize",
"tracing",
- "windows",
+ "windows 0.61.3",
]
[[package]]
@@ -4451,7 +4512,7 @@
"rustc_target",
"termize",
"tracing",
- "windows",
+ "windows 0.61.3",
]
[[package]]
@@ -5136,7 +5197,7 @@
"libc",
"objc2-core-foundation",
"objc2-io-kit",
- "windows",
+ "windows 0.61.3",
]
[[package]]
@@ -6030,12 +6091,22 @@
[[package]]
name = "windows"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
+dependencies = [
+ "windows-core 0.58.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows"
version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections",
- "windows-core",
+ "windows-core 0.61.2",
"windows-future",
"windows-link",
"windows-numerics",
@@ -6058,7 +6129,20 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
- "windows-core",
+ "windows-core 0.61.2",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
+dependencies = [
+ "windows-implement 0.58.0",
+ "windows-interface 0.58.0",
+ "windows-result 0.2.0",
+ "windows-strings 0.1.0",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -6067,11 +6151,11 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
- "windows-implement",
- "windows-interface",
+ "windows-implement 0.60.0",
+ "windows-interface 0.59.1",
"windows-link",
- "windows-result",
- "windows-strings",
+ "windows-result 0.3.4",
+ "windows-strings 0.4.2",
]
[[package]]
@@ -6080,13 +6164,24 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
- "windows-core",
+ "windows-core 0.61.2",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.103",
+]
+
+[[package]]
+name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
@@ -6098,6 +6193,17 @@
[[package]]
name = "windows-interface"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.103",
+]
+
+[[package]]
+name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
@@ -6119,12 +6225,21 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
- "windows-core",
+ "windows-core 0.61.2",
"windows-link",
]
[[package]]
name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
@@ -6134,6 +6249,16 @@
[[package]]
name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result 0.2.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 6d729b6..0df8921 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1592,24 +1592,33 @@ pub enum TagEncoding<VariantIdx: Idx> {
/// (so converting the tag to the discriminant can require sign extension).
Direct,
- /// Niche (values invalid for a type) encoding the discriminant:
- /// Discriminant and variant index coincide.
- /// The variant `untagged_variant` contains a niche at an arbitrary
- /// offset (field `tag_field` of the enum), which for a variant with
- /// discriminant `d` is set to
- /// `(d - niche_variants.start).wrapping_add(niche_start)`
- /// (this is wrapping arithmetic using the type of the niche field).
+ /// Niche (values invalid for a type) encoding the discriminant.
+ /// Note that for this encoding, the discriminant and variant index of each variant coincide!
+ /// This invariant is codified as part of [`layout_sanity_check`](../rustc_ty_utils/layout/invariant/fn.layout_sanity_check.html).
///
- /// For example, `Option<(usize, &T)>` is represented such that
- /// `None` has a null pointer for the second tuple field, and
- /// `Some` is the identity function (with a non-null reference).
+ /// The variant `untagged_variant` contains a niche at an arbitrary
+ /// offset (field [`Variants::Multiple::tag_field`] of the enum).
+ /// For a variant with variant index `i`, such that `i != untagged_variant`,
+ /// the tag is set to `(i - niche_variants.start).wrapping_add(niche_start)`
+ /// (this is wrapping arithmetic using the type of the niche field, cf. the
+ /// [`tag_for_variant`](../rustc_const_eval/interpret/struct.InterpCx.html#method.tag_for_variant)
+ /// query implementation).
+ /// To recover the variant index `i` from a `tag`, the above formula has to be reversed,
+ /// i.e. `i = tag.wrapping_sub(niche_start) + niche_variants.start`. If `i` ends up outside
+ /// `niche_variants`, the tag must have encoded the `untagged_variant`.
+ ///
+ /// For example, `Option<(usize, &T)>` is represented such that the tag for
+ /// `None` is the null pointer in the second tuple field, and
+ /// `Some` is the identity function (with a non-null reference)
+ /// and has no additional tag, i.e. the reference being non-null uniquely identifies this variant.
///
/// Other variants that are not `untagged_variant` and that are outside the `niche_variants`
/// range cannot be represented; they must be uninhabited.
+ /// Nonetheless, uninhabited variants can also fall into the range of `niche_variants`.
Niche {
untagged_variant: VariantIdx,
- /// This range *may* contain `untagged_variant`; that is then just a "dead value" and
- /// not used to encode anything.
+ /// This range *may* contain `untagged_variant` or uninhabited variants;
+ /// these are then just "dead values" and not used to encode anything.
niche_variants: RangeInclusive<VariantIdx>,
/// This is inbounds of the type of the niche field
/// (not sign-extended, i.e., all bits beyond the niche field size are 0).
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d927298..b2d8881 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -323,7 +323,7 @@ pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId};
-/// Modifiers on a trait bound like `~const`, `?` and `!`.
+/// Modifiers on a trait bound like `[const]`, `?` and `!`.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
pub struct TraitBoundModifiers {
pub constness: BoundConstness,
@@ -3115,7 +3115,7 @@ pub enum BoundConstness {
Never,
/// `Type: const Trait`
Always(Span),
- /// `Type: ~const Trait`
+ /// `Type: [const] Trait`
Maybe(Span),
}
@@ -3124,7 +3124,7 @@ pub fn as_str(self) -> &'static str {
match self {
Self::Never => "",
Self::Always(_) => "const",
- Self::Maybe(_) => "~const",
+ Self::Maybe(_) => "[const]",
}
}
}
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 4fc7c74..896d1e1 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -16,10 +16,7 @@
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(macro_metavar_expr)]
-#![feature(negative_impls)]
-#![feature(never_type)]
#![feature(rustdoc_internals)]
-#![feature(stmt_expr_attributes)]
#![recursion_limit = "256"]
// tidy-alphabetical-end
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 9b4535d..fc816f2 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -893,7 +893,7 @@ pub fn is_path_start(&self) -> bool {
|| self.is_qpath_start()
|| matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
|| self.is_path_segment_keyword()
- || self.is_ident() && !self.is_reserved_ident()
+ || self.is_non_reserved_ident()
}
/// Returns `true` if the token is a given keyword, `kw`.
@@ -937,6 +937,10 @@ pub fn is_reserved_ident(&self) -> bool {
self.is_non_raw_ident_where(Ident::is_reserved)
}
+ pub fn is_non_reserved_ident(&self) -> bool {
+ self.ident().is_some_and(|(id, raw)| raw == IdentIsRaw::Yes || !Ident::is_reserved(id))
+ }
+
/// Returns `true` if the token is the identifier `true` or `false`.
pub fn is_bool_lit(&self) -> bool {
self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 3c231be..c60185c 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -634,10 +634,8 @@ pub fn add_comma(&self) -> Option<(TokenStream, Span)> {
(
TokenTree::Token(token_left, Spacing::Alone),
TokenTree::Token(token_right, _),
- ) if ((token_left.is_ident() && !token_left.is_reserved_ident())
- || token_left.is_lit())
- && ((token_right.is_ident() && !token_right.is_reserved_ident())
- || token_right.is_lit()) =>
+ ) if (token_left.is_non_reserved_ident() || token_left.is_lit())
+ && (token_right.is_non_reserved_ident() || token_right.is_lit()) =>
{
token_left.span
}
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 6eddce7..4290f7b 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -237,17 +237,17 @@
free static item without body
.suggestion = provide a definition for the static
-ast_passes_tilde_const_disallowed = `~const` is not allowed here
- .closure = closures cannot have `~const` trait bounds
- .function = this function is not `const`, so it cannot have `~const` trait bounds
- .trait = this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
- .trait_impl = this impl is not `const`, so it cannot have `~const` trait bounds
- .impl = inherent impls cannot have `~const` trait bounds
- .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `~const` trait bounds
- .trait_impl_assoc_ty = associated types in non-const impls cannot have `~const` trait bounds
- .inherent_assoc_ty = inherent associated types cannot have `~const` trait bounds
- .object = trait objects cannot have `~const` trait bounds
- .item = this item cannot have `~const` trait bounds
+ast_passes_tilde_const_disallowed = `[const]` is not allowed here
+ .closure = closures cannot have `[const]` trait bounds
+ .function = this function is not `const`, so it cannot have `[const]` trait bounds
+ .trait = this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+ .trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds
+ .impl = inherent impls cannot have `[const]` trait bounds
+ .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds
+ .trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds
+ .inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds
+ .object = trait objects cannot have `[const]` trait bounds
+ .item = this item cannot have `[const]` trait bounds
ast_passes_trait_fn_const =
functions in {$in_impl ->
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index d755afa..5eb1931 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -131,6 +131,17 @@ pub fn is_since_rustc_version(&self) -> bool {
}
}
+/// There are three valid forms of the attribute:
+/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable.
+/// `#[used(compiler)]`
+/// `#[used(linker)]`
+#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic, PrintAttribute)]
+pub enum UsedBy {
+ Compiler,
+ Linker,
+}
+
/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
@@ -242,6 +253,9 @@ pub enum AttributeKind {
/// Represents `#[inline]` and `#[rustc_force_inline]`.
Inline(InlineAttr, Span),
+ /// Represents `#[link_name]`.
+ LinkName { name: Symbol, span: Span },
+
/// Represents `#[loop_match]`.
LoopMatch(Span),
@@ -285,5 +299,8 @@ pub enum AttributeKind {
/// Represents `#[track_caller]`
TrackCaller(Span),
+
+ /// Represents `#[used]`
+ Used { used_by: UsedBy, span: Span },
// tidy-alphabetical-end
}
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index d4402f4..0d6ee77 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -29,6 +29,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
Stability { .. } => Yes,
Cold(..) => No,
ConstContinue(..) => No,
+ LinkName { .. } => Yes,
LoopMatch(..) => No,
MayDangle(..) => No,
MustUse { .. } => Yes,
@@ -38,6 +39,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
PubTransparent(..) => Yes,
SkipDuringMethodDispatch { .. } => No,
TrackCaller(..) => Yes,
+ Used { .. } => No,
}
}
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 5a849e7..7c412d4 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -1,4 +1,4 @@
-use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
+use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
use rustc_feature::{AttributeTemplate, template};
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
@@ -228,3 +228,84 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<At
Some(AttributeKind::NoMangle(cx.attr_span))
}
}
+
+#[derive(Default)]
+pub(crate) struct UsedParser {
+ first_compiler: Option<Span>,
+ first_linker: Option<Span>,
+}
+
+// A custom `AttributeParser` is used rather than a Simple attribute parser because
+// - Specifying two `#[used]` attributes is a warning (but will be an error in the future)
+// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today
+// We can change this to a Simple parser once the warning becomes an error
+impl<S: Stage> AttributeParser<S> for UsedParser {
+ const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+ &[sym::used],
+ template!(Word, List: "compiler|linker"),
+ |group: &mut Self, cx, args| {
+ let used_by = match args {
+ ArgParser::NoArgs => UsedBy::Linker,
+ ArgParser::List(list) => {
+ let Some(l) = list.single() else {
+ cx.expected_single_argument(list.span);
+ return;
+ };
+
+ match l.meta_item().and_then(|i| i.path().word_sym()) {
+ Some(sym::compiler) => {
+ if !cx.features().used_with_arg() {
+ feature_err(
+ &cx.sess(),
+ sym::used_with_arg,
+ cx.attr_span,
+ "`#[used(compiler)]` is currently unstable",
+ )
+ .emit();
+ }
+ UsedBy::Compiler
+ }
+ Some(sym::linker) => {
+ if !cx.features().used_with_arg() {
+ feature_err(
+ &cx.sess(),
+ sym::used_with_arg,
+ cx.attr_span,
+ "`#[used(linker)]` is currently unstable",
+ )
+ .emit();
+ }
+ UsedBy::Linker
+ }
+ _ => {
+ cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
+ return;
+ }
+ }
+ }
+ ArgParser::NameValue(_) => return,
+ };
+
+ let target = match used_by {
+ UsedBy::Compiler => &mut group.first_compiler,
+ UsedBy::Linker => &mut group.first_linker,
+ };
+
+ let attr_span = cx.attr_span;
+ if let Some(prev) = *target {
+ cx.warn_unused_duplicate(prev, attr_span);
+ } else {
+ *target = Some(attr_span);
+ }
+ },
+ )];
+
+ fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
+ // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker`
+ Some(match (self.first_compiler, self.first_linker) {
+ (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span },
+ (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
+ (None, None) => return None,
+ })
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
new file mode 100644
index 0000000..7402221
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
@@ -0,0 +1,30 @@
+use rustc_attr_data_structures::AttributeKind;
+use rustc_attr_data_structures::AttributeKind::LinkName;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Symbol, sym};
+
+use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct LinkNameParser;
+
+impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
+ const PATH: &[Symbol] = &[sym::link_name];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+ const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+ const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+ let Some(nv) = args.name_value() else {
+ cx.expected_name_value(cx.attr_span, None);
+ return None;
+ };
+ let Some(name) = nv.value_as_str() else {
+ cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ return None;
+ };
+
+ Some(LinkName { name, span: cx.attr_span })
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index d407669..584dada 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -31,6 +31,7 @@
pub(crate) mod confusables;
pub(crate) mod deprecation;
pub(crate) mod inline;
+pub(crate) mod link_attrs;
pub(crate) mod lint_helpers;
pub(crate) mod loop_match;
pub(crate) mod must_use;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 83e3c75..1ac41b9 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -17,10 +17,12 @@
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::codegen_attrs::{
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
+ UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
+use crate::attributes::link_attrs::LinkNameParser;
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::must_use::MustUseParser;
@@ -103,6 +105,7 @@ mod late {
ConstStabilityParser,
NakedParser,
StabilityParser,
+ UsedParser,
// tidy-alphabetical-end
// tidy-alphabetical-start
@@ -119,6 +122,7 @@ mod late {
Single<DeprecationParser>,
Single<ExportNameParser>,
Single<InlineParser>,
+ Single<LinkNameParser>,
Single<LoopMatchParser>,
Single<MayDangleParser>,
Single<MustUseParser>,
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 0b641ba..1b68c65 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -407,6 +407,18 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
source_info.span,
)
}
+ AssertKind::InvalidEnumConstruction(source) => {
+ let source = codegen_operand(fx, source).load_scalar(fx);
+ let location = fx.get_caller_location(source_info).load_scalar(fx);
+
+ codegen_panic_inner(
+ fx,
+ rustc_hir::LangItem::PanicInvalidEnumConstruction,
+ &[source, location],
+ *unwind,
+ source_info.span,
+ )
+ }
_ => {
let location = fx.get_caller_location(source_info).load_scalar(fx);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 68ff0b6..6281089 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -496,7 +496,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
| sym::simd_flog
| sym::simd_flog10
| sym::simd_flog2
- | sym::simd_round => {
+ | sym::simd_round
+ | sym::simd_round_ties_even => {
intrinsic_args!(fx, args => (a); intrinsic);
if !a.layout().ty.is_simd() {
@@ -527,6 +528,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
(sym::simd_flog2, types::F64) => "log2",
(sym::simd_round, types::F32) => "roundf",
(sym::simd_round, types::F64) => "round",
+ (sym::simd_round_ties_even, types::F32) => "rintf",
+ (sym::simd_round_ties_even, types::F64) => "rint",
_ => unreachable!("{:?}", intrinsic),
};
fx.lib_call(
diff --git a/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs b/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs
new file mode 100644
index 0000000..3c1531b
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs
@@ -0,0 +1,65 @@
+use std::ffi::OsStr;
+use std::path::Path;
+
+use crate::utils::run_command_with_output;
+
+fn show_usage() {
+ println!(
+ r#"
+`abi-test` command help:
+ --help : Show this help"#
+ );
+}
+
+pub fn run() -> Result<(), String> {
+ let mut args = std::env::args().skip(2);
+ // FractalFir: In the future, I'd like to add some more subcommands / options.
+ // So, this loop ought to stay for that purpose. It should also stay as a while loop(to parse args)
+ #[allow(clippy::never_loop, clippy::while_let_on_iterator)]
+ while let Some(arg) = args.next() {
+ match arg.as_str() {
+ "--help" => {
+ show_usage();
+ return Ok(());
+ }
+ _ => return Err(format!("Unknown option {arg:?}")),
+ }
+ }
+ // Ensure that we have a cloned version of abi-cafe on hand.
+ crate::utils::git_clone(
+ "https://github.com/Gankra/abi-cafe.git",
+ Some("clones/abi-cafe".as_ref()),
+ true,
+ )
+ .map_err(|err| (format!("Git clone failed with message: {err:?}!")))?;
+ // Configure abi-cafe to use the exact same rustc version we use - this is crucial.
+ // Otherwise, the concept of ABI compatibility becomes meanignless.
+ std::fs::copy("rust-toolchain", "clones/abi-cafe/rust-toolchain")
+ .expect("Could not copy toolchain configs!");
+ // Get the backend path.
+ // We will use the *debug* build of the backend - it has more checks enabled.
+ let backend_path = std::path::absolute("target/debug/librustc_codegen_gcc.so").unwrap();
+ let backend_arg = format!("--add-rustc-codegen-backend=cg_gcc:{}", backend_path.display());
+ // Run ABI cafe using cargo.
+ let cmd: &[&dyn AsRef<OsStr>] = &[
+ &"cargo",
+ &"run",
+ &"--release",
+ &"--",
+ &backend_arg,
+ // Test rust-LLVM to Rust-GCC calls
+ &"--pairs",
+ &"rustc_calls_cg_gcc",
+ &"--pairs",
+ &"cg_gcc_calls_rustc",
+ // Test Rust-GCC to C calls
+ &"--pairs",
+ &"cg_gcc_calls_c",
+ &"--pairs",
+ &"c_calls_cg_gcc",
+ ];
+ // Run ABI cafe.
+ run_command_with_output(cmd, Some(Path::new("clones/abi-cafe")))?;
+
+ Ok(())
+}
diff --git a/compiler/rustc_codegen_gcc/build_system/src/main.rs b/compiler/rustc_codegen_gcc/build_system/src/main.rs
index 078a472..ae975c9 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/main.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/main.rs
@@ -1,5 +1,6 @@
use std::{env, process};
+mod abi_test;
mod build;
mod clean;
mod clone_gcc;
@@ -12,7 +13,6 @@
mod rustc_info;
mod test;
mod utils;
-
const BUILD_DIR: &str = "build";
macro_rules! arg_error {
@@ -44,7 +44,8 @@ fn usage() {
info : Displays information about the build environment and project configuration.
clone-gcc : Clones the GCC compiler from a specified source.
fmt : Runs rustfmt
- fuzz : Fuzzes `cg_gcc` using rustlantis"
+ fuzz : Fuzzes `cg_gcc` using rustlantis
+ abi-test : Runs the abi-cafe test suite on the codegen, checking for ABI compatibility with LLVM"
);
}
@@ -59,6 +60,7 @@ pub enum Command {
Info,
Fmt,
Fuzz,
+ AbiTest,
}
fn main() {
@@ -77,6 +79,7 @@ fn main() {
Some("test") => Command::Test,
Some("info") => Command::Info,
Some("clone-gcc") => Command::CloneGcc,
+ Some("abi-test") => Command::AbiTest,
Some("fmt") => Command::Fmt,
Some("fuzz") => Command::Fuzz,
Some("--help") => {
@@ -102,6 +105,7 @@ fn main() {
Command::CloneGcc => clone_gcc::run(),
Command::Fmt => fmt::run(),
Command::Fuzz => fuzz::run(),
+ Command::AbiTest => abi_test::run(),
} {
eprintln!("Command failed to run: {e}");
process::exit(1);
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index bcaab0f..f1f31f8 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -738,14 +738,7 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
let path = get_sysroot_dir().join("sysroot_src/library/coretests");
let _ = remove_dir_all(path.join("target"));
// TODO(antoyo): run in release mode when we fix the failures.
- // TODO(antoyo): remove the --skip f16::test_total_cmp when this issue is fixed:
- // https://github.com/rust-lang/rust/issues/141503
- run_cargo_command(
- &[&"test", &"--", &"--skip", &"f16::test_total_cmp"],
- Some(&path),
- env,
- args,
- )?;
+ run_cargo_command(&[&"test"], Some(&path), env, args)?;
Ok(())
}
diff --git a/compiler/rustc_codegen_gcc/patches/0001-Pin-compiler_builtins-to-0.1.160.patch b/compiler/rustc_codegen_gcc/patches/0001-Pin-compiler_builtins-to-0.1.160.patch
deleted file mode 100644
index 39266e0..0000000
--- a/compiler/rustc_codegen_gcc/patches/0001-Pin-compiler_builtins-to-0.1.160.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From cdb3d407740e4f15c3746051f8ba89b8e74e99d3 Mon Sep 17 00:00:00 2001
-From: None <none@example.com>
-Date: Fri, 30 May 2025 13:46:22 -0400
-Subject: [PATCH] Pin compiler_builtins to 0.1.160
-
----
- library/alloc/Cargo.toml | 2 +-
- library/std/Cargo.toml | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
-index 9d0d957..365c9dc 100644
---- a/library/alloc/Cargo.toml
-+++ b/library/alloc/Cargo.toml
-@@ -16,7 +16,7 @@ bench = false
-
- [dependencies]
- core = { path = "../core", public = true }
--compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "=0.1.160", features = ['rustc-dep-of-std'] }
-
- [features]
- compiler-builtins-mem = ['compiler_builtins/mem']
-diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
-index 4ff4895..31371f0 100644
---- a/library/std/Cargo.toml
-+++ b/library/std/Cargo.toml
-@@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
- panic_unwind = { path = "../panic_unwind", optional = true }
- panic_abort = { path = "../panic_abort" }
- core = { path = "../core", public = true }
--compiler_builtins = { version = "=0.1.159" }
-+compiler_builtins = { version = "=0.1.160" }
- unwind = { path = "../unwind" }
- hashbrown = { version = "0.15", default-features = false, features = [
- 'rustc-dep-of-std',
---
-2.49.0
-
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
index bafe497..8be204c 100644
--- a/compiler/rustc_codegen_gcc/rust-toolchain
+++ b/compiler/rustc_codegen_gcc/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2025-05-21"
+channel = "nightly-2025-06-02"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 7852aeb..1fce547 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -520,8 +520,7 @@ fn llbb(&self) -> Block<'gcc> {
self.block
}
- fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> {
- let func = cx.rvalue_as_function(func);
+ fn append_block(_: &'a CodegenCx<'gcc, 'tcx>, func: Function<'gcc>, name: &str) -> Block<'gcc> {
func.new_block(name)
}
@@ -782,6 +781,7 @@ fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
return self.context.new_call(self.location, fmod, &[a, b]);
}
TypeKind::FP128 => {
+ // TODO(antoyo): use get_simple_function_f128_2args.
let f128_type = self.type_f128();
let fmodf128 = self.context.new_function(
None,
@@ -938,22 +938,36 @@ fn dynamic_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc>
fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
let block = self.llbb();
let function = block.get_function();
+ // NOTE(FractalFir): In some cases, we *should* skip the call to get_aligned.
+ // For example, calling `get_aligned` on a i8 is pointless(since it can only be 1 aligned)
+ // Calling get_aligned on a `u128`/`i128` causes the attribute to become "stacked"
+ //
+ // From GCCs perspective:
+ // __int128_t __attribute__((aligned(16))) __attribute__((aligned(16)))
+ // and:
+ // __int128_t __attribute__((aligned(16)))
+ // are 2 distinct, incompatible types.
+ //
+ // So, we skip the call to `get_aligned` in such a case. *Ideally*, we could do this for all the types,
+ // but the GCC APIs to facilitate this just aren't quite there yet.
+
+ // This checks that we only skip `get_aligned` on 128 bit ints if they have the correct alignment.
+ // Otherwise, this may be an under-aligned load, so we will still call get_aligned.
+ let mut can_skip_align = (pointee_ty == self.cx.u128_type
+ || pointee_ty == self.cx.i128_type)
+ && align == self.int128_align;
+ // We can skip the call to `get_aligned` for byte-sized types with alignment of 1.
+ can_skip_align = can_skip_align
+ || (pointee_ty == self.cx.u8_type || pointee_ty == self.cx.i8_type)
+ && align.bytes() == 1;
+ // Skip the call to `get_aligned` when possible.
+ let aligned_type =
+ if can_skip_align { pointee_ty } else { pointee_ty.get_aligned(align.bytes()) };
+
+ let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer());
// NOTE: instead of returning the dereference here, we have to assign it to a variable in
// the current basic block. Otherwise, it could be used in another basic block, causing a
// dereference after a drop, for instance.
- // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type.
- // Ideally, we shouldn't need to do this check.
- // FractalFir: the `align == self.int128_align` check ensures we *do* call `get_aligned` if
- // the alignment of a `u128`/`i128` is not the one mandated by the ABI. This ensures we handle
- // under-aligned loads correctly.
- let aligned_type = if (pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type)
- && align == self.int128_align
- {
- pointee_ty
- } else {
- pointee_ty.get_aligned(align.bytes())
- };
- let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer());
let deref = ptr.dereference(self.location).to_rvalue();
let loaded_value = function.new_local(
self.location,
@@ -1105,7 +1119,13 @@ fn nonnull_metadata(&mut self, _load: RValue<'gcc>) {
// TODO(antoyo)
}
- fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
+ fn store(&mut self, mut val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
+ if self.structs_as_pointer.borrow().contains(&val) {
+ // NOTE: hack to workaround a limitation of the rustc API: see comment on
+ // CodegenCx.structs_as_pointer
+ val = val.dereference(self.location).to_rvalue();
+ }
+
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
@@ -1551,16 +1571,13 @@ fn insert_value(
aggregate_value
}
- fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
+ fn set_personality_fn(&mut self, _personality: Function<'gcc>) {
#[cfg(feature = "master")]
- {
- let personality = self.rvalue_as_function(_personality);
- self.current_func().set_personality_function(personality);
- }
+ self.current_func().set_personality_function(_personality);
}
#[cfg(feature = "master")]
- fn cleanup_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
+ fn cleanup_landing_pad(&mut self, pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
self.set_personality_fn(pers_fn);
// NOTE: insert the current block in a variable so that a later call to invoke knows to
@@ -1581,7 +1598,7 @@ fn cleanup_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValu
}
#[cfg(not(feature = "master"))]
- fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
+ fn cleanup_landing_pad(&mut self, _pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
let value1 = self
.current_func()
.new_local(self.location, self.u8_type.make_pointer(), "landing_pad0")
@@ -1591,7 +1608,7 @@ fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RVal
(value1, value2)
}
- fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) {
+ fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) {
// TODO(antoyo): generate the correct landing pad
self.cleanup_landing_pad(pers_fn);
}
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 58ff2f1..fdd4782 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -234,19 +234,6 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) ->
match cv {
Scalar::Int(int) => {
let data = int.to_bits(layout.size(self));
-
- // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
- // the paths for floating-point values.
- // TODO: Remove this code?
- /*if ty == self.float_type {
- return self
- .context
- .new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
- }
- if ty == self.double_type {
- return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64));
- }*/
-
let value = self.const_uint_big(self.type_ix(bitsize), data);
let bytesize = layout.size(self).bytes();
if bitsize > 1 && ty.is_integral() && bytesize as u32 == ty.get_size() {
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index ff141ad..1d02981 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -118,14 +118,15 @@ pub struct CodegenCx<'gcc, 'tcx> {
/// A counter that is used for generating local symbol names
local_gen_sym_counter: Cell<usize>,
- eh_personality: Cell<Option<RValue<'gcc>>>,
+ eh_personality: Cell<Option<Function<'gcc>>>,
#[cfg(feature = "master")]
pub rust_try_fn: Cell<Option<(Type<'gcc>, Function<'gcc>)>>,
pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
/// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such,
- /// `const_undef()` returns struct as pointer so that they can later be assigned a value.
+ /// `const_undef()` returns struct as pointer so that they can later be assigned a value (in
+ /// e.g. Builder::insert_value).
/// As such, this set remembers which of these pointers were returned by this function so that
/// they can be dereferenced later.
/// FIXME(antoyo): fix the rustc API to avoid having this hack.
@@ -155,6 +156,13 @@ pub fn new(
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type))
.unwrap();
let align = layout.align.abi.bytes();
+ // For types with size 1, the alignment can be 1 and only 1
+ // So, we can skip the call to ``get_aligned`.
+ // In the future, we can add a GCC API to query the type align,
+ // and call `get_aligned` if and only if that differs from Rust's expectations.
+ if layout.size.bytes() == 1 {
+ return context.new_c_type(ctype);
+ }
#[cfg(feature = "master")]
{
context.new_c_type(ctype).get_aligned(align)
@@ -373,8 +381,7 @@ pub fn bitcast_if_needed(
impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
type Value = RValue<'gcc>;
type Metadata = RValue<'gcc>;
- // TODO(antoyo): change to Function<'gcc>.
- type Function = RValue<'gcc>;
+ type Function = Function<'gcc>;
type BasicBlock = Block<'gcc>;
type Type = Type<'gcc>;
@@ -392,11 +399,10 @@ fn vtables(
&self.vtables
}
- fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
+ fn get_fn(&self, instance: Instance<'tcx>) -> Function<'gcc> {
let func = get_fn(self, instance);
*self.current_func.borrow_mut() = Some(func);
- // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
- unsafe { std::mem::transmute(func) }
+ func
}
fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
@@ -420,7 +426,7 @@ fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
ptr
}
- fn eh_personality(&self) -> RValue<'gcc> {
+ fn eh_personality(&self) -> Function<'gcc> {
// The exception handling personality function.
//
// If our compilation unit has the `eh_personality` lang item somewhere
@@ -458,9 +464,7 @@ fn eh_personality(&self) -> RValue<'gcc> {
let symbol_name = tcx.symbol_name(instance).name;
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
self.linkage.set(FunctionType::Extern);
- let func = self.declare_fn(symbol_name, fn_abi);
- let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
- func
+ self.declare_fn(symbol_name, fn_abi)
}
_ => {
let name = if wants_msvc_seh(self.sess()) {
@@ -468,8 +472,7 @@ fn eh_personality(&self) -> RValue<'gcc> {
} else {
"rust_eh_personality"
};
- let func = self.declare_func(name, self.type_i32(), &[], true);
- unsafe { std::mem::transmute::<Function<'gcc>, RValue<'gcc>>(func) }
+ self.declare_func(name, self.type_i32(), &[], true)
}
};
// TODO(antoyo): apply target cpu attributes.
@@ -481,11 +484,11 @@ fn sess(&self) -> &Session {
self.tcx.sess
}
- fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
+ fn set_frame_pointer_type(&self, _llfn: Function<'gcc>) {
// TODO(antoyo)
}
- fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
+ fn apply_target_cpu_attr(&self, _llfn: Function<'gcc>) {
// TODO(antoyo)
}
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index 3a265fb..4c85851 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -1,7 +1,7 @@
use std::ops::Range;
use std::sync::Arc;
-use gccjit::{Location, RValue};
+use gccjit::{Function, Location, RValue};
use rustc_abi::Size;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods};
@@ -221,7 +221,7 @@ fn create_function_debug_context(
&self,
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
- llfn: RValue<'gcc>,
+ llfn: Function<'gcc>,
mir: &mir::Body<'tcx>,
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
if self.sess().opts.debuginfo == DebugInfo::None {
@@ -272,7 +272,7 @@ fn dbg_scope_fn(
&self,
_instance: Instance<'tcx>,
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
- _maybe_definition_llfn: Option<RValue<'gcc>>,
+ _maybe_definition_llfn: Option<Function<'gcc>>,
) -> Self::DIScope {
// TODO(antoyo): implement.
}
diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs
index bed8207..691fd87 100644
--- a/compiler/rustc_codegen_gcc/src/declare.rs
+++ b/compiler/rustc_codegen_gcc/src/declare.rs
@@ -94,7 +94,7 @@ pub fn declare_entry_fn(
_fn_type: Type<'gcc>,
#[cfg(feature = "master")] callconv: Option<FnAttribute<'gcc>>,
#[cfg(not(feature = "master"))] callconv: Option<()>,
- ) -> RValue<'gcc> {
+ ) -> Function<'gcc> {
// TODO(antoyo): use the fn_type parameter.
let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
let return_type = self.type_i32();
@@ -111,8 +111,7 @@ pub fn declare_entry_fn(
// NOTE: it is needed to set the current_func here as well, because get_fn() is not called
// for the main function.
*self.current_func.borrow_mut() = Some(func);
- // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
- unsafe { std::mem::transmute(func) }
+ func
}
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 09132c3..4c10380 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -4,7 +4,9 @@
#[cfg(feature = "master")]
use std::iter;
-use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp};
+#[cfg(feature = "master")]
+use gccjit::Type;
+use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp};
#[cfg(feature = "master")]
use rustc_abi::ExternAbi;
use rustc_abi::{BackendRepr, HasDataLayout};
@@ -300,6 +302,8 @@ fn codegen_intrinsic_call(
let fn_args = instance.args;
let simple = get_simple_intrinsic(self, name);
+ // TODO(antoyo): Only call get_simple_function_f128 and get_simple_function_f128_2args when
+ // it is the symbols for the supported f128 builtins.
let simple_func = get_simple_function(self, name)
.or_else(|| get_simple_function_f128(self, name))
.or_else(|| get_simple_function_f128_2args(self, name));
@@ -441,7 +445,7 @@ fn codegen_intrinsic_call(
match int_type_width_signed(args[0].layout.ty, self) {
Some((width, signed)) => match name {
sym::ctlz | sym::cttz => {
- let func = self.current_func.borrow().expect("func");
+ let func = self.current_func();
let then_block = func.new_block("then");
let else_block = func.new_block("else");
let after_block = func.new_block("after");
@@ -1109,7 +1113,7 @@ fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> {
// for (int counter = 0; value != 0; counter++) {
// value &= value - 1;
// }
- let func = self.current_func.borrow().expect("func");
+ let func = self.current_func();
let loop_head = func.new_block("head");
let loop_body = func.new_block("body");
let loop_tail = func.new_block("tail");
@@ -1188,7 +1192,7 @@ fn saturating_add(
let result_type = lhs.get_type();
if signed {
// Based on algorithm from: https://stackoverflow.com/a/56531252/389119
- let func = self.current_func.borrow().expect("func");
+ let func = self.current_func();
let res = func.new_local(self.location, result_type, "saturating_sum");
let supports_native_type = self.is_native_int_type(result_type);
let overflow = if supports_native_type {
@@ -1259,7 +1263,7 @@ fn saturating_sub(
let result_type = lhs.get_type();
if signed {
// Based on algorithm from: https://stackoverflow.com/a/56531252/389119
- let func = self.current_func.borrow().expect("func");
+ let func = self.current_func();
let res = func.new_local(self.location, result_type, "saturating_diff");
let supports_native_type = self.is_native_int_type(result_type);
let overflow = if supports_native_type {
@@ -1483,10 +1487,9 @@ fn gen_fn<'a, 'gcc, 'tcx>(
// FIXME(eddyb) find a nicer way to do this.
cx.linkage.set(FunctionType::Internal);
let func = cx.declare_fn(name, fn_abi);
- let func_val = unsafe { std::mem::transmute::<Function<'gcc>, RValue<'gcc>>(func) };
- cx.set_frame_pointer_type(func_val);
- cx.apply_target_cpu_attr(func_val);
- let block = Builder::append_block(cx, func_val, "entry-block");
+ cx.set_frame_pointer_type(func);
+ cx.apply_target_cpu_attr(func);
+ let block = Builder::append_block(cx, func, "entry-block");
let bx = Builder::build(cx, block);
codegen(bx);
(return_type, func)
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 6f6bc93..2e50881 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -61,7 +61,7 @@ macro_rules! require_simd {
let (len, _) = args[1].layout.ty.simd_size_and_type(bx.tcx());
let expected_int_bits = (len.max(8) - 1).next_power_of_two();
- let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
+ let expected_bytes = len / 8 + ((!len.is_multiple_of(8)) as u64);
let mask_ty = args[0].layout.ty;
let mut mask = match *mask_ty.kind() {
@@ -676,7 +676,8 @@ macro_rules! arith_binary {
let elem_type = vector_type.get_element_type();
let expected_int_bits = in_len.max(8);
- let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
+ let expected_bytes =
+ expected_int_bits / 8 + ((!expected_int_bits.is_multiple_of(8)) as u64);
// FIXME(antoyo): that's not going to work for masks bigger than 128 bits.
let result_type = bx.type_ix(expected_int_bits);
@@ -779,6 +780,7 @@ macro_rules! return_error {
sym::simd_fsin => "sin",
sym::simd_fsqrt => "sqrt",
sym::simd_round => "round",
+ sym::simd_round_ties_even => "rint",
sym::simd_trunc => "trunc",
_ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
};
@@ -826,6 +828,7 @@ macro_rules! return_error {
| sym::simd_fsin
| sym::simd_fsqrt
| sym::simd_round
+ | sym::simd_round_ties_even
| sym::simd_trunc
) {
return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
index d931f0d..544d0bf 100644
--- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
+++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
@@ -9,6 +9,7 @@
tests/ui/iterators/iter-sum-overflow-overflow-checks.rs
tests/ui/mir/mir_drop_order.rs
tests/ui/mir/mir_let_chains_drop_order.rs
+tests/ui/mir/mir_match_guard_let_chains_drop_order.rs
tests/ui/oom_unwind.rs
tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
tests/ui/panic-runtime/abort.rs
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index f7f0628..9930eae 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1537,6 +1537,7 @@ macro_rules! return_error {
sym::simd_fsin => "llvm.sin",
sym::simd_fsqrt => "llvm.sqrt",
sym::simd_round => "llvm.round",
+ sym::simd_round_ties_even => "llvm.rint",
sym::simd_trunc => "llvm.trunc",
_ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
};
@@ -1563,6 +1564,7 @@ macro_rules! return_error {
| sym::simd_fsqrt
| sym::simd_relaxed_fma
| sym::simd_round
+ | sym::simd_round_ties_even
| sym::simd_trunc
) {
return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
@@ -2309,7 +2311,13 @@ macro_rules! arith_unary {
// Unary integer intrinsics
if matches!(
name,
- sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop | sym::simd_cttz
+ sym::simd_bswap
+ | sym::simd_bitreverse
+ | sym::simd_ctlz
+ | sym::simd_ctpop
+ | sym::simd_cttz
+ | sym::simd_funnel_shl
+ | sym::simd_funnel_shr
) {
let vec_ty = bx.cx.type_vector(
match *in_elem.kind() {
@@ -2330,6 +2338,8 @@ macro_rules! arith_unary {
sym::simd_ctlz => "llvm.ctlz",
sym::simd_ctpop => "llvm.ctpop",
sym::simd_cttz => "llvm.cttz",
+ sym::simd_funnel_shl => "llvm.fshl",
+ sym::simd_funnel_shr => "llvm.fshr",
_ => unreachable!(),
};
let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
@@ -2350,6 +2360,11 @@ macro_rules! arith_unary {
// simple unary argument cases
Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()]))
}
+ sym::simd_funnel_shl | sym::simd_funnel_shr => Ok(bx.call_intrinsic(
+ llvm_intrinsic,
+ &[vec_ty],
+ &[args[0].immediate(), args[1].immediate(), args[2].immediate()],
+ )),
_ => unreachable!(),
};
}
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 6362d2e..84d6381 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -48,8 +48,6 @@
codegen_ssa_expected_name_value_pair = expected name value pair
-codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
-
codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index cd08c0f..ede1149 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1870,8 +1870,28 @@ pub(crate) fn linked_symbols(
crate_type: CrateType,
) -> Vec<(String, SymbolExportKind)> {
match crate_type {
- CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (),
- CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
+ CrateType::Executable
+ | CrateType::ProcMacro
+ | CrateType::Cdylib
+ | CrateType::Dylib
+ | CrateType::Sdylib => (),
+ CrateType::Staticlib | CrateType::Rlib => {
+ // These are not linked, so no need to generate symbols.o for them.
+ return Vec::new();
+ }
+ }
+
+ match tcx.sess.lto() {
+ Lto::No | Lto::ThinLocal => {}
+ Lto::Thin | Lto::Fat => {
+ // We really only need symbols from upstream rlibs to end up in the linked symbols list.
+ // The rest are in separate object files which the linker will always link in and
+ // doesn't have rules around the order in which they need to appear.
+ // When doing LTO, some of the symbols in the linked symbols list happen to be
+ // internalized by LTO, which then prevents referencing them from symbols.o. When doing
+ // LTO, all object files that get linked in will be local object files rather than
+ // pulled in from rlibs, so an empty linked symbols list works fine to avoid referencing
+ // all those internalized symbols from symbols.o.
return Vec::new();
}
}
@@ -1882,6 +1902,7 @@ pub(crate) fn linked_symbols(
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum)
|| info.used
+ || info.rustc_std_internal_symbol
{
symbols.push((
symbol_export::linking_symbol_name_for_instance_in_crate(
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 19c005d..75f7a46 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -131,6 +131,9 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|| used,
+ rustc_std_internal_symbol: codegen_attrs
+ .flags
+ .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL),
};
(def_id.to_def_id(), info)
})
@@ -143,6 +146,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
level: SymbolExportLevel::C,
kind: SymbolExportKind::Data,
used: false,
+ rustc_std_internal_symbol: false,
},
);
}
@@ -191,6 +195,7 @@ fn exported_symbols_provider_local<'tcx>(
level: info.level,
kind: SymbolExportKind::Text,
used: info.used,
+ rustc_std_internal_symbol: info.rustc_std_internal_symbol,
},
)
})
@@ -207,6 +212,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::C,
kind: SymbolExportKind::Text,
used: false,
+ rustc_std_internal_symbol: false,
},
));
}
@@ -230,6 +236,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
+ rustc_std_internal_symbol: true,
},
));
}
@@ -250,6 +257,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::C,
kind: SymbolExportKind::Data,
used: false,
+ rustc_std_internal_symbol: false,
},
)
}));
@@ -275,6 +283,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::C,
kind: SymbolExportKind::Data,
used: false,
+ rustc_std_internal_symbol: false,
},
)
}));
@@ -292,6 +301,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::C,
kind: SymbolExportKind::Data,
used: true,
+ rustc_std_internal_symbol: false,
},
));
}
@@ -367,6 +377,8 @@ fn exported_symbols_provider_local<'tcx>(
}
}
+ // Note: These all set rustc_std_internal_symbol to false as generic functions must not
+ // be marked with this attribute and we are only handling generic functions here.
match *mono_item {
MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => {
let has_generics = args.non_erasable_generics().next().is_some();
@@ -382,6 +394,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
+ rustc_std_internal_symbol: false,
},
));
}
@@ -404,6 +417,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
+ rustc_std_internal_symbol: false,
},
));
}
@@ -420,6 +434,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
+ rustc_std_internal_symbol: false,
},
));
}
@@ -430,6 +445,7 @@ fn exported_symbols_provider_local<'tcx>(
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
+ rustc_std_internal_symbol: false,
},
));
}
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index cc90271..b06cfd1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -6,7 +6,7 @@
use itertools::Itertools;
use rustc_abi::FIRST_VARIANT;
use rustc_ast as ast;
-use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name};
+use rustc_ast::expand::allocator::AllocatorKind;
use rustc_attr_data_structures::OptimizeAttr;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
@@ -1056,26 +1056,6 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
.collect::<Vec<_>>();
symbols.sort_unstable_by(|a, b| a.0.cmp(&b.0));
linked_symbols.extend(symbols);
- if tcx.allocator_kind(()).is_some() {
- // At least one crate needs a global allocator. This crate may be placed
- // after the crate that defines it in the linker order, in which case some
- // linkers return an error. By adding the global allocator shim methods to
- // the linked_symbols list, linking the generated symbols.o will ensure that
- // circular dependencies involving the global allocator don't lead to linker
- // errors.
- linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
- (
- add_prefix(
- mangle_internal_symbol(
- tcx,
- global_fn_name(method.name).as_str(),
- ),
- SymbolExportKind::Text,
- ),
- SymbolExportKind::Text,
- )
- }));
- }
});
}
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 94df5e8..7680f8e 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -4,7 +4,7 @@
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
use rustc_attr_data_structures::{
- AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, find_attr,
+ AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, UsedBy, find_attr,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -123,6 +123,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
+ AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
AttributeKind::NoMangle(attr_span) => {
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
@@ -160,6 +161,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
}
+ AttributeKind::Used { used_by, .. } => match used_by {
+ UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
+ UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
+ },
_ => {}
}
}
@@ -181,44 +186,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
sym::rustc_std_internal_symbol => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
}
- sym::used => {
- let inner = attr.meta_item_list();
- match inner.as_deref() {
- Some([item]) if item.has_name(sym::linker) => {
- if !tcx.features().used_with_arg() {
- feature_err(
- &tcx.sess,
- sym::used_with_arg,
- attr.span(),
- "`#[used(linker)]` is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
- }
- Some([item]) if item.has_name(sym::compiler) => {
- if !tcx.features().used_with_arg() {
- feature_err(
- &tcx.sess,
- sym::used_with_arg,
- attr.span(),
- "`#[used(compiler)]` is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER;
- }
- Some(_) => {
- tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() });
- }
- None => {
- // Unconditionally using `llvm.used` causes issues in handling
- // `.init_array` with the gold linker. Luckily gold has been
- // deprecated with GCC 15 and rustc now warns about using gold.
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER
- }
- }
- }
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::target_feature => {
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
@@ -296,7 +263,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
}
- sym::link_name => codegen_fn_attrs.link_name = attr.value_str(),
sym::link_ordinal => {
link_ordinal_span = Some(attr.span());
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
@@ -430,7 +396,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
- // Apply the minimum function alignment here, so that individual backends don't have to.
+ // Apply the minimum function alignment here. This ensures that a function's alignment is
+ // determined by the `-C` flags of the crate it is defined in, not the `-C` flags of the crate
+ // it happens to be codegen'd (or const-eval'd) in.
codegen_fn_attrs.alignment =
Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment);
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index db536af..1950a35 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -727,13 +727,6 @@ pub struct UnknownArchiveKind<'a> {
}
#[derive(Diagnostic)]
-#[diag(codegen_ssa_expected_used_symbol)]
-pub(crate) struct ExpectedUsedSymbol {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
#[diag(codegen_ssa_multiple_main_functions)]
#[help]
pub(crate) struct MultipleMainFunctions {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 3df9742..1d5fbfc 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -776,6 +776,12 @@ fn codegen_assert_terminator(
// `#[track_caller]` adds an implicit argument.
(LangItem::PanicNullPointerDereference, vec![location])
}
+ AssertKind::InvalidEnumConstruction(source) => {
+ let source = self.codegen_operand(bx, source).immediate();
+ // It's `fn panic_invalid_enum_construction(source: u128)`,
+ // `#[track_caller]` adds an implicit argument.
+ (LangItem::PanicInvalidEnumConstruction, vec![source, location])
+ }
_ => {
// It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument.
(msg.panic_function(), vec![location])
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 99957c6..da615cc 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -479,17 +479,8 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
_ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
};
- // Layout ensures that we only get here for cases where the discriminant
+ // `layout_sanity_check` ensures that we only get here for cases where the discriminant
// value and the variant index match, since that's all `Niche` can encode.
- // But for emphasis and debugging, let's double-check one anyway.
- debug_assert_eq!(
- self.layout
- .ty
- .discriminant_for_variant(bx.tcx(), untagged_variant)
- .unwrap()
- .val,
- u128::from(untagged_variant.as_u32()),
- );
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 97b154a..2a2c3e6 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -125,16 +125,11 @@
calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
const_eval_interior_mutable_borrow_escaping =
- interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed
- .label = this borrow of an interior mutable value refers to a lifetime-extended temporary
- .help = to fix this, the value can be extracted to a separate `static` item and then referenced
- .teach_note =
- This creates a raw pointer to a temporary that has its lifetime extended to last for the entire program.
- Lifetime-extended temporaries in constants and statics must be immutable.
- This is to avoid accidentally creating shared mutable state.
-
-
- If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
+ interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
+ .label = this borrow of an interior mutable value refers to such a temporary
+ .note = Temporaries in constants and statics can have their lifetime extended until the end of the program
+ .note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable
+ .help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
const_eval_intern_kind = {$kind ->
[static] static
@@ -215,14 +210,11 @@
modifying a static's initial value from another static's initializer
const_eval_mutable_borrow_escaping =
- mutable borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed
- .teach_note =
- This creates a reference to a temporary that has its lifetime extended to last for the entire program.
- Lifetime-extended temporaries in constants and statics must be immutable.
- This is to avoid accidentally creating shared mutable state.
-
-
- If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
+ mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
+ .label = this mutable borrow refers to such a temporary
+ .note = Temporaries in constants and statics can have their lifetime extended until the end of the program
+ .note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable
+ .help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
@@ -352,7 +344,7 @@
*[other] {""}
} {$ptr} which does not point to the beginning of an object
-const_eval_recursive_static = encountered static that tried to initialize itself with itself
+const_eval_recursive_static = encountered static that tried to access itself during initialization
const_eval_remainder_by_zero =
calculating the remainder with a divisor of zero
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index c151e8a..c1d91f9 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -421,7 +421,7 @@ fn revalidate_conditional_constness(
Some(ConstConditionsHold::Yes)
} else {
tcx.dcx()
- .span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
+ .span_delayed_bug(call_span, "this should have reported a [const] error in HIR");
Some(ConstConditionsHold::No)
}
}
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 02edff8..b2e0577 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -149,7 +149,7 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
debug!(?param_ty);
if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() {
let constraint = with_no_trimmed_paths!(format!(
- "~const {}",
+ "[const] {}",
trait_ref.print_trait_sugared(),
));
suggest_constraining_type_param(
@@ -567,12 +567,7 @@ fn importance(&self) -> DiagImportance {
DiagImportance::Secondary
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
- ccx.dcx().create_err(errors::InteriorMutableBorrowEscaping {
- span,
- opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)),
- kind: ccx.const_kind(),
- teach: ccx.tcx.sess.teach(E0492),
- })
+ ccx.dcx().create_err(errors::InteriorMutableBorrowEscaping { span, kind: ccx.const_kind() })
}
}
@@ -594,11 +589,7 @@ fn importance(&self) -> DiagImportance {
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
- ccx.dcx().create_err(errors::MutableBorrowEscaping {
- span,
- kind: ccx.const_kind(),
- teach: ccx.tcx.sess.teach(E0764),
- })
+ ccx.dcx().create_err(errors::MutableBorrowEscaping { span, kind: ccx.const_kind() })
}
}
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index c1a37ab..166491b 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -170,14 +170,14 @@ fn in_qualifs(qualifs: &ConstQualifs) -> bool {
#[instrument(level = "trace", skip(cx), ret)]
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
- // If this doesn't need drop at all, then don't select `~const Destruct`.
+ // If this doesn't need drop at all, then don't select `[const] Destruct`.
if !ty.needs_drop(cx.tcx, cx.typing_env) {
return false;
}
- // We check that the type is `~const Destruct` since that will verify that
- // the type is both `~const Drop` (if a drop impl exists for the adt), *and*
- // that the components of this type are also `~const Destruct`. This
+ // We check that the type is `[const] Destruct` since that will verify that
+ // the type is both `[const] Drop` (if a drop impl exists for the adt), *and*
+ // that the components of this type are also `[const] Destruct`. This
// amounts to verifying that there are no values in this ADT that may have
// a non-const drop.
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, cx.body.span);
@@ -203,9 +203,9 @@ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
// As soon as an ADT has a destructor, then the drop becomes non-structural
// in its value since:
- // 1. The destructor may have `~const` bounds which are not present on the type.
+ // 1. The destructor may have `[const]` bounds which are not present on the type.
// Someone needs to check that those are satisfied.
- // While this could be instead satisfied by checking that the `~const Drop`
+ // While this could be instead satisfied by checking that the `[const] Drop`
// impl holds (i.e. replicating part of the `in_any_value_of_ty` logic above),
// even in this case, we have another problem, which is,
// 2. The destructor may *modify* the operand being dropped, so even if we
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index be84019..569a07c 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -7,7 +7,7 @@
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
+use rustc_middle::ty::layout::HasTypingEnv;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, throw_inval};
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index a68dcf2..317b122 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -62,7 +62,7 @@ pub struct CompileTimeMachine<'tcx> {
/// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`,
/// storing the result in the given `AllocId`.
- /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops.
+ /// Used to prevent accesses to a static's base allocation, as that may allow for self-initialization loops.
pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>,
/// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes).
@@ -508,6 +508,7 @@ fn assert_panic(
found: eval_to_int(found)?,
},
NullPointerDereference => NullPointerDereference,
+ InvalidEnumConstruction(source) => InvalidEnumConstruction(eval_to_int(source)?),
};
Err(ConstEvalErrKind::AssertFailure(err)).into()
}
@@ -705,19 +706,27 @@ fn before_memory_write(
interp_ok(())
}
- fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> {
+ fn before_alloc_access(
+ tcx: TyCtxtAt<'tcx>,
+ machine: &Self,
+ alloc_id: AllocId,
+ ) -> InterpResult<'tcx> {
+ if machine.stack.is_empty() {
+ // Get out of the way for the final copy.
+ return interp_ok(());
+ }
// Check if this is the currently evaluated static.
- if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
+ if Some(alloc_id) == machine.static_root_ids.map(|(id, _)| id) {
return Err(ConstEvalErrKind::RecursiveStatic).into();
}
// If this is another static, make sure we fire off the query to detect cycles.
// But only do that when checks for static recursion are enabled.
- if ecx.machine.static_root_ids.is_some() {
- if let Some(GlobalAlloc::Static(def_id)) = ecx.tcx.try_get_global_alloc(alloc_id) {
- if ecx.tcx.is_foreign_item(def_id) {
+ if machine.static_root_ids.is_some() {
+ if let Some(GlobalAlloc::Static(def_id)) = tcx.try_get_global_alloc(alloc_id) {
+ if tcx.is_foreign_item(def_id) {
throw_unsup!(ExternStatic(def_id));
}
- ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
+ tcx.eval_static_initializer(def_id)?;
}
}
interp_ok(())
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 73cb1e7..d95d552 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -2,7 +2,6 @@
use rustc_abi::{FieldIdx, VariantIdx};
use rustc_middle::query::Key;
-use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use tracing::instrument;
@@ -67,18 +66,13 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
#[instrument(skip(tcx), level = "debug")]
pub fn tag_for_variant_provider<'tcx>(
tcx: TyCtxt<'tcx>,
- (ty, variant_index): (Ty<'tcx>, VariantIdx),
+ key: ty::PseudoCanonicalInput<'tcx, (Ty<'tcx>, VariantIdx)>,
) -> Option<ty::ScalarInt> {
+ let (ty, variant_index) = key.value;
assert!(ty.is_enum());
- // FIXME: This uses an empty `TypingEnv` even though
- // it may be used by a generic CTFE.
- let ecx = InterpCx::new(
- tcx,
- ty.default_span(tcx),
- ty::TypingEnv::fully_monomorphized(),
- crate::const_eval::DummyMachine,
- );
+ let ecx =
+ InterpCx::new(tcx, ty.default_span(tcx), key.typing_env, crate::const_eval::DummyMachine);
let layout = ecx.layout_of(ty).unwrap();
ecx.tag_for_variant(layout, variant_index).unwrap().map(|(tag, _tag_field)| tag)
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index b3d2e1a..5ab72c8 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,7 +1,7 @@
use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
-use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_span::DUMMY_SP;
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index b2c3103..14abdd8 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -151,12 +151,14 @@ pub(crate) struct UnmarkedIntrinsicExposed {
#[derive(Diagnostic)]
#[diag(const_eval_mutable_borrow_escaping, code = E0764)]
+#[note]
+#[note(const_eval_note2)]
+#[help]
pub(crate) struct MutableBorrowEscaping {
#[primary_span]
+ #[label]
pub span: Span,
pub kind: ConstContext,
- #[note(const_eval_teach_note)]
- pub teach: bool,
}
#[derive(Diagnostic)]
@@ -217,15 +219,14 @@ pub(crate) struct UnallowedInlineAsm {
#[derive(Diagnostic)]
#[diag(const_eval_interior_mutable_borrow_escaping, code = E0492)]
+#[note]
+#[note(const_eval_note2)]
+#[help]
pub(crate) struct InteriorMutableBorrowEscaping {
#[primary_span]
#[label]
pub span: Span,
- #[help]
- pub opt_help: bool,
pub kind: ConstContext,
- #[note(const_eval_teach_note)]
- pub teach: bool,
}
#[derive(LintDiagnostic)]
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 37677f9..79c14b2 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -6,7 +6,7 @@
use either::{Left, Right};
use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::sym;
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 9e15f45..1036935 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -6,7 +6,7 @@
use rustc_middle::mir::CastKind;
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::{self, FloatTy, Ty};
use rustc_middle::{bug, span_bug};
use tracing::trace;
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 6c4b000..b7e7f65 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -1,7 +1,7 @@
//! Functions for reading and writing discriminants of multi-variant layouts (enums and coroutines).
use rustc_abi::{self as abi, FieldIdx, TagEncoding, VariantIdx, Variants};
-use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_middle::ty::{self, CoroutineArgsExt, ScalarInt, Ty};
use rustc_middle::{mir, span_bug};
use tracing::{instrument, trace};
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index b69bc09..46c784b 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -7,7 +7,8 @@
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
- self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
+ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
+ TyAndLayout,
};
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
use rustc_middle::{mir, span_bug};
@@ -21,7 +22,7 @@
MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance,
err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom,
};
-use crate::{ReportErrorExt, fluent_generated as fluent, util};
+use crate::{ReportErrorExt, enter_trace_span, fluent_generated as fluent, util};
pub struct InterpCx<'tcx, M: Machine<'tcx>> {
/// Stores the `Machine` instance.
@@ -91,6 +92,20 @@ fn handle_layout_err(
}
}
+impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
+ /// This inherent method takes priority over the trait method with the same name in LayoutOf,
+ /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span.
+ /// See [LayoutOf::layout_of] for the original documentation.
+ #[inline]
+ pub fn layout_of(
+ &self,
+ ty: Ty<'tcx>,
+ ) -> <InterpCx<'tcx, M> as LayoutOfHelpers<'tcx>>::LayoutOfResult {
+ let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind());
+ LayoutOf::layout_of(self, ty)
+ }
+}
+
impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>;
@@ -284,6 +299,12 @@ pub fn instantiate_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCt
frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
value: T,
) -> Result<T, ErrorHandled> {
+ let _span = enter_trace_span!(
+ M,
+ "instantiate_from_frame_and_normalize_erasing_regions",
+ "{}",
+ frame.instance
+ );
frame
.instance
.try_instantiate_mir_and_normalize_erasing_regions(
@@ -362,7 +383,7 @@ pub(crate) fn find_closest_untracked_caller_location(&self) -> Span {
/// Returns the actual dynamic size and alignment of the place at the given type.
/// Only the "meta" (metadata) part of the place matters.
/// This can fail to provide an answer for extern types.
- pub(super) fn size_and_align_of(
+ pub(super) fn size_and_align_from_meta(
&self,
metadata: &MemPlaceMeta<M::Provenance>,
layout: &TyAndLayout<'tcx>,
@@ -388,7 +409,7 @@ pub(super) fn size_and_align_of(
// adjust alignment and size for them?
let field = layout.field(self, layout.fields.count() - 1);
let Some((unsized_size, mut unsized_align)) =
- self.size_and_align_of(metadata, &field)?
+ self.size_and_align_from_meta(metadata, &field)?
else {
// A field with an extern type. We don't know the actual dynamic size
// or the alignment.
@@ -450,11 +471,11 @@ pub(super) fn size_and_align_of(
}
}
#[inline]
- pub fn size_and_align_of_mplace(
+ pub fn size_and_align_of_val(
&self,
- mplace: &MPlaceTy<'tcx, M::Provenance>,
+ val: &impl Projectable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, Option<(Size, Align)>> {
- self.size_and_align_of(&mplace.meta(), &mplace.layout)
+ self.size_and_align_from_meta(&val.meta(), &val.layout())
}
/// Jump to the given block.
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 96c39c7..b29c5c7 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -8,7 +8,7 @@
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
-use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement};
+use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement};
use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt};
use rustc_middle::{bug, ty};
use rustc_span::{Symbol, sym};
@@ -125,7 +125,7 @@ pub fn eval_intrinsic(
// dereferenceable!
let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
let (size, align) = self
- .size_and_align_of_mplace(&place)?
+ .size_and_align_of_val(&place)?
.ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
let result = match intrinsic_name {
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index b9e022c..d6d230f 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -443,7 +443,11 @@ fn before_memory_read(
///
/// Used to prevent statics from self-initializing by reading from their own memory
/// as it is being initialized.
- fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> {
+ fn before_alloc_access(
+ _tcx: TyCtxtAt<'tcx>,
+ _machine: &Self,
+ _alloc_id: AllocId,
+ ) -> InterpResult<'tcx> {
interp_ok(())
}
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 57bf867..69fceb0 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -720,7 +720,7 @@ pub fn get_ptr_alloc<'a>(
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
if !self.memory.validation_in_progress.get() {
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) {
- M::before_alloc_read(self, alloc_id)?;
+ M::before_alloc_access(self.tcx, &self.machine, alloc_id)?;
}
}
@@ -821,6 +821,9 @@ pub fn get_ptr_alloc_mut<'a>(
if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc {
let range = alloc_range(offset, size);
if !validation_in_progress {
+ // For writes, it's okay to only call those when there actually is a non-zero
+ // amount of bytes to be written: a zero-sized write doesn't manifest anything.
+ M::before_alloc_access(tcx, machine, alloc_id)?;
M::before_memory_write(
tcx,
machine,
@@ -1396,6 +1399,14 @@ pub fn mem_copy_repeatedly(
let src_parts = self.get_ptr_access(src, size)?;
let dest_parts = self.get_ptr_access(dest, size * num_copies)?; // `Size` multiplication
+ // Similar to `get_ptr_alloc`, we need to call `before_alloc_access` even for zero-sized
+ // reads. However, just like in `get_ptr_alloc_mut`, the write part is okay to skip for
+ // zero-sized writes.
+ if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes().try_into().unwrap())
+ {
+ M::before_alloc_access(tcx, &self.machine, alloc_id)?;
+ }
+
// FIXME: we look up both allocations twice here, once before for the `check_ptr_access`
// and once below to get the underlying `&[mut] Allocation`.
@@ -1408,12 +1419,9 @@ pub fn mem_copy_repeatedly(
let src_range = alloc_range(src_offset, size);
assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation");
- // Trigger read hooks.
- // For the overlapping case, it is crucial that we trigger the read hooks
+ // Trigger read hook.
+ // For the overlapping case, it is crucial that we trigger the read hook
// before the write hook -- the aliasing model cares about the order.
- if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes() as i64) {
- M::before_alloc_read(self, alloc_id)?;
- }
M::before_memory_read(
tcx,
&self.machine,
@@ -1438,16 +1446,18 @@ pub fn mem_copy_repeatedly(
let provenance = src_alloc
.provenance()
.prepare_copy(src_range, dest_offset, num_copies, self)
- .map_err(|e| e.to_interp_error(dest_alloc_id))?;
+ .map_err(|e| e.to_interp_error(src_alloc_id))?;
// Prepare a copy of the initialization mask.
let init = src_alloc.init_mask().prepare_copy(src_range);
- // Destination alloc preparations and access hooks.
- let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
+ // Destination alloc preparations...
+ let (dest_alloc, machine) = self.get_alloc_raw_mut(dest_alloc_id)?;
let dest_range = alloc_range(dest_offset, size * num_copies);
+ // ...and access hooks.
+ M::before_alloc_access(tcx, machine, dest_alloc_id)?;
M::before_memory_write(
tcx,
- extra,
+ machine,
&mut dest_alloc.extra,
dest,
(dest_alloc_id, dest_prov),
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 337b161..62cbbae 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -8,7 +8,7 @@
use rustc_abi::{BackendRepr, HasDataLayout, Size};
use rustc_hir::def::Namespace;
use rustc_middle::mir::interpret::ScalarSizeMismatch;
-use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, mir, span_bug, ty};
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 899670a..74f8a0a 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -3,7 +3,7 @@
use rustc_apfloat::{Float, FloatConvert};
use rustc_middle::mir::NullOp;
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
-use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::sym;
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index e4885af..3028568 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -7,7 +7,7 @@
use either::{Either, Left, Right};
use rustc_abi::{BackendRepr, HasDataLayout, Size};
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, mir, span_bug};
use tracing::{instrument, trace};
@@ -470,7 +470,7 @@ pub(super) fn get_place_alloc(
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
{
let (size, _align) = self
- .size_and_align_of_mplace(mplace)?
+ .size_and_align_of_val(mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
// We check alignment separately, and *after* checking everything else.
// If an access is both OOB and misaligned, we want to see the bounds error.
@@ -486,7 +486,7 @@ pub(super) fn get_place_alloc_mut(
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
{
let (size, _align) = self
- .size_and_align_of_mplace(mplace)?
+ .size_and_align_of_val(mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
// We check alignment separately, and raise that error *after* checking everything else.
// If an access is both OOB and misaligned, we want to see the bounds error.
@@ -888,11 +888,11 @@ fn copy_op_no_validate(
trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout().ty);
let dest = dest.force_mplace(self)?;
- let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else {
+ let Some((dest_size, _)) = self.size_and_align_of_val(&dest)? else {
span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values")
};
if cfg!(debug_assertions) {
- let src_size = self.size_and_align_of_mplace(&src)?.unwrap().0;
+ let src_size = self.size_and_align_of_val(&src)?.unwrap().0;
assert_eq!(src_size, dest_size, "Cannot copy differently-sized data");
} else {
// As a cheap approximation, we compare the fixed parts of the size.
@@ -980,7 +980,7 @@ pub fn allocate_dyn(
kind: MemoryKind<M::MemoryKind>,
meta: MemPlaceMeta<M::Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
- let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else {
+ let Some((size, align)) = self.size_and_align_from_meta(&meta, &layout)? else {
span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
};
let ptr = self.allocate_ptr(size, align, kind, AllocInit::Uninit)?;
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index ad47a19..306697d 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -12,7 +12,7 @@
use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx};
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, mir, span_bug, ty};
use tracing::{debug, instrument};
@@ -168,7 +168,7 @@ pub fn project_field<P: Projectable<'tcx, M::Provenance>>(
// Re-use parent metadata to determine dynamic field layout.
// With custom DSTS, this *will* execute user-defined code, but the same
// happens at run-time so that's okay.
- match self.size_and_align_of(&base_meta, &field_layout)? {
+ match self.size_and_align_from_meta(&base_meta, &field_layout)? {
Some((_, align)) => {
// For packed types, we need to cap alignment.
let align = if let ty::Adt(def, _) = base.layout().ty.kind()
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 2a2d1bb..3361a58 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -7,7 +7,7 @@
use rustc_hir as hir;
use rustc_hir::definitions::DefPathData;
use rustc_index::IndexVec;
-use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_mir_dataflow::impls::always_storage_live_locals;
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 7249ef2..8b63495 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -1,6 +1,5 @@
use rustc_abi::{Align, FieldIdx, Size};
use rustc_middle::mir::interpret::{InterpResult, Pointer};
-use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry};
use tracing::trace;
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 7e26b7f..998ef37 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -24,7 +24,7 @@
ExpectedKind, InterpErrorKind, InvalidMetaKind, Misalignment, PointerKind, Provenance,
UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok,
};
-use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_span::{Symbol, sym};
use tracing::trace;
@@ -35,6 +35,7 @@
Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub,
format_interp_error,
};
+use crate::enter_trace_span;
// for the validation errors
#[rustfmt::skip]
@@ -493,7 +494,7 @@ fn check_safe_pointer(
}
// Make sure this is dereferenceable and all.
let size_and_align = try_validation!(
- self.ecx.size_and_align_of_mplace(&place),
+ self.ecx.size_and_align_of_val(&place),
self.path,
Ub(InvalidMeta(msg)) => match msg {
InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind },
@@ -905,7 +906,7 @@ fn reset_padding(&mut self, place: &PlaceTy<'tcx, M::Provenance>) -> InterpResul
let (_prov, start_offset) = mplace.ptr().into_parts();
let (size, _align) = self
.ecx
- .size_and_align_of_mplace(&mplace)?
+ .size_and_align_of_val(&mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
// If there is no padding at all, we can skip the rest: check for
// a single data range covering the entire value.
@@ -1085,8 +1086,10 @@ fn visit_union(
) -> InterpResult<'tcx> {
// Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory.
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
- if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env)
- {
+ // Unsized unions are currently not a thing, but let's keep this code consistent with
+ // the check in `visit_value`.
+ let zst = self.ecx.size_and_align_of_val(val)?.is_some_and(|(s, _a)| s.bytes() == 0);
+ if !zst && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env) {
if !self.in_mutable_memory(val) {
throw_validation_failure!(self.path, UnsafeCellInImmutable);
}
@@ -1130,7 +1133,10 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t
// Special check preventing `UnsafeCell` in the inner part of constants
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
- if !val.layout.is_zst()
+ // Exclude ZST values. We need to compute the dynamic size/align to properly
+ // handle slices and trait objects.
+ let zst = self.ecx.size_and_align_of_val(val)?.is_some_and(|(s, _a)| s.bytes() == 0);
+ if !zst
&& let Some(def) = val.layout.ty.ty_adt_def()
&& def.is_unsafe_cell()
{
@@ -1363,8 +1369,8 @@ fn validate_operand_internal(
})
}
- /// This function checks the data at `op` to be const-valid.
- /// `op` is assumed to cover valid memory if it is an indirect operand.
+ /// This function checks the data at `val` to be const-valid.
+ /// `val` is assumed to cover valid memory if it is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
///
/// `ref_tracking` is used to record references that we encounter so that they
@@ -1390,8 +1396,8 @@ pub(crate) fn const_validate_operand(
)
}
- /// This function checks the data at `op` to be runtime-valid.
- /// `op` is assumed to cover valid memory if it is an indirect operand.
+ /// This function checks the data at `val` to be runtime-valid.
+ /// `val` is assumed to cover valid memory if it is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
#[inline(always)]
pub fn validate_operand(
@@ -1400,6 +1406,12 @@ pub fn validate_operand(
recursive: bool,
reset_provenance_and_padding: bool,
) -> InterpResult<'tcx> {
+ let _span = enter_trace_span!(
+ M,
+ "validate_operand",
+ "recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}"
+ );
+
// Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
// value, it rules out things like `UnsafeCell` in awkward places.
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 5aea912..d5970b6 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -6,7 +6,6 @@
use rustc_abi::{FieldIdx, FieldsShape, VariantIdx, Variants};
use rustc_index::IndexVec;
use rustc_middle::mir::interpret::InterpResult;
-use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use tracing::trace;
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 6712140..f489b05 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -1,6 +1,5 @@
use rustc_abi::FieldIdx;
use rustc_hir::LangItem;
-use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_span::Symbol;
@@ -22,13 +21,14 @@ fn alloc_caller_location<'tcx>(
assert!(!filename.as_str().as_bytes().contains(&0));
let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail;
- let file_wide_ptr = {
+ let filename = {
let filename = if loc_details.file { filename.as_str() } else { "<redacted>" };
let filename_with_nul = filename.to_owned() + "\0";
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
// pointless, since that would require allocating more memory than these short strings.
let file_ptr = ecx.allocate_bytes_dedup(filename_with_nul.as_bytes()).unwrap();
- Immediate::new_slice(file_ptr.into(), filename_with_nul.len().try_into().unwrap(), ecx)
+ let file_len = u64::try_from(filename.len()).unwrap();
+ Immediate::new_slice(file_ptr.into(), file_len, ecx)
};
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
@@ -42,11 +42,8 @@ fn alloc_caller_location<'tcx>(
let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
// Initialize fields.
- ecx.write_immediate(
- file_wide_ptr,
- &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap(),
- )
- .expect("writing to memory we just allocated cannot fail");
+ ecx.write_immediate(filename, &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap())
+ .expect("writing to memory we just allocated cannot fail");
ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap())
.expect("writing to memory we just allocated cannot fail");
ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap())
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 4e4345c..4b3ecad 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -3,7 +3,6 @@
#![doc(rust_logo)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
-#![feature(type_alias_impl_trait)]
// tidy-alphabetical-end
use std::borrow::Cow;
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index cfe0f4e..2d68736 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -341,7 +341,7 @@ macro_rules! declare_features {
(accepted, pattern_parentheses, "1.31.0", Some(51087)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
(accepted, precise_capturing, "1.82.0", Some(123432)),
- /// Allows `use<..>` precise capturign on impl Trait in traits.
+ /// Allows `use<..>` precise capturing on impl Trait in traits.
(accepted, precise_capturing_in_traits, "1.87.0", Some(130044)),
/// Allows procedural macros in `proc-macro` crates.
(accepted, proc_macro, "1.29.0", Some(38356)),
@@ -388,7 +388,7 @@ macro_rules! declare_features {
(accepted, self_struct_ctor, "1.32.0", Some(51994)),
/// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
(accepted, sha512_sm_x86, "CURRENT_RUSTC_VERSION", Some(126624)),
- /// Shortern the tail expression lifetime
+ /// Shorten the tail expression lifetime
(accepted, shorter_tail_lifetimes, "1.84.0", Some(123739)),
/// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
(accepted, slice_patterns, "1.42.0", Some(62254)),
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 8e13929..7d9915d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1140,6 +1140,10 @@ pub struct BuiltinAttribute {
WarnFollowing, EncodeCrossCrate::Yes
),
rustc_attr!(
+ TEST, rustc_no_implicit_bounds, CrateLevel, template!(Word),
+ WarnFollowing, EncodeCrossCrate::No
+ ),
+ rustc_attr!(
TEST, rustc_strict_coherence, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes
),
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index ddb9958..a855e4c1 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -87,7 +87,7 @@ macro_rules! declare_features {
Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported"), 87020),
/// Allows `T: ?const Trait` syntax in bounds.
(removed, const_trait_bound_opt_out, "1.56.0", Some(67794),
- Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]"), 88328),
+ Some("Removed in favor of `[const]` bound in #![feature(const_trait_impl)]"), 88328),
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
(removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`"), 97254),
/// Allows using custom attributes (RFC 572).
@@ -123,7 +123,7 @@ macro_rules! declare_features {
/// [^1]: Formerly known as "object safe".
(removed, dyn_compatible_for_dispatch, "1.87.0", Some(43561),
Some("removed, not used heavily and represented additional complexity in dyn compatibility"), 136522),
- /// Uses generic effect parameters for ~const bounds
+ /// Uses generic effect parameters for [const] bounds
(removed, effects, "1.84.0", Some(102090),
Some("removed, redundant with `#![feature(const_trait_impl)]`"), 132479),
/// Allows defining `existential type`s.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e73a4e1..719ba59 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -437,7 +437,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, const_async_blocks, "1.53.0", Some(85368)),
/// Allows `const || {}` closures in const contexts.
(incomplete, const_closures, "1.68.0", Some(106003)),
- /// Allows using `~const Destruct` bounds and calling drop impls in const contexts.
+ /// Allows using `[const] Destruct` bounds and calling drop impls in const contexts.
(unstable, const_destruct, "1.85.0", Some(133214)),
/// Allows `for _ in _` loops in const contexts.
(unstable, const_for, "1.56.0", Some(87575)),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 88e0ee1..75dff58 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3141,6 +3141,15 @@ pub enum TraitItemKind<'hir> {
/// type.
Type(GenericBounds<'hir>, Option<&'hir Ty<'hir>>),
}
+impl TraitItemKind<'_> {
+ pub fn descr(&self) -> &'static str {
+ match self {
+ TraitItemKind::Const(..) => "associated constant",
+ TraitItemKind::Fn(..) => "function",
+ TraitItemKind::Type(..) => "associated type",
+ }
+ }
+}
// The bodies for items are stored "out of line", in a separate
// hashmap in the `Crate`. Here we just record the hir-id of the item
@@ -3202,6 +3211,15 @@ pub enum ImplItemKind<'hir> {
/// An associated type.
Type(&'hir Ty<'hir>),
}
+impl ImplItemKind<'_> {
+ pub fn descr(&self) -> &'static str {
+ match self {
+ ImplItemKind::Const(..) => "associated constant",
+ ImplItemKind::Fn(..) => "function",
+ ImplItemKind::Type(..) => "associated type",
+ }
+ }
+}
/// A constraint on an associated item.
///
@@ -4527,6 +4545,16 @@ pub enum ForeignItemKind<'hir> {
Type,
}
+impl ForeignItemKind<'_> {
+ pub fn descr(&self) -> &'static str {
+ match self {
+ ForeignItemKind::Fn(..) => "function",
+ ForeignItemKind::Static(..) => "static variable",
+ ForeignItemKind::Type => "type",
+ }
+ }
+}
+
/// A variable captured by a closure.
#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub struct Upvar {
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 3a08e5a..10dd5ff 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -312,6 +312,7 @@ pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None;
PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None;
PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None;
+ PanicInvalidEnumConstruction, sym::panic_invalid_enum_construction, panic_invalid_enum_construction, Target::Fn, GenericRequirement::None;
PanicCoroutineResumedDrop, sym::panic_const_coroutine_resumed_drop, panic_const_coroutine_resumed_drop, Target::Fn, GenericRequirement::None;
PanicAsyncFnResumedDrop, sym::panic_const_async_fn_resumed_drop, panic_const_async_fn_resumed_drop, Target::Fn, GenericRequirement::None;
PanicAsyncGenFnResumedDrop, sym::panic_const_async_gen_fn_resumed_drop, panic_const_async_gen_fn_resumed_drop, Target::Fn, GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 4ec2bbf..529d357 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -447,6 +447,9 @@
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
.label = not allowed in type signatures
+
+hir_analysis_pointee_sized_trait_object = `PointeeSized` cannot be used with trait objects
+
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
.label = `Self` is not a generic argument, but an alias to the type of the {$what}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index f08a245..a361679 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -344,7 +344,7 @@ fn check_opaque_meets_bounds<'tcx>(
let misc_cause = ObligationCause::misc(span, def_id);
// FIXME: We should just register the item bounds here, rather than equating.
// FIXME(const_trait_impl): When we do that, please make sure to also register
- // the `~const` bounds.
+ // the `[const]` bounds.
match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
Ok(()) => {}
Err(ty_err) => {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 372a383..abbe497 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -264,9 +264,9 @@ fn compare_method_predicate_entailment<'tcx>(
}
// If we're within a const implementation, we need to make sure that the method
- // does not assume stronger `~const` bounds than the trait definition.
+ // does not assume stronger `[const]` bounds than the trait definition.
//
- // This registers the `~const` bounds of the impl method, which we will prove
+ // This registers the `[const]` bounds of the impl method, which we will prove
// using the hybrid param-env that we earlier augmented with the const conditions
// from the impl header and trait method declaration.
if is_conditionally_const {
@@ -2335,7 +2335,7 @@ pub(super) fn check_type_bounds<'tcx>(
)
.collect();
- // Only in a const implementation do we need to check that the `~const` item bounds hold.
+ // Only in a const implementation do we need to check that the `[const]` item bounds hold.
if tcx.is_conditionally_const(impl_ty_def_id) {
obligations.extend(util::elaborate(
tcx,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 060fc51..cebf7d1 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -594,8 +594,9 @@ pub(crate) fn check_intrinsic_type(
| sym::simd_ceil
| sym::simd_floor
| sym::simd_round
+ | sym::simd_round_ties_even
| sym::simd_trunc => (1, 0, vec![param(0)], param(0)),
- sym::simd_fma | sym::simd_relaxed_fma => {
+ sym::simd_fma | sym::simd_relaxed_fma | sym::simd_funnel_shl | sym::simd_funnel_shr => {
(1, 0, vec![param(0), param(0), param(0)], param(0))
}
sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)),
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 00f9347..b9124ea 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -231,7 +231,6 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
item.name = ? tcx.def_path_str(def_id)
);
crate::collect::lower_item(tcx, item.item_id());
- crate::collect::reject_placeholder_type_signatures_in_item(tcx, item);
let res = match item.kind {
// Right now we check that every default trait implementation
@@ -1403,7 +1402,7 @@ fn check_impl<'tcx>(
}
}
- // Ensure that the `~const` where clauses of the trait hold for the impl.
+ // Ensure that the `[const]` where clauses of the trait hold for the impl.
if tcx.is_conditionally_const(item.owner_id.def_id) {
for (bound, _) in
tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index c967e87..d756855 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -29,7 +29,7 @@
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_generics};
+use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt};
use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
@@ -154,26 +154,7 @@ fn visit_infer(&mut self, _inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -
}
}
-/// If there are any placeholder types (`_`), emit an error explaining that this is not allowed
-/// and suggest adding type parameters in the appropriate place, taking into consideration any and
-/// all already existing generic type parameters to avoid suggesting a name that is already in use.
-pub(crate) fn placeholder_type_error<'tcx>(
- cx: &dyn HirTyLowerer<'tcx>,
- generics: Option<&hir::Generics<'_>>,
- placeholder_types: Vec<Span>,
- suggest: bool,
- hir_ty: Option<&hir::Ty<'_>>,
- kind: &'static str,
-) {
- if placeholder_types.is_empty() {
- return;
- }
-
- placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
- .emit();
-}
-
-pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
+fn placeholder_type_error_diag<'cx, 'tcx>(
cx: &'cx dyn HirTyLowerer<'tcx>,
generics: Option<&hir::Generics<'_>>,
placeholder_types: Vec<Span>,
@@ -245,37 +226,6 @@ pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
err
}
-pub(super) fn reject_placeholder_type_signatures_in_item<'tcx>(
- tcx: TyCtxt<'tcx>,
- item: &'tcx hir::Item<'tcx>,
-) {
- let (generics, suggest) = match &item.kind {
- hir::ItemKind::Union(_, generics, _)
- | hir::ItemKind::Enum(_, generics, _)
- | hir::ItemKind::TraitAlias(_, generics, _)
- | hir::ItemKind::Trait(_, _, _, generics, ..)
- | hir::ItemKind::Impl(hir::Impl { generics, .. })
- | hir::ItemKind::Struct(_, generics, _) => (generics, true),
- hir::ItemKind::TyAlias(_, generics, _) => (generics, false),
- // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
- _ => return,
- };
-
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_item(item);
-
- let icx = ItemCtxt::new(tcx, item.owner_id.def_id);
-
- placeholder_type_error(
- icx.lowerer(),
- Some(generics),
- visitor.spans,
- suggest && !visitor.may_contain_const_infer,
- None,
- item.kind.descr(),
- );
-}
-
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
@@ -313,6 +263,54 @@ fn check_tainted_by_errors(&self) -> Result<(), ErrorGuaranteed> {
None => Ok(()),
}
}
+
+ fn report_placeholder_type_error(
+ &self,
+ placeholder_types: Vec<Span>,
+ infer_replacements: Vec<(Span, String)>,
+ ) -> ErrorGuaranteed {
+ let node = self.tcx.hir_node_by_def_id(self.item_def_id);
+ let generics = node.generics();
+ let kind_id = match node {
+ Node::GenericParam(_) | Node::WherePredicate(_) | Node::Field(_) => {
+ self.tcx.local_parent(self.item_def_id)
+ }
+ _ => self.item_def_id,
+ };
+ // FIXME: just invoke `tcx.def_descr` instead of going through the HIR
+ // Can also remove most `descr` methods then.
+ let kind = match self.tcx.hir_node_by_def_id(kind_id) {
+ Node::Item(it) => it.kind.descr(),
+ Node::ImplItem(it) => it.kind.descr(),
+ Node::TraitItem(it) => it.kind.descr(),
+ Node::ForeignItem(it) => it.kind.descr(),
+ Node::OpaqueTy(_) => "opaque type",
+ Node::Synthetic => self.tcx.def_descr(kind_id.into()),
+ node => todo!("{node:#?}"),
+ };
+ let mut diag = placeholder_type_error_diag(
+ self,
+ generics,
+ placeholder_types,
+ infer_replacements.iter().map(|&(span, _)| span).collect(),
+ false,
+ None,
+ kind,
+ );
+ if !infer_replacements.is_empty() {
+ diag.multipart_suggestion(
+ format!(
+ "try replacing `_` with the type{} in the corresponding trait method \
+ signature",
+ rustc_errors::pluralize!(infer_replacements.len()),
+ ),
+ infer_replacements,
+ Applicability::MachineApplicable,
+ );
+ }
+
+ diag.emit()
+ }
}
impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
@@ -346,10 +344,14 @@ fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx
}
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+ if !self.tcx.dcx().has_stashed_diagnostic(span, StashKey::ItemNoType) {
+ self.report_placeholder_type_error(vec![span], vec![]);
+ }
Ty::new_error_with_message(self.tcx(), span, "bad placeholder type")
}
fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
+ self.report_placeholder_type_error(vec![span], vec![]);
ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant")
}
@@ -524,18 +526,13 @@ fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
fn lower_fn_sig(
&self,
decl: &hir::FnDecl<'tcx>,
- generics: Option<&hir::Generics<'_>>,
+ _generics: Option<&hir::Generics<'_>>,
hir_id: rustc_hir::HirId,
- hir_ty: Option<&hir::Ty<'_>>,
+ _hir_ty: Option<&hir::Ty<'_>>,
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
let tcx = self.tcx();
- // We proactively collect all the inferred type params to emit a single error per fn def.
- let mut visitor = HirPlaceholderCollector::default();
- let mut infer_replacements = vec![];
- if let Some(generics) = generics {
- walk_generics(&mut visitor, generics);
- }
+ let mut infer_replacements = vec![];
let input_tys = decl
.inputs
@@ -551,8 +548,6 @@ fn lower_fn_sig(
}
}
- // Only visit the type looking for `_` if we didn't fix the type above
- visitor.visit_ty_unambig(a);
self.lowerer().lower_ty(a)
})
.collect();
@@ -566,42 +561,15 @@ fn lower_fn_sig(
infer_replacements.push((output.span, suggested_ty.to_string()));
Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
} else {
- visitor.visit_ty_unambig(output);
self.lower_ty(output)
}
}
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
};
- if !(visitor.spans.is_empty() && infer_replacements.is_empty()) {
- // We check for the presence of
- // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
-
- let mut diag = crate::collect::placeholder_type_error_diag(
- self,
- generics,
- visitor.spans,
- infer_replacements.iter().map(|(s, _)| *s).collect(),
- !visitor.may_contain_const_infer,
- hir_ty,
- "function",
- );
-
- if !infer_replacements.is_empty() {
- diag.multipart_suggestion(
- format!(
- "try replacing `_` with the type{} in the corresponding trait method \
- signature",
- rustc_errors::pluralize!(infer_replacements.len()),
- ),
- infer_replacements,
- Applicability::MachineApplicable,
- );
- }
-
- diag.emit();
+ if !infer_replacements.is_empty() {
+ self.report_placeholder_type_error(vec![], infer_replacements);
}
-
(input_tys, output_ty)
}
@@ -652,7 +620,6 @@ pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir_item(item_id);
debug!(item = ?it.kind.ident(), id = %it.hir_id());
let def_id = item_id.owner_id.def_id;
- let icx = ItemCtxt::new(tcx, def_id);
match &it.kind {
// These don't define types.
@@ -678,16 +645,6 @@ pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
}
hir::ForeignItemKind::Static(..) => {
tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_foreign_item(item);
- placeholder_type_error(
- icx.lowerer(),
- None,
- visitor.spans,
- false,
- None,
- "static variable",
- );
}
_ => (),
}
@@ -741,22 +698,10 @@ pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.ensure_ok().predicates_of(def_id);
}
- hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _) => {
+ hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
- if !ty.is_suggestable_infer_ty() {
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_item(it);
- placeholder_type_error(
- icx.lowerer(),
- None,
- visitor.spans,
- false,
- None,
- it.kind.descr(),
- );
- }
}
hir::ItemKind::Fn { .. } => {
@@ -773,7 +718,6 @@ pub(crate) fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId)
let trait_item = tcx.hir_trait_item(trait_item_id);
let def_id = trait_item_id.owner_id;
tcx.ensure_ok().generics_of(def_id);
- let icx = ItemCtxt::new(tcx, def_id.def_id);
match trait_item.kind {
hir::TraitItemKind::Fn(..) => {
@@ -782,58 +726,19 @@ pub(crate) fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId)
tcx.ensure_ok().fn_sig(def_id);
}
- hir::TraitItemKind::Const(ty, body_id) => {
+ hir::TraitItemKind::Const(..) => {
tcx.ensure_ok().type_of(def_id);
- if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
- && !(ty.is_suggestable_infer_ty() && body_id.is_some())
- {
- // Account for `const C: _;`.
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_trait_item(trait_item);
- placeholder_type_error(
- icx.lowerer(),
- None,
- visitor.spans,
- false,
- None,
- "associated constant",
- );
- }
}
hir::TraitItemKind::Type(_, Some(_)) => {
tcx.ensure_ok().item_bounds(def_id);
tcx.ensure_ok().item_self_bounds(def_id);
tcx.ensure_ok().type_of(def_id);
- // Account for `type T = _;`.
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_trait_item(trait_item);
- placeholder_type_error(
- icx.lowerer(),
- None,
- visitor.spans,
- false,
- None,
- "associated type",
- );
}
hir::TraitItemKind::Type(_, None) => {
tcx.ensure_ok().item_bounds(def_id);
tcx.ensure_ok().item_self_bounds(def_id);
- // #74612: Visit and try to find bad placeholders
- // even if there is no concrete type.
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_trait_item(trait_item);
-
- placeholder_type_error(
- icx.lowerer(),
- None,
- visitor.spans,
- false,
- None,
- "associated type",
- );
}
};
@@ -846,41 +751,13 @@ pub(super) fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
let impl_item = tcx.hir_impl_item(impl_item_id);
- let icx = ItemCtxt::new(tcx, def_id.def_id);
match impl_item.kind {
hir::ImplItemKind::Fn(..) => {
tcx.ensure_ok().codegen_fn_attrs(def_id);
tcx.ensure_ok().fn_sig(def_id);
}
- hir::ImplItemKind::Type(_) => {
- // Account for `type T = _;`
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_impl_item(impl_item);
-
- placeholder_type_error(
- icx.lowerer(),
- None,
- visitor.spans,
- false,
- None,
- "associated type",
- );
- }
- hir::ImplItemKind::Const(ty, _) => {
- // Account for `const T: _ = ..;`
- if !ty.is_suggestable_infer_ty() {
- let mut visitor = HirPlaceholderCollector::default();
- visitor.visit_impl_item(impl_item);
- placeholder_type_error(
- icx.lowerer(),
- None,
- visitor.spans,
- false,
- None,
- "associated constant",
- );
- }
- }
+ hir::ImplItemKind::Type(_) => {}
+ hir::ImplItemKind::Const(..) => {}
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 53c44cd..e51ef46 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -54,7 +54,7 @@ fn associated_type_bounds<'tcx>(
);
icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
}
- // `ConstIfConst` is only interested in `~const` bounds.
+ // `ConstIfConst` is only interested in `[const]` bounds.
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
}
@@ -351,7 +351,7 @@ fn opaque_type_bounds<'tcx>(
);
icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
}
- //`ConstIfConst` is only interested in `~const` bounds.
+ //`ConstIfConst` is only interested in `[const]` bounds.
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
}
debug!(?bounds);
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index c337765..a93e58b 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -421,7 +421,9 @@ fn is_const_param_default(tcx: TyCtxt<'_>, def: LocalDefId) -> bool {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ConstCollector<'tcx> {
fn visit_const(&mut self, c: ty::Const<'tcx>) {
if let ty::ConstKind::Unevaluated(uv) = c.kind() {
- if is_const_param_default(self.tcx, uv.def.expect_local()) {
+ if let Some(local) = uv.def.as_local()
+ && is_const_param_default(self.tcx, local)
+ {
// Do not look into const param defaults,
// these get checked when they are actually instantiated.
//
@@ -666,7 +668,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
item.span,
);
}
- //`ConstIfConst` is only interested in `~const` bounds.
+ //`ConstIfConst` is only interested in `[const]` bounds.
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
}
@@ -821,7 +823,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
assert_eq!(
pred.constness,
ty::BoundConstness::Maybe,
- "expected `~const` predicate when computing `{filter:?}` \
+ "expected `[const]` predicate when computing `{filter:?}` \
implied bounds: {clause:?}",
);
assert_eq!(
@@ -1009,7 +1011,7 @@ pub(super) fn const_conditions<'tcx>(
}
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
},
- // While associated types are not really const, we do allow them to have `~const`
+ // While associated types are not really const, we do allow them to have `[const]`
// bounds and where clauses. `const_conditions` is responsible for gathering
// these up so we can check them in `compare_type_predicate_entailment`, and
// in `HostEffect` goal computation.
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c920e25..c1c8283 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -319,6 +319,13 @@ pub(crate) struct TraitObjectDeclaredWithNoTraits {
}
#[derive(Diagnostic)]
+#[diag(hir_analysis_pointee_sized_trait_object)]
+pub(crate) struct PointeeSizedTraitObject {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
#[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)]
pub(crate) struct AmbiguousLifetimeBound {
#[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index a3c8ce6..ef78974 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -635,7 +635,7 @@ fn suggest_adding_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
self.suggest_adding_type_and_const_args(err);
}
ExcessTypesOrConsts { .. } => {
- // this can happen with `~const T` where T isn't a const_trait.
+ // this can happen with `[const] T` where T isn't a const_trait.
}
_ => unreachable!(),
}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index ea1dfdf..d17986d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -5,14 +5,14 @@
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_hir::{AmbigArg, LangItem, PolyTraitRef};
use rustc_middle::bug;
use rustc_middle::ty::{
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor, Upcast,
};
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
use rustc_trait_selection::traits;
use smallvec::SmallVec;
use tracing::{debug, instrument};
@@ -188,6 +188,11 @@ pub(crate) fn add_sizedness_bounds(
) {
let tcx = self.tcx();
+ // Skip adding any default bounds if `#![rustc_no_implicit_bounds]`
+ if tcx.has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) {
+ return;
+ }
+
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
@@ -408,24 +413,21 @@ pub(crate) fn add_default_trait(
let tcx = self.tcx();
let trait_id = tcx.lang_items().get(trait_);
if let Some(trait_id) = trait_id
- && self.do_not_provide_default_trait_bound(
- trait_id,
- hir_bounds,
- self_ty_where_predicates,
- )
+ && self.should_add_default_traits(trait_id, hir_bounds, self_ty_where_predicates)
{
add_trait_bound(tcx, bounds, self_ty, trait_id, span);
}
}
- fn do_not_provide_default_trait_bound<'a>(
+ /// Returns `true` if default trait bound should be added.
+ fn should_add_default_traits<'a>(
&self,
trait_def_id: DefId,
hir_bounds: &'a [hir::GenericBound<'tcx>],
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
) -> bool {
let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id);
- !collected.any()
+ !self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any()
}
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
@@ -492,7 +494,7 @@ pub(crate) fn lower_bounds<'hir, I: IntoIterator<Item = &'hir hir::GenericBound<
);
}
hir::GenericBound::Outlives(lifetime) => {
- // `ConstIfConst` is only interested in `~const` bounds.
+ // `ConstIfConst` is only interested in `[const]` bounds.
if matches!(
predicate_filter,
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst
@@ -708,7 +710,7 @@ pub(super) fn lower_assoc_item_constraint(
}
// SelfTraitThatDefines is only interested in trait predicates.
PredicateFilter::SelfTraitThatDefines(_) => {}
- // `ConstIfConst` is only interested in `~const` bounds.
+ // `ConstIfConst` is only interested in `[const]` bounds.
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
}
}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 05465b4..cb106962 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -2,6 +2,7 @@
use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
+use rustc_hir::LangItem;
use rustc_hir::def::{DefKind, Res};
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
@@ -69,7 +70,7 @@ pub(super) fn lower_trait_object_ty(
.into_iter()
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
- // We don't support empty trait objects.
+ // We don't support empty trait objects.
if regular_traits.is_empty() && auto_traits.is_empty() {
let guar =
self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied());
@@ -80,6 +81,13 @@ pub(super) fn lower_trait_object_ty(
let guar = self.report_trait_object_addition_traits(®ular_traits);
return Ty::new_error(tcx, guar);
}
+ // We don't support `PointeeSized` principals
+ let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+ if regular_traits.iter().any(|(pred, _)| pred.def_id() == pointee_sized_did) {
+ let guar = self.report_pointee_sized_trait_object(span);
+ return Ty::new_error(tcx, guar);
+ }
+
// Don't create a dyn trait if we have errors in the principal.
if let Err(guar) = regular_traits.error_reported() {
return Ty::new_error(tcx, guar);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index f211137..5d85a3f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -29,7 +29,7 @@
use super::InherentAssocCandidate;
use crate::errors::{
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
- ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
+ ParenthesizedFnTraitExpansion, PointeeSizedTraitObject, TraitObjectDeclaredWithNoTraits,
};
use crate::fluent_generated as fluent;
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
@@ -1410,6 +1410,10 @@ pub fn report_trait_object_with_no_traits(
self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
}
+
+ pub(super) fn report_pointee_sized_trait_object(&self, span: Span) -> ErrorGuaranteed {
+ self.dcx().emit_err(PointeeSizedTraitObject { span })
+ }
}
/// Emit an error for the given associated item constraint.
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index baf3b9b..7473935 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -80,10 +80,10 @@ pub enum PredicateFilter {
/// and `<Self as Tr>::A: B`.
SelfAndAssociatedTypeBounds,
- /// Filter only the `~const` bounds, which are lowered into `HostEffect` clauses.
+ /// Filter only the `[const]` bounds, which are lowered into `HostEffect` clauses.
ConstIfConst,
- /// Filter only the `~const` bounds which are *also* in the supertrait position.
+ /// Filter only the `[const]` bounds which are *also* in the supertrait position.
SelfConstIfConst,
}
@@ -885,7 +885,7 @@ pub(crate) fn lower_poly_trait_ref(
}
}
// On the flip side, when filtering `ConstIfConst` bounds, we only need to convert
- // `~const` bounds. All other predicates are handled in their respective queries.
+ // `[const]` bounds. All other predicates are handled in their respective queries.
//
// Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering
// here because we only call this on self bounds, and deal with the recursive case
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 309221f..574d19a 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -402,22 +402,22 @@ fn check_predicates<'tcx>(
/// as some predicate on the base impl (`predicate2`).
///
/// This basically just checks syntactic equivalence, but is a little more
-/// forgiving since we want to equate `T: Tr` with `T: ~const Tr` so this can work:
+/// forgiving since we want to equate `T: Tr` with `T: [const] Tr` so this can work:
///
/// ```ignore (illustrative)
/// #[rustc_specialization_trait]
/// trait Specialize { }
///
/// impl<T: Bound> Tr for T { }
-/// impl<T: ~const Bound + Specialize> const Tr for T { }
+/// impl<T: [const] Bound + Specialize> const Tr for T { }
/// ```
///
/// However, we *don't* want to allow the reverse, i.e., when the bound on the
/// specializing impl is not as const as the bound on the base impl:
///
/// ```ignore (illustrative)
-/// impl<T: ~const Bound> const Tr for T { }
-/// impl<T: Bound + Specialize> const Tr for T { } // should be T: ~const Bound
+/// impl<T: [const] Bound> const Tr for T { }
+/// impl<T: Bound + Specialize> const Tr for T { } // should be T: [const] Bound
/// ```
///
/// So we make that check in this function and try to raise a helpful error message.
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 76ab2e5..2ff7cae 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -65,7 +65,6 @@
#![feature(debug_closure_helpers)]
#![feature(gen_blocks)]
#![feature(if_let_guard)]
-#![feature(iter_from_coroutine)]
#![feature(iter_intersperse)]
#![feature(never_type)]
#![feature(rustdoc_internals)]
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index ff87d3d..087167d 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -784,7 +784,7 @@ fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
match constness {
hir::BoundConstness::Never => {}
hir::BoundConstness::Always(_) => self.word("const"),
- hir::BoundConstness::Maybe(_) => self.word("~const"),
+ hir::BoundConstness::Maybe(_) => self.word("[const]"),
}
match polarity {
hir::BoundPolarity::Positive => {}
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 94f1697..8c1399a 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -916,7 +916,7 @@ pub(super) fn enforce_context_effects(
return;
}
- // If we have `rustc_do_not_const_check`, do not check `~const` bounds.
+ // 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) {
return;
}
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 6fa473d..57d3c5d 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -278,8 +278,8 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
/// fall back to subtyping (`unify_and`).
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
- assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
- assert!(self.shallow_resolve(b) == b);
+ debug_assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
+ debug_assert!(self.shallow_resolve(b) == b);
if b.is_ty_var() {
// Two unresolved type variables: create a `Coerce` predicate.
@@ -323,6 +323,8 @@ fn coerce_borrowed_pointer(
mutbl_b: hir::Mutability,
) -> CoerceResult<'tcx> {
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
+ debug_assert!(self.shallow_resolve(a) == a);
+ debug_assert!(self.shallow_resolve(b) == b);
// If we have a parameter of type `&M T_a` and the value
// provided is `expr`, we will be adding an implicit borrow,
@@ -514,10 +516,10 @@ fn coerce_borrowed_pointer(
///
/// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
#[instrument(skip(self), level = "debug")]
- fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> {
- source = self.shallow_resolve(source);
- target = self.shallow_resolve(target);
+ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> {
debug!(?source, ?target);
+ debug_assert!(self.shallow_resolve(source) == source);
+ debug_assert!(self.shallow_resolve(target) == target);
// We don't apply any coercions incase either the source or target
// aren't sufficiently well known but tend to instead just equate
@@ -531,6 +533,54 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
return Err(TypeError::Mismatch);
}
+ // This is an optimization because coercion is one of the most common
+ // operations that we do in typeck, since it happens at every assignment
+ // and call arg (among other positions).
+ //
+ // These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
+ // That's because these are built-in types for which a core-provided impl
+ // doesn't exist, and for which a user-written impl is invalid.
+ //
+ // This is technically incomplete when users write impossible bounds like
+ // `where T: CoerceUnsized<usize>`, for example, but that trait is unstable
+ // and coercion is allowed to be incomplete. The only case where this matters
+ // is impossible bounds.
+ //
+ // Note that some of these types implement `LHS: Unsize<RHS>`, but they
+ // do not implement *`CoerceUnsized`* which is the root obligation of the
+ // check below.
+ match target.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+ | ty::Str
+ | ty::Array(_, _)
+ | ty::Slice(_)
+ | ty::FnDef(_, _)
+ | ty::FnPtr(_, _)
+ | ty::Dynamic(_, _, _)
+ | ty::Closure(_, _)
+ | ty::CoroutineClosure(_, _)
+ | ty::Coroutine(_, _)
+ | ty::CoroutineWitness(_, _)
+ | ty::Never
+ | ty::Tuple(_) => return Err(TypeError::Mismatch),
+ _ => {}
+ }
+ // Additionally, we ignore `&str -> &str` coercions, which happen very
+ // commonly since strings are one of the most used argument types in Rust,
+ // we do coercions when type checking call expressions.
+ if let ty::Ref(_, source_pointee, ty::Mutability::Not) = *source.kind()
+ && source_pointee.is_str()
+ && let ty::Ref(_, target_pointee, ty::Mutability::Not) = *target.kind()
+ && target_pointee.is_str()
+ {
+ return Err(TypeError::Mismatch);
+ }
+
let traits =
(self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait());
let (Some(unsize_did), Some(coerce_unsized_did)) = traits else {
@@ -800,6 +850,9 @@ fn coerce_dyn_star(
/// - `Pin<Box<T>>` as `Pin<&mut T>`
#[instrument(skip(self), level = "trace")]
fn coerce_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
+ debug_assert!(self.shallow_resolve(a) == a);
+ debug_assert!(self.shallow_resolve(b) == b);
+
// We need to make sure the two types are compatible for coercion.
// Then we will build a ReborrowPin adjustment and return that as an InferOk.
@@ -848,6 +901,8 @@ fn coerce_from_safe_fn(
b: Ty<'tcx>,
adjustment: Option<Adjust>,
) -> CoerceResult<'tcx> {
+ debug_assert!(self.shallow_resolve(b) == b);
+
self.commit_if_ok(|snapshot| {
let outer_universe = self.infcx.universe();
@@ -888,24 +943,19 @@ fn coerce_from_fn_pointer(
fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
- //! Attempts to coerce from the type of a Rust function item
- //! into a closure or a `proc`.
- //!
-
- let b = self.shallow_resolve(b);
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
+ debug_assert!(self.shallow_resolve(b) == b);
self.coerce_from_safe_fn(fn_ty_a, b, None)
}
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
- //! Attempts to coerce from the type of a Rust function item
- //! into a closure or a `proc`.
+ debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
+ debug_assert!(self.shallow_resolve(a) == a);
+ debug_assert!(self.shallow_resolve(b) == b);
- let b = self.shallow_resolve(b);
let InferOk { value: b, mut obligations } =
self.at(&self.cause, self.param_env).normalize(b);
- debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
match b.kind() {
ty::FnPtr(_, b_hdr) => {
@@ -955,6 +1005,8 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
}
}
+ /// Attempts to coerce from the type of a non-capturing closure
+ /// into a function pointer.
fn coerce_closure_to_fn(
&self,
a: Ty<'tcx>,
@@ -962,11 +1014,8 @@ fn coerce_closure_to_fn(
args_a: GenericArgsRef<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
- //! Attempts to coerce from the type of a non-capturing closure
- //! into a function pointer.
- //!
-
- let b = self.shallow_resolve(b);
+ debug_assert!(self.shallow_resolve(a) == a);
+ debug_assert!(self.shallow_resolve(b) == b);
match b.kind() {
// At this point we haven't done capture analysis, which means
@@ -1010,6 +1059,8 @@ fn coerce_raw_ptr(
mutbl_b: hir::Mutability,
) -> CoerceResult<'tcx> {
debug!("coerce_raw_ptr(a={:?}, b={:?})", a, b);
+ debug_assert!(self.shallow_resolve(a) == a);
+ debug_assert!(self.shallow_resolve(b) == b);
let (is_ref, mt_a) = match *a.kind() {
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 2df19cb..58751f2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -281,7 +281,7 @@ pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment
);
}
Adjust::Deref(None) => {
- // FIXME(const_trait_impl): We *could* enforce `&T: ~const Deref` here.
+ // FIXME(const_trait_impl): We *could* enforce `&T: [const] Deref` here.
}
Adjust::Pointer(_pointer_coercion) => {
// FIXME(const_trait_impl): We should probably enforce these.
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index d066879..d6c402d 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -1,4 +1,5 @@
use rustc_abi::FIRST_VARIANT;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
@@ -6,7 +7,7 @@
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt};
use rustc_session::declare_lint;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
use tracing::{debug, instrument};
use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub};
@@ -182,7 +183,11 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName {
// information, we could have codegen_fn_attrs also give span information back for
// where the attribute was defined. However, until this is found to be a
// bottleneck, this does just fine.
- (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span())
+ (
+ overridden_link_name,
+ find_attr!(tcx.get_all_attrs(fi), AttributeKind::LinkName {span, ..} => *span)
+ .unwrap(),
+ )
})
{
SymbolName::Link(overridden_link_name, overridden_link_name_span)
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index a868c88..a206f71 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -183,6 +183,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
let mut op_warned = false;
if let Some(must_use_op) = must_use_op {
+ let span = expr.span.find_oldest_ancestor_in_same_ctxt();
cx.emit_span_lint(
UNUSED_MUST_USE,
expr.span,
@@ -191,11 +192,11 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
label: expr.span,
suggestion: if expr_is_from_block {
UnusedOpSuggestion::BlockTailExpr {
- before_span: expr.span.shrink_to_lo(),
- after_span: expr.span.shrink_to_hi(),
+ before_span: span.shrink_to_lo(),
+ after_span: span.shrink_to_hi(),
}
} else {
- UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() }
+ UnusedOpSuggestion::NormalExpr { span: span.shrink_to_lo() }
},
},
);
@@ -508,9 +509,10 @@ fn emit_must_use_untranslated(
);
}
MustUsePath::Def(span, def_id, reason) => {
+ let span = span.find_oldest_ancestor_in_same_ctxt();
cx.emit_span_lint(
UNUSED_MUST_USE,
- *span,
+ span,
UnusedDef {
pre: descr_pre,
post: descr_post,
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 04fdada..dcd0116 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -220,7 +220,7 @@ fn identify_kind(
}
/// Generates the code for a field with no attributes.
- fn generate_field_arg(&mut self, binding_info: &BindingInfo<'_>) -> (TokenStream, TokenStream) {
+ fn generate_field_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
let diag = &self.parent.diag;
let field = binding_info.ast();
@@ -230,16 +230,12 @@ fn generate_field_arg(&mut self, binding_info: &BindingInfo<'_>) -> (TokenStream
let ident = field.ident.as_ref().unwrap();
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
- let args = quote! {
+ quote! {
#diag.arg(
stringify!(#ident),
#field_binding
);
- };
- let remove_args = quote! {
- #diag.remove_arg(stringify!(#ident));
- };
- (args, remove_args)
+ }
}
/// Generates the necessary code for all attributes on a field.
@@ -610,7 +606,7 @@ pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveErro
let restore_args = quote! {
#diag.restore_args();
};
- let (plain_args, remove_args): (TokenStream, TokenStream) = self
+ let plain_args: TokenStream = self
.variant
.bindings()
.iter()
@@ -623,9 +619,8 @@ pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveErro
// For #[derive(Subdiagnostic)]
//
// - Store args of the main diagnostic for later restore.
- // - add args of subdiagnostic.
+ // - Add args of subdiagnostic.
// - Generate the calls, such as note, label, etc.
- // - Remove the arguments for allowing Vec<Subdiagnostic> to be used.
// - Restore the arguments for allowing main and subdiagnostic share the same fields.
Ok(quote! {
#init
@@ -634,7 +629,6 @@ pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveErro
#store_args
#plain_args
#calls
- #remove_args
#restore_args
})
}
diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs
index 2b00b7d..78a4d47 100644
--- a/compiler/rustc_macros/src/symbols.rs
+++ b/compiler/rustc_macros/src/symbols.rs
@@ -190,17 +190,6 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
let mut symbols_stream = quote! {};
let mut prefill_stream = quote! {};
let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10);
- let mut prev_key: Option<(Span, String)> = None;
-
- let mut check_order = |span: Span, s: &str, errors: &mut Errors| {
- if let Some((prev_span, ref prev_str)) = prev_key {
- if s < prev_str {
- errors.error(span, format!("Symbol `{s}` must precede `{prev_str}`"));
- errors.error(prev_span, format!("location of previous symbol `{prev_str}`"));
- }
- }
- prev_key = Some((span, s.to_string()));
- };
// Generate the listed keywords.
for keyword in input.keywords.iter() {
@@ -219,7 +208,6 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
// Generate the listed symbols.
for symbol in input.symbols.iter() {
let name = &symbol.name;
- check_order(symbol.name.span(), &name.to_string(), &mut errors);
let value = match &symbol.value {
Value::SameAsName => name.to_string(),
diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs
index 9c53453..f0a7a21 100644
--- a/compiler/rustc_macros/src/symbols/tests.rs
+++ b/compiler/rustc_macros/src/symbols/tests.rs
@@ -84,18 +84,3 @@ fn check_dup_symbol_and_keyword() {
};
test_symbols_macro(input, &["Symbol `splat` is duplicated", "location of previous definition"]);
}
-
-#[test]
-fn check_symbol_order() {
- let input = quote! {
- Keywords {}
- Symbols {
- zebra,
- aardvark,
- }
- };
- test_symbols_macro(
- input,
- &["Symbol `aardvark` must precede `zebra`", "location of previous symbol `zebra`"],
- );
-}
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index de19c10..2c882b8 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1,7 +1,6 @@
//! Validates all used crates and extern libraries and loads their metadata
use std::error::Error;
-use std::ops::Fn;
use std::path::Path;
use std::str::FromStr;
use std::time::Duration;
@@ -276,12 +275,6 @@ pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMe
.filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
}
- fn iter_crate_data_mut(&mut self) -> impl Iterator<Item = (CrateNum, &mut CrateMetadata)> {
- self.metas
- .iter_enumerated_mut()
- .filter_map(|(cnum, data)| data.as_deref_mut().map(|data| (cnum, data)))
- }
-
fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) {
if !deps.contains(&cnum) {
let data = self.get_crate_data(cnum);
@@ -307,13 +300,6 @@ pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> IndexSet
deps
}
- fn crate_dependencies_in_reverse_postorder(
- &self,
- cnum: CrateNum,
- ) -> impl Iterator<Item = CrateNum> {
- self.crate_dependencies_in_postorder(cnum).into_iter().rev()
- }
-
pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> {
self.injected_panic_runtime
}
@@ -966,47 +952,27 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
// If we need a panic runtime, we try to find an existing one here. At
// the same time we perform some general validation of the DAG we've got
// going such as ensuring everything has a compatible panic strategy.
- //
- // The logic for finding the panic runtime here is pretty much the same
- // as the allocator case with the only addition that the panic strategy
- // compilation mode also comes into play.
- let desired_strategy = self.sess.panic_strategy();
- let mut runtime_found = false;
let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
-
- let mut panic_runtimes = Vec::new();
- for (cnum, data) in self.cstore.iter_crate_data() {
- needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
- if data.is_panic_runtime() {
- // Inject a dependency from all #![needs_panic_runtime] to this
- // #![panic_runtime] crate.
- panic_runtimes.push(cnum);
- runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit;
- }
- }
- for cnum in panic_runtimes {
- self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
+ for (_cnum, data) in self.cstore.iter_crate_data() {
+ needs_panic_runtime |= data.needs_panic_runtime();
}
- // If an explicitly linked and matching panic runtime was found, or if
- // we just don't need one at all, then we're done here and there's
- // nothing else to do.
- if !needs_panic_runtime || runtime_found {
+ // If we just don't need a panic runtime at all, then we're done here
+ // and there's nothing else to do.
+ if !needs_panic_runtime {
return;
}
- // By this point we know that we (a) need a panic runtime and (b) no
- // panic runtime was explicitly linked. Here we just load an appropriate
- // default runtime for our panic strategy and then inject the
- // dependencies.
+ // By this point we know that we need a panic runtime. Here we just load
+ // an appropriate default runtime for our panic strategy.
//
// We may resolve to an already loaded crate (as the crate may not have
- // been explicitly linked prior to this) and we may re-inject
- // dependencies again, but both of those situations are fine.
+ // been explicitly linked prior to this), but this is fine.
//
// Also note that we have yet to perform validation of the crate graph
// in terms of everyone has a compatible panic runtime format, that's
// performed later as part of the `dependency_format` module.
+ let desired_strategy = self.sess.panic_strategy();
let name = match desired_strategy {
PanicStrategy::Unwind => sym::panic_unwind,
PanicStrategy::Abort => sym::panic_abort,
@@ -1031,7 +997,6 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
}
self.cstore.injected_panic_runtime = Some(cnum);
- self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
}
fn inject_profiler_runtime(&mut self) {
@@ -1212,45 +1177,6 @@ fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
}
}
- fn inject_dependency_if(
- &mut self,
- krate: CrateNum,
- what: &str,
- needs_dep: &dyn Fn(&CrateMetadata) -> bool,
- ) {
- // Don't perform this validation if the session has errors, as one of
- // those errors may indicate a circular dependency which could cause
- // this to stack overflow.
- if self.dcx().has_errors().is_some() {
- return;
- }
-
- // Before we inject any dependencies, make sure we don't inject a
- // circular dependency by validating that this crate doesn't
- // transitively depend on any crates satisfying `needs_dep`.
- for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
- let data = self.cstore.get_crate_data(dep);
- if needs_dep(&data) {
- self.dcx().emit_err(errors::NoTransitiveNeedsDep {
- crate_name: self.cstore.get_crate_data(krate).name(),
- needs_crate_name: what,
- deps_crate_name: data.name(),
- });
- }
- }
-
- // All crates satisfying `needs_dep` do not explicitly depend on the
- // crate provided for this compile, but in order for this compilation to
- // be successfully linked we need to inject a dependency (to order the
- // crates on the command line correctly).
- for (cnum, data) in self.cstore.iter_crate_data_mut() {
- if needs_dep(data) {
- info!("injecting a dep from {} to {}", cnum, krate);
- data.add_dependency(krate);
- }
- }
- }
-
fn report_unused_deps(&mut self, krate: &ast::Crate) {
// Make a point span rather than covering the whole file
let span = krate.spans.inner_span.shrink_to_lo();
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 1089c4a..fb9c2e2 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -370,15 +370,15 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De
Some(ret)
}
-// Given a list of how to link upstream dependencies so far, ensure that an
-// injected dependency is activated. This will not do anything if one was
-// transitively included already (e.g., via a dylib or explicitly so).
-//
-// If an injected dependency was not found then we're guaranteed the
-// metadata::creader module has injected that dependency (not listed as
-// a required dependency) in one of the session's field. If this field is not
-// set then this compilation doesn't actually need the dependency and we can
-// also skip this step entirely.
+/// Given a list of how to link upstream dependencies so far, ensure that an
+/// injected dependency is activated. This will not do anything if one was
+/// transitively included already (e.g., via a dylib or explicitly so).
+///
+/// If an injected dependency was not found then we're guaranteed the
+/// metadata::creader module has injected that dependency (not listed as
+/// a required dependency) in one of the session's field. If this field is not
+/// set then this compilation doesn't actually need the dependency and we can
+/// also skip this step entirely.
fn activate_injected_dep(
injected: Option<CrateNum>,
list: &mut DependencyList,
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 23ffb1e..3e50689 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -7,7 +7,6 @@
#![feature(file_buffered)]
#![feature(gen_blocks)]
#![feature(if_let_guard)]
-#![feature(iter_from_coroutine)]
#![feature(macro_metavar_expr)]
#![feature(min_specialization)]
#![feature(never_type)]
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index d886f25..2696c47 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1912,10 +1912,6 @@ pub(crate) fn dependencies(&self) -> impl Iterator<Item = CrateNum> {
self.dependencies.iter().copied()
}
- pub(crate) fn add_dependency(&mut self, cnum: CrateNum) {
- self.dependencies.push(cnum);
- }
-
pub(crate) fn target_modifiers(&self) -> TargetModifiers {
self.root.decode_target_modifiers(&self.blob).collect()
}
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 0073deb..69aa438 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -17,6 +17,9 @@
middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further iterated on after it panicked
+middle_assert_invalid_enum_construction =
+ trying to construct an enum from an invalid value `{$source}`
+
middle_assert_misaligned_ptr_deref =
misaligned pointer dereference: address must be a multiple of {$required} but is {$found}
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index ce2cb33..b30b9b6 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -48,7 +48,6 @@
#![feature(gen_blocks)]
#![feature(if_let_guard)]
#![feature(intra_doc_pointers)]
-#![feature(iter_from_coroutine)]
#![feature(min_specialization)]
#![feature(negative_impls)]
#![feature(never_type)]
diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs
index 64a1f2a..c70ff39 100644
--- a/compiler/rustc_middle/src/middle/exported_symbols.rs
+++ b/compiler/rustc_middle/src/middle/exported_symbols.rs
@@ -31,11 +31,17 @@ pub enum SymbolExportKind {
/// The `SymbolExportInfo` of a symbols specifies symbol-related information
/// that is relevant to code generation and linking.
+///
+/// The difference between `used` and `rustc_std_internal_symbol` is that the
+/// former is exported by LTO while the latter isn't.
#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
pub struct SymbolExportInfo {
pub level: SymbolExportLevel,
pub kind: SymbolExportKind,
+ /// Was the symbol marked as `#[used(compiler)]` or `#[used(linker)]`?
pub used: bool,
+ /// Was the symbol marked as `#[rustc_std_internal_symbol]`?
+ pub rustc_std_internal_symbol: bool,
}
#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index ab6a65e..99faba7 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -620,7 +620,7 @@ pub fn check_optional_stability(
/// instead of regular stability.
///
/// This enforces *syntactical* const stability of const traits. In other words,
- /// it enforces the ability to name `~const`/`const` traits in trait bounds in various
+ /// it enforces the ability to name `[const]`/`const` traits in trait bounds in various
/// syntax positions in HIR (including in the trait of an impl header).
pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Span) {
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 56f19d7..92eefd8 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -284,15 +284,15 @@ pub enum FakeBorrowKind {
///
/// This is used when lowering deref patterns, where shallow borrows wouldn't prevent something
/// like:
- // ```compile_fail
- // let mut b = Box::new(false);
- // match b {
- // deref!(true) => {} // not reached because `*b == false`
- // _ if { *b = true; false } => {} // not reached because the guard is `false`
- // deref!(false) => {} // not reached because the guard changed it
- // // UB because we reached the unreachable.
- // }
- // ```
+ /// ```compile_fail
+ /// let mut b = Box::new(false);
+ /// match b {
+ /// deref!(true) => {} // not reached because `*b == false`
+ /// _ if { *b = true; false } => {} // not reached because the guard is `false`
+ /// deref!(false) => {} // not reached because the guard changed it
+ /// // UB because we reached the unreachable.
+ /// }
+ /// ```
Deep,
}
@@ -1075,6 +1075,7 @@ pub enum AssertKind<O> {
ResumedAfterDrop(CoroutineKind),
MisalignedPointerDereference { required: O, found: O },
NullPointerDereference,
+ InvalidEnumConstruction(O),
}
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 0834fa8..4034a3a 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -208,6 +208,7 @@ pub fn panic_function(&self) -> LangItem {
LangItem::PanicGenFnNonePanic
}
NullPointerDereference => LangItem::PanicNullPointerDereference,
+ InvalidEnumConstruction(_) => LangItem::PanicInvalidEnumConstruction,
ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop,
ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
LangItem::PanicAsyncFnResumedDrop
@@ -284,6 +285,9 @@ pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
)
}
NullPointerDereference => write!(f, "\"null pointer dereference occurred\""),
+ InvalidEnumConstruction(source) => {
+ write!(f, "\"trying to construct an enum from an invalid value {{}}\", {source:?}")
+ }
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
write!(f, "\"coroutine resumed after completion\"")
}
@@ -367,6 +371,7 @@ pub fn diagnostic_message(&self) -> DiagMessage {
middle_assert_coroutine_resume_after_panic
}
NullPointerDereference => middle_assert_null_ptr_deref,
+ InvalidEnumConstruction(_) => middle_assert_invalid_enum_construction,
ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
middle_assert_async_resume_after_drop
}
@@ -420,6 +425,9 @@ macro_rules! add {
add!("required", format!("{required:#?}"));
add!("found", format!("{found:#?}"));
}
+ InvalidEnumConstruction(source) => {
+ add!("source", format!("{source:#?}"));
+ }
}
}
}
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 1777756..929ebe1 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -642,7 +642,7 @@ fn super_assert_message(
self.visit_operand(l, location);
self.visit_operand(r, location);
}
- OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+ OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) | InvalidEnumConstruction(op) => {
self.visit_operand(op, location);
}
ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference | ResumedAfterDrop(_) => {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 3668f4e..8a3d26e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -850,14 +850,14 @@
}
/// Compute the conditions that need to hold for a conditionally-const item to be const.
- /// That is, compute the set of `~const` where clauses for a given item.
+ /// That is, compute the set of `[const]` where clauses for a given item.
///
- /// This can be thought of as the `~const` equivalent of `predicates_of`. These are the
+ /// This can be thought of as the `[const]` equivalent of `predicates_of`. These are the
/// predicates that need to be proven at usage sites, and can be assumed at definition.
///
- /// This query also computes the `~const` where clauses for associated types, which are
- /// not "const", but which have item bounds which may be `~const`. These must hold for
- /// the `~const` item bound to hold.
+ /// This query also computes the `[const]` where clauses for associated types, which are
+ /// not "const", but which have item bounds which may be `[const]`. These must hold for
+ /// the `[const]` item bound to hold.
query const_conditions(
key: DefId
) -> ty::ConstConditions<'tcx> {
@@ -869,13 +869,13 @@
/// Compute the const bounds that are implied for a conditionally-const item.
///
- /// This can be though of as the `~const` equivalent of `explicit_item_bounds`. These
+ /// This can be though of as the `[const]` equivalent of `explicit_item_bounds`. These
/// are the predicates that need to proven at definition sites, and can be assumed at
/// usage sites.
query explicit_implied_const_bounds(
key: DefId
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
- desc { |tcx| "computing the implied `~const` bounds for `{}`",
+ desc { |tcx| "computing the implied `[const]` bounds for `{}`",
tcx.def_path_str(key)
}
separate_provide_extern
@@ -1283,15 +1283,15 @@
return_result_from_ensure_ok
}
- /// Check whether the function has any recursion that could cause the inliner to trigger
- /// a cycle.
- query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool {
+ /// Return the set of (transitive) callees that may result in a recursive call to `key`.
+ query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> {
fatal_cycle
+ arena_cache
desc { |tcx|
- "computing if `{}` (transitively) calls `{}`",
- key.0,
- tcx.def_path_str(key.1),
+ "computing (transitive) callees of `{}` that may recurse",
+ tcx.def_path_str(key),
}
+ cache_on_disk_if { true }
}
/// Obtain all the calls into other local functions
@@ -1311,7 +1311,7 @@
///
/// This query will panic for uninhabited variants and if the passed type is not an enum.
query tag_for_variant(
- key: (Ty<'tcx>, abi::VariantIdx)
+ key: PseudoCanonicalInput<'tcx, (Ty<'tcx>, abi::VariantIdx)>,
) -> Option<ty::ScalarInt> {
desc { "computing variant tag for enum" }
}
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index d4cc562..c7b3b54 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -419,7 +419,7 @@ fn instantiate_identity_into(
}
}
-/// `~const` bounds for a given item. This is represented using a struct much like
+/// `[const]` bounds for a given item. This is represented using a struct much like
/// `GenericPredicates`, where you can either choose to only instantiate the "own"
/// bounds or all of the bounds including those from the parent. This distinction
/// is necessary for code like `compare_method_predicate_entailment`.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 425f518..84b21fe 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2139,7 +2139,7 @@ pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
},
DefKind::Closure => {
// Closures and RPITs will eventually have const conditions
- // for `~const` bounds.
+ // for `[const]` bounds.
false
}
DefKind::Ctor(_, CtorKind::Const)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index c10277c..1392d1d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2077,7 +2077,7 @@ fn pretty_print_bound_constness(
p!("const ");
}
ty::BoundConstness::Maybe => {
- p!("~const ");
+ p!("[const] ");
}
}
Ok(())
@@ -3250,7 +3250,7 @@ macro_rules! define_print_and_forward_display {
ty::HostEffectPredicate<'tcx> {
let constness = match self.constness {
ty::BoundConstness::Const => { "const" }
- ty::BoundConstness::Maybe => { "~const" }
+ ty::BoundConstness::Maybe => { "[const]" }
};
p!(print(self.trait_ref.self_ty()), ": {constness} ");
p!(print(self.trait_ref.print_trait_sugared()))
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 51f57e7..69b8be3 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -768,6 +768,7 @@ pub fn def_descr(self, def_id: DefId) -> &'static str {
pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str {
match def_kind {
DefKind::AssocFn if self.associated_item(def_id).is_method() => "method",
+ DefKind::AssocTy if self.opt_rpitit_info(def_id).is_some() => "opaque type",
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
match coroutine_kind {
hir::CoroutineKind::Desugared(
diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs
new file mode 100644
index 0000000..e06e0c6
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/check_enums.rs
@@ -0,0 +1,501 @@
+use rustc_abi::{Scalar, Size, TagEncoding, Variants, WrappingRange};
+use rustc_hir::LangItem;
+use rustc_index::IndexVec;
+use rustc_middle::bug;
+use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::*;
+use rustc_middle::ty::layout::PrimitiveExt;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingEnv};
+use rustc_session::Session;
+use tracing::debug;
+
+/// This pass inserts checks for a valid enum discriminant where they are most
+/// likely to find UB, because checking everywhere like Miri would generate too
+/// much MIR.
+pub(super) struct CheckEnums;
+
+impl<'tcx> crate::MirPass<'tcx> for CheckEnums {
+ fn is_enabled(&self, sess: &Session) -> bool {
+ sess.ub_checks()
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ // This pass emits new panics. If for whatever reason we do not have a panic
+ // implementation, running this pass may cause otherwise-valid code to not compile.
+ if tcx.lang_items().get(LangItem::PanicImpl).is_none() {
+ return;
+ }
+
+ let typing_env = body.typing_env(tcx);
+ let basic_blocks = body.basic_blocks.as_mut();
+ let local_decls = &mut body.local_decls;
+
+ // This operation inserts new blocks. Each insertion changes the Location for all
+ // statements/blocks after. Iterating or visiting the MIR in order would require updating
+ // our current location after every insertion. By iterating backwards, we dodge this issue:
+ // The only Locations that an insertion changes have already been handled.
+ for block in basic_blocks.indices().rev() {
+ for statement_index in (0..basic_blocks[block].statements.len()).rev() {
+ let location = Location { block, statement_index };
+ let statement = &basic_blocks[block].statements[statement_index];
+ let source_info = statement.source_info;
+
+ let mut finder = EnumFinder::new(tcx, local_decls, typing_env);
+ finder.visit_statement(statement, location);
+
+ for check in finder.into_found_enums() {
+ debug!("Inserting enum check");
+ let new_block = split_block(basic_blocks, location);
+
+ match check {
+ EnumCheckType::Direct { source_op, discr, op_size, valid_discrs } => {
+ insert_direct_enum_check(
+ tcx,
+ local_decls,
+ basic_blocks,
+ block,
+ source_op,
+ discr,
+ op_size,
+ valid_discrs,
+ source_info,
+ new_block,
+ )
+ }
+ EnumCheckType::Uninhabited => insert_uninhabited_enum_check(
+ tcx,
+ local_decls,
+ &mut basic_blocks[block],
+ source_info,
+ new_block,
+ ),
+ EnumCheckType::WithNiche {
+ source_op,
+ discr,
+ op_size,
+ offset,
+ valid_range,
+ } => insert_niche_check(
+ tcx,
+ local_decls,
+ &mut basic_blocks[block],
+ source_op,
+ valid_range,
+ discr,
+ op_size,
+ offset,
+ source_info,
+ new_block,
+ ),
+ }
+ }
+ }
+ }
+ }
+
+ fn is_required(&self) -> bool {
+ true
+ }
+}
+
+/// Represent the different kind of enum checks we can insert.
+enum EnumCheckType<'tcx> {
+ /// We know we try to create an uninhabited enum from an inhabited variant.
+ Uninhabited,
+ /// We know the enum does no niche optimizations and can thus easily compute
+ /// the valid discriminants.
+ Direct {
+ source_op: Operand<'tcx>,
+ discr: TyAndSize<'tcx>,
+ op_size: Size,
+ valid_discrs: Vec<u128>,
+ },
+ /// We try to construct an enum that has a niche.
+ WithNiche {
+ source_op: Operand<'tcx>,
+ discr: TyAndSize<'tcx>,
+ op_size: Size,
+ offset: Size,
+ valid_range: WrappingRange,
+ },
+}
+
+struct TyAndSize<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub size: Size,
+}
+
+/// A [Visitor] that finds the construction of enums and evaluates which checks
+/// we should apply.
+struct EnumFinder<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ local_decls: &'a mut LocalDecls<'tcx>,
+ typing_env: TypingEnv<'tcx>,
+ enums: Vec<EnumCheckType<'tcx>>,
+}
+
+impl<'a, 'tcx> EnumFinder<'a, 'tcx> {
+ fn new(
+ tcx: TyCtxt<'tcx>,
+ local_decls: &'a mut LocalDecls<'tcx>,
+ typing_env: TypingEnv<'tcx>,
+ ) -> Self {
+ EnumFinder { tcx, local_decls, typing_env, enums: Vec::new() }
+ }
+
+ /// Returns the found enum creations and which checks should be inserted.
+ fn into_found_enums(self) -> Vec<EnumCheckType<'tcx>> {
+ self.enums
+ }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for EnumFinder<'a, 'tcx> {
+ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+ if let Rvalue::Cast(CastKind::Transmute, op, ty) = rvalue {
+ let ty::Adt(adt_def, _) = ty.kind() else {
+ return;
+ };
+ if !adt_def.is_enum() {
+ return;
+ }
+
+ let Ok(enum_layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
+ return;
+ };
+ let Ok(op_layout) = self
+ .tcx
+ .layout_of(self.typing_env.as_query_input(op.ty(self.local_decls, self.tcx)))
+ else {
+ return;
+ };
+
+ match enum_layout.variants {
+ Variants::Empty if op_layout.is_uninhabited() => return,
+ // An empty enum that tries to be constructed from an inhabited value, this
+ // is never correct.
+ Variants::Empty => {
+ // The enum layout is uninhabited but we construct it from sth inhabited.
+ // This is always UB.
+ self.enums.push(EnumCheckType::Uninhabited);
+ }
+ // Construction of Single value enums is always fine.
+ Variants::Single { .. } => {}
+ // Construction of an enum with multiple variants but no niche optimizations.
+ Variants::Multiple {
+ tag_encoding: TagEncoding::Direct,
+ tag: Scalar::Initialized { value, .. },
+ ..
+ } => {
+ let valid_discrs =
+ adt_def.discriminants(self.tcx).map(|(_, discr)| discr.val).collect();
+
+ let discr =
+ TyAndSize { ty: value.to_int_ty(self.tcx), size: value.size(&self.tcx) };
+ self.enums.push(EnumCheckType::Direct {
+ source_op: op.to_copy(),
+ discr,
+ op_size: op_layout.size,
+ valid_discrs,
+ });
+ }
+ // Construction of an enum with multiple variants and niche optimizations.
+ Variants::Multiple {
+ tag_encoding: TagEncoding::Niche { .. },
+ tag: Scalar::Initialized { value, valid_range, .. },
+ tag_field,
+ ..
+ } => {
+ let discr =
+ TyAndSize { ty: value.to_int_ty(self.tcx), size: value.size(&self.tcx) };
+ self.enums.push(EnumCheckType::WithNiche {
+ source_op: op.to_copy(),
+ discr,
+ op_size: op_layout.size,
+ offset: enum_layout.fields.offset(tag_field.as_usize()),
+ valid_range,
+ });
+ }
+ _ => return,
+ }
+
+ self.super_rvalue(rvalue, location);
+ }
+ }
+}
+
+fn split_block(
+ basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+ location: Location,
+) -> BasicBlock {
+ let block_data = &mut basic_blocks[location.block];
+
+ // Drain every statement after this one and move the current terminator to a new basic block.
+ let new_block = BasicBlockData {
+ statements: block_data.statements.split_off(location.statement_index),
+ terminator: block_data.terminator.take(),
+ is_cleanup: block_data.is_cleanup,
+ };
+
+ basic_blocks.push(new_block)
+}
+
+/// Inserts the cast of an operand (any type) to a u128 value that holds the discriminant value.
+fn insert_discr_cast_to_u128<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
+ block_data: &mut BasicBlockData<'tcx>,
+ source_op: Operand<'tcx>,
+ discr: TyAndSize<'tcx>,
+ op_size: Size,
+ offset: Option<Size>,
+ source_info: SourceInfo,
+) -> Place<'tcx> {
+ let get_ty_for_size = |tcx: TyCtxt<'tcx>, size: Size| -> Ty<'tcx> {
+ match size.bytes() {
+ 1 => tcx.types.u8,
+ 2 => tcx.types.u16,
+ 4 => tcx.types.u32,
+ 8 => tcx.types.u64,
+ 16 => tcx.types.u128,
+ invalid => bug!("Found discriminant with invalid size, has {} bytes", invalid),
+ }
+ };
+
+ let (cast_kind, discr_ty_bits) = if discr.size.bytes() < op_size.bytes() {
+ // The discriminant is less wide than the operand, cast the operand into
+ // [MaybeUninit; N] and then index into it.
+ let mu = Ty::new_maybe_uninit(tcx, tcx.types.u8);
+ let array_len = op_size.bytes();
+ let mu_array_ty = Ty::new_array(tcx, mu, array_len);
+ let mu_array =
+ local_decls.push(LocalDecl::with_source_info(mu_array_ty, source_info)).into();
+ let rvalue = Rvalue::Cast(CastKind::Transmute, source_op, mu_array_ty);
+ block_data.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Assign(Box::new((mu_array, rvalue))),
+ });
+
+ // Index into the array of MaybeUninit to get something that is actually
+ // as wide as the discriminant.
+ let offset = offset.unwrap_or(Size::ZERO);
+ let smaller_mu_array = mu_array.project_deeper(
+ &[ProjectionElem::Subslice {
+ from: offset.bytes(),
+ to: offset.bytes() + discr.size.bytes(),
+ from_end: false,
+ }],
+ tcx,
+ );
+
+ (CastKind::Transmute, Operand::Copy(smaller_mu_array))
+ } else {
+ let operand_int_ty = get_ty_for_size(tcx, op_size);
+
+ let op_as_int =
+ local_decls.push(LocalDecl::with_source_info(operand_int_ty, source_info)).into();
+ let rvalue = Rvalue::Cast(CastKind::Transmute, source_op, operand_int_ty);
+ block_data.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Assign(Box::new((op_as_int, rvalue))),
+ });
+
+ (CastKind::IntToInt, Operand::Copy(op_as_int))
+ };
+
+ // Cast the resulting value to the actual discriminant integer type.
+ let rvalue = Rvalue::Cast(cast_kind, discr_ty_bits, discr.ty);
+ let discr_in_discr_ty =
+ local_decls.push(LocalDecl::with_source_info(discr.ty, source_info)).into();
+ block_data.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Assign(Box::new((discr_in_discr_ty, rvalue))),
+ });
+
+ // Cast the discriminant to a u128 (base for comparisions of enum discriminants).
+ let const_u128 = Ty::new_uint(tcx, ty::UintTy::U128);
+ let rvalue = Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr_in_discr_ty), const_u128);
+ let discr = local_decls.push(LocalDecl::with_source_info(const_u128, source_info)).into();
+ block_data
+ .statements
+ .push(Statement { source_info, kind: StatementKind::Assign(Box::new((discr, rvalue))) });
+
+ discr
+}
+
+fn insert_direct_enum_check<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
+ basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+ current_block: BasicBlock,
+ source_op: Operand<'tcx>,
+ discr: TyAndSize<'tcx>,
+ op_size: Size,
+ discriminants: Vec<u128>,
+ source_info: SourceInfo,
+ new_block: BasicBlock,
+) {
+ // Insert a new target block that is branched to in case of an invalid discriminant.
+ let invalid_discr_block_data = BasicBlockData::new(None, false);
+ let invalid_discr_block = basic_blocks.push(invalid_discr_block_data);
+ let block_data = &mut basic_blocks[current_block];
+ let discr = insert_discr_cast_to_u128(
+ tcx,
+ local_decls,
+ block_data,
+ source_op,
+ discr,
+ op_size,
+ None,
+ source_info,
+ );
+
+ // Branch based on the discriminant value.
+ block_data.terminator = Some(Terminator {
+ source_info,
+ kind: TerminatorKind::SwitchInt {
+ discr: Operand::Copy(discr),
+ targets: SwitchTargets::new(
+ discriminants.into_iter().map(|discr| (discr, new_block)),
+ invalid_discr_block,
+ ),
+ },
+ });
+
+ // Abort in case of an invalid enum discriminant.
+ basic_blocks[invalid_discr_block].terminator = Some(Terminator {
+ source_info,
+ kind: TerminatorKind::Assert {
+ cond: Operand::Constant(Box::new(ConstOperand {
+ span: source_info.span,
+ user_ty: None,
+ const_: Const::Val(ConstValue::from_bool(false), tcx.types.bool),
+ })),
+ expected: true,
+ target: new_block,
+ msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr))),
+ // This calls panic_invalid_enum_construction, which is #[rustc_nounwind].
+ // We never want to insert an unwind into unsafe code, because unwinding could
+ // make a failing UB check turn into much worse UB when we start unwinding.
+ unwind: UnwindAction::Unreachable,
+ },
+ });
+}
+
+fn insert_uninhabited_enum_check<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
+ block_data: &mut BasicBlockData<'tcx>,
+ source_info: SourceInfo,
+ new_block: BasicBlock,
+) {
+ let is_ok: Place<'_> =
+ local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
+ block_data.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Assign(Box::new((
+ is_ok,
+ Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
+ span: source_info.span,
+ user_ty: None,
+ const_: Const::Val(ConstValue::from_bool(false), tcx.types.bool),
+ }))),
+ ))),
+ });
+
+ block_data.terminator = Some(Terminator {
+ source_info,
+ kind: TerminatorKind::Assert {
+ cond: Operand::Copy(is_ok),
+ expected: true,
+ target: new_block,
+ msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Constant(Box::new(
+ ConstOperand {
+ span: source_info.span,
+ user_ty: None,
+ const_: Const::Val(ConstValue::from_u128(0), tcx.types.u128),
+ },
+ )))),
+ // This calls panic_invalid_enum_construction, which is #[rustc_nounwind].
+ // We never want to insert an unwind into unsafe code, because unwinding could
+ // make a failing UB check turn into much worse UB when we start unwinding.
+ unwind: UnwindAction::Unreachable,
+ },
+ });
+}
+
+fn insert_niche_check<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
+ block_data: &mut BasicBlockData<'tcx>,
+ source_op: Operand<'tcx>,
+ valid_range: WrappingRange,
+ discr: TyAndSize<'tcx>,
+ op_size: Size,
+ offset: Size,
+ source_info: SourceInfo,
+ new_block: BasicBlock,
+) {
+ let discr = insert_discr_cast_to_u128(
+ tcx,
+ local_decls,
+ block_data,
+ source_op,
+ discr,
+ op_size,
+ Some(offset),
+ source_info,
+ );
+
+ // Compare the discriminant agains the valid_range.
+ let start_const = Operand::Constant(Box::new(ConstOperand {
+ span: source_info.span,
+ user_ty: None,
+ const_: Const::Val(ConstValue::from_u128(valid_range.start), tcx.types.u128),
+ }));
+ let end_start_diff_const = Operand::Constant(Box::new(ConstOperand {
+ span: source_info.span,
+ user_ty: None,
+ const_: Const::Val(
+ ConstValue::from_u128(u128::wrapping_sub(valid_range.end, valid_range.start)),
+ tcx.types.u128,
+ ),
+ }));
+
+ let discr_diff: Place<'_> =
+ local_decls.push(LocalDecl::with_source_info(tcx.types.u128, source_info)).into();
+ block_data.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Assign(Box::new((
+ discr_diff,
+ Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(discr), start_const))),
+ ))),
+ });
+
+ let is_ok: Place<'_> =
+ local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
+ block_data.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Assign(Box::new((
+ is_ok,
+ Rvalue::BinaryOp(
+ // This is a `WrappingRange`, so make sure to get the wrapping right.
+ BinOp::Le,
+ Box::new((Operand::Copy(discr_diff), end_start_diff_const)),
+ ),
+ ))),
+ });
+
+ block_data.terminator = Some(Terminator {
+ source_info,
+ kind: TerminatorKind::Assert {
+ cond: Operand::Copy(is_ok),
+ expected: true,
+ target: new_block,
+ msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr))),
+ // This calls panic_invalid_enum_construction, which is #[rustc_nounwind].
+ // We never want to insert an unwind into unsafe code, because unwinding could
+ // make a failing UB check turn into much worse UB when we start unwinding.
+ unwind: UnwindAction::Unreachable,
+ },
+ });
+}
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 0cf8142..fe53de3 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -16,7 +16,6 @@
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::lattice::{FlatSet, HasBottom};
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index bda71ce..b17b7f4 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -102,7 +102,7 @@
use rustc_middle::mir::interpret::GlobalAlloc;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
-use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
+use rustc_middle::ty::layout::HasTypingEnv;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_span::def_id::DefId;
@@ -1625,7 +1625,7 @@ fn op_to_prop_const<'tcx>(
// If this constant is already represented as an `Allocation`,
// try putting it into global memory to return it.
if let Either::Left(mplace) = op.as_mplace_or_imm() {
- let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_err()??;
+ let (size, _align) = ecx.size_and_align_of_val(&mplace).discard_err()??;
// Do not try interning a value that contains provenance.
// Due to https://github.com/rust-lang/rust/issues/79738, doing so could lead to bugs.
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f48dba9..c27087f 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -770,14 +770,15 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>(
return Ok(());
}
- if callee_def_id.is_local()
+ if let Some(callee_def_id) = callee_def_id.as_local()
&& !inliner
.tcx()
.is_lang_item(inliner.tcx().parent(caller_def_id), rustc_hir::LangItem::FnOnce)
{
// If we know for sure that the function we're calling will itself try to
// call us, then we avoid inlining that function.
- if inliner.tcx().mir_callgraph_reachable((callee, caller_def_id.expect_local())) {
+ if inliner.tcx().mir_callgraph_cyclic(caller_def_id.expect_local()).contains(&callee_def_id)
+ {
debug!("query cycle avoidance");
return Err("caller might be reachable from callee");
}
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index a944960..08f3ce5 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -1,5 +1,6 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_data_structures::unord::UnordSet;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::mir::TerminatorKind;
use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt, TypeVisitableExt};
@@ -7,137 +8,143 @@
use rustc_span::sym;
use tracing::{instrument, trace};
-// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
-// this query ridiculously often.
-#[instrument(level = "debug", skip(tcx, root, target))]
-pub(crate) fn mir_callgraph_reachable<'tcx>(
- tcx: TyCtxt<'tcx>,
- (root, target): (ty::Instance<'tcx>, LocalDefId),
-) -> bool {
- trace!(%root, target = %tcx.def_path_str(target));
- assert_ne!(
- root.def_id().expect_local(),
- target,
- "you should not call `mir_callgraph_reachable` on immediate self recursion"
- );
- assert!(
- matches!(root.def, InstanceKind::Item(_)),
- "you should not call `mir_callgraph_reachable` on shims"
- );
- assert!(
- !tcx.is_constructor(root.def_id()),
- "you should not call `mir_callgraph_reachable` on enum/struct constructor functions"
- );
- #[instrument(
- level = "debug",
- skip(tcx, typing_env, target, stack, seen, recursion_limiter, caller, recursion_limit)
- )]
- fn process<'tcx>(
- tcx: TyCtxt<'tcx>,
- typing_env: ty::TypingEnv<'tcx>,
- caller: ty::Instance<'tcx>,
- target: LocalDefId,
- stack: &mut Vec<ty::Instance<'tcx>>,
- seen: &mut FxHashSet<ty::Instance<'tcx>>,
- recursion_limiter: &mut FxHashMap<DefId, usize>,
- recursion_limit: Limit,
- ) -> bool {
- trace!(%caller);
- for &(callee, args) in tcx.mir_inliner_callees(caller.def) {
- let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions(
- tcx,
- typing_env,
- ty::EarlyBinder::bind(args),
- ) else {
- trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping");
- continue;
- };
- let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else {
- trace!(?callee, "cannot resolve, skipping");
- continue;
- };
-
- // Found a path.
- if callee.def_id() == target.to_def_id() {
- return true;
- }
-
- if tcx.is_constructor(callee.def_id()) {
- trace!("constructors always have MIR");
- // Constructor functions cannot cause a query cycle.
- continue;
- }
-
- match callee.def {
- InstanceKind::Item(_) => {
- // If there is no MIR available (either because it was not in metadata or
- // because it has no MIR because it's an extern function), then the inliner
- // won't cause cycles on this.
- if !tcx.is_mir_available(callee.def_id()) {
- trace!(?callee, "no mir available, skipping");
- continue;
- }
- }
- // These have no own callable MIR.
- InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => continue,
- // These have MIR and if that MIR is inlined, instantiated and then inlining is run
- // again, a function item can end up getting inlined. Thus we'll be able to cause
- // a cycle that way
- InstanceKind::VTableShim(_)
- | InstanceKind::ReifyShim(..)
- | InstanceKind::FnPtrShim(..)
- | InstanceKind::ClosureOnceShim { .. }
- | InstanceKind::ConstructCoroutineInClosureShim { .. }
- | InstanceKind::ThreadLocalShim { .. }
- | InstanceKind::CloneShim(..) => {}
-
- // This shim does not call any other functions, thus there can be no recursion.
- InstanceKind::FnPtrAddrShim(..) => {
- continue;
- }
- InstanceKind::DropGlue(..)
- | InstanceKind::FutureDropPollShim(..)
- | InstanceKind::AsyncDropGlue(..)
- | InstanceKind::AsyncDropGlueCtorShim(..) => {
- // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to
- // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
- // needs some more analysis.
- if callee.has_param() {
- continue;
- }
- }
- }
-
- if seen.insert(callee) {
- let recursion = recursion_limiter.entry(callee.def_id()).or_default();
- trace!(?callee, recursion = *recursion);
- if recursion_limit.value_within_limit(*recursion) {
- *recursion += 1;
- stack.push(callee);
- let found_recursion = ensure_sufficient_stack(|| {
- process(
- tcx,
- typing_env,
- callee,
- target,
- stack,
- seen,
- recursion_limiter,
- recursion_limit,
- )
- });
- if found_recursion {
- return true;
- }
- stack.pop();
- } else {
- // Pessimistically assume that there could be recursion.
- return true;
- }
+#[instrument(level = "debug", skip(tcx), ret)]
+fn should_recurse<'tcx>(tcx: TyCtxt<'tcx>, callee: ty::Instance<'tcx>) -> bool {
+ match callee.def {
+ // If there is no MIR available (either because it was not in metadata or
+ // because it has no MIR because it's an extern function), then the inliner
+ // won't cause cycles on this.
+ InstanceKind::Item(_) => {
+ if !tcx.is_mir_available(callee.def_id()) {
+ return false;
}
}
- false
+
+ // These have no own callable MIR.
+ InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => return false,
+
+ // These have MIR and if that MIR is inlined, instantiated and then inlining is run
+ // again, a function item can end up getting inlined. Thus we'll be able to cause
+ // a cycle that way
+ InstanceKind::VTableShim(_)
+ | InstanceKind::ReifyShim(..)
+ | InstanceKind::FnPtrShim(..)
+ | InstanceKind::ClosureOnceShim { .. }
+ | InstanceKind::ConstructCoroutineInClosureShim { .. }
+ | InstanceKind::ThreadLocalShim { .. }
+ | InstanceKind::CloneShim(..) => {}
+
+ // This shim does not call any other functions, thus there can be no recursion.
+ InstanceKind::FnPtrAddrShim(..) => return false,
+
+ // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to
+ // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
+ // needs some more analysis.
+ InstanceKind::DropGlue(..)
+ | InstanceKind::FutureDropPollShim(..)
+ | InstanceKind::AsyncDropGlue(..)
+ | InstanceKind::AsyncDropGlueCtorShim(..) => {
+ if callee.has_param() {
+ return false;
+ }
+ }
}
+
+ crate::pm::should_run_pass(tcx, &crate::inline::Inline, crate::pm::Optimizations::Allowed)
+ || crate::inline::ForceInline::should_run_pass_for_callee(tcx, callee.def.def_id())
+}
+
+#[instrument(
+ level = "debug",
+ skip(tcx, typing_env, seen, involved, recursion_limiter, recursion_limit),
+ ret
+)]
+fn process<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ typing_env: ty::TypingEnv<'tcx>,
+ caller: ty::Instance<'tcx>,
+ target: LocalDefId,
+ seen: &mut FxHashSet<ty::Instance<'tcx>>,
+ involved: &mut FxHashSet<LocalDefId>,
+ recursion_limiter: &mut FxHashMap<DefId, usize>,
+ recursion_limit: Limit,
+) -> bool {
+ trace!(%caller);
+ let mut cycle_found = false;
+
+ for &(callee, args) in tcx.mir_inliner_callees(caller.def) {
+ let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions(
+ tcx,
+ typing_env,
+ ty::EarlyBinder::bind(args),
+ ) else {
+ trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping");
+ continue;
+ };
+ let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else {
+ trace!(?callee, "cannot resolve, skipping");
+ continue;
+ };
+
+ // Found a path.
+ if callee.def_id() == target.to_def_id() {
+ cycle_found = true;
+ }
+
+ if tcx.is_constructor(callee.def_id()) {
+ trace!("constructors always have MIR");
+ // Constructor functions cannot cause a query cycle.
+ continue;
+ }
+
+ if !should_recurse(tcx, callee) {
+ continue;
+ }
+
+ if seen.insert(callee) {
+ let recursion = recursion_limiter.entry(callee.def_id()).or_default();
+ trace!(?callee, recursion = *recursion);
+ let found_recursion = if recursion_limit.value_within_limit(*recursion) {
+ *recursion += 1;
+ ensure_sufficient_stack(|| {
+ process(
+ tcx,
+ typing_env,
+ callee,
+ target,
+ seen,
+ involved,
+ recursion_limiter,
+ recursion_limit,
+ )
+ })
+ } else {
+ // Pessimistically assume that there could be recursion.
+ true
+ };
+ if found_recursion {
+ if let Some(callee) = callee.def_id().as_local() {
+ // Calling `optimized_mir` of a non-local definition cannot cycle.
+ involved.insert(callee);
+ }
+ cycle_found = true;
+ }
+ }
+ }
+
+ cycle_found
+}
+
+#[instrument(level = "debug", skip(tcx), ret)]
+pub(crate) fn mir_callgraph_cyclic<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ root: LocalDefId,
+) -> UnordSet<LocalDefId> {
+ assert!(
+ !tcx.is_constructor(root.to_def_id()),
+ "you should not call `mir_callgraph_reachable` on enum/struct constructor functions"
+ );
+
// FIXME(-Znext-solver=no): Remove this hack when trait solver overflow can return an error.
// In code like that pointed out in #128887, the type complexity we ask the solver to deal with
// grows as we recurse into the call graph. If we use the same recursion limit here and in the
@@ -146,16 +153,32 @@ fn process<'tcx>(
// the default recursion limits are quite generous for us. If we need to recurse 64 times
// into the call graph, we're probably not going to find any useful MIR inlining.
let recursion_limit = tcx.recursion_limit() / 2;
+ let mut involved = FxHashSet::default();
+ let typing_env = ty::TypingEnv::post_analysis(tcx, root);
+ let Ok(Some(root_instance)) = ty::Instance::try_resolve(
+ tcx,
+ typing_env,
+ root.to_def_id(),
+ ty::GenericArgs::identity_for_item(tcx, root.to_def_id()),
+ ) else {
+ trace!("cannot resolve, skipping");
+ return involved.into();
+ };
+ if !should_recurse(tcx, root_instance) {
+ trace!("cannot walk, skipping");
+ return involved.into();
+ }
process(
tcx,
- ty::TypingEnv::post_analysis(tcx, target),
+ typing_env,
+ root_instance,
root,
- target,
- &mut Vec::new(),
&mut FxHashSet::default(),
+ &mut involved,
&mut FxHashMap::default(),
recursion_limit,
- )
+ );
+ involved.into()
}
pub(crate) fn mir_inliner_callees<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index b45bff2..f9e642e 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -45,7 +45,6 @@
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ScalarInt, TyCtxt};
use rustc_mir_dataflow::lattice::HasBottom;
use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem};
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 572ad58..c441529 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -117,6 +117,7 @@ macro_rules! declare_passes {
mod check_inline : CheckForceInline;
mod check_call_recursion : CheckCallRecursion, CheckDropRecursion;
mod check_alignment : CheckAlignment;
+ mod check_enums : CheckEnums;
mod check_const_item_mutation : CheckConstItemMutation;
mod check_null : CheckNull;
mod check_packed_ref : CheckPackedRef;
@@ -215,7 +216,7 @@ pub fn provide(providers: &mut Providers) {
optimized_mir,
is_mir_available,
is_ctfe_mir_available: is_mir_available,
- mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
+ mir_callgraph_cyclic: inline::cycle::mir_callgraph_cyclic,
mir_inliner_callees: inline::cycle::mir_inliner_callees,
promoted_mir,
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
@@ -666,6 +667,7 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
// Add some UB checks before any UB gets optimized away.
&check_alignment::CheckAlignment,
&check_null::CheckNull,
+ &check_enums::CheckEnums,
// Before inlining: trim down MIR with passes to reduce inlining work.
// Has to be done before inlining, otherwise actual call will be almost always inlined.
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 38da5c3..798f4da 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -834,6 +834,9 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
mir::AssertKind::NullPointerDereference => {
push_mono_lang_item(self, LangItem::PanicNullPointerDereference);
}
+ mir::AssertKind::InvalidEnumConstruction(_) => {
+ push_mono_lang_item(self, LangItem::PanicInvalidEnumConstruction);
+ }
_ => {
push_mono_lang_item(self, msg.panic_function());
}
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 843ee80..73bb150 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -734,11 +734,11 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
let destruct_def_id = cx.require_lang_item(TraitSolverLangItem::Destruct);
match self_ty.kind() {
- // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it.
+ // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it.
ty::Adt(adt_def, _) if adt_def.is_manually_drop() => Ok(vec![]),
- // An ADT is `~const Destruct` only if all of the fields are,
- // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`.
+ // An ADT is `[const] Destruct` only if all of the fields are,
+ // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`.
ty::Adt(adt_def, args) => {
let mut const_conditions: Vec<_> = adt_def
.all_field_tys(cx)
@@ -746,9 +746,9 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
.map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty]))
.collect();
match adt_def.destructor(cx) {
- // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`.
+ // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`.
Some(AdtDestructorKind::NotConst) => return Err(NoSolution),
- // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold.
+ // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold.
Some(AdtDestructorKind::Const) => {
let drop_def_id = cx.require_lang_item(TraitSolverLangItem::Drop);
let drop_trait_ref = ty::TraitRef::new(cx, drop_def_id, [self_ty]);
@@ -769,7 +769,7 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
.map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty]))
.collect()),
- // Trivially implement `~const Destruct`
+ // Trivially implement `[const] Destruct`
ty::Bool
| ty::Char
| ty::Int(..)
@@ -784,14 +784,14 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
| ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
| ty::Error(_) => Ok(vec![]),
- // Coroutines and closures could implement `~const Drop`,
+ // Coroutines and closures could implement `[const] Drop`,
// but they don't really need to right now.
ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _) => Err(NoSolution),
- // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop`
+ // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
// if their inner type implements it.
ty::UnsafeBinder(_) => Err(NoSolution),
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index ca86b5a..42264f5 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -1,5 +1,5 @@
//! Dealing with host effect goals, i.e. enforcing the constness in
-//! `T: const Trait` or `T: ~const Trait`.
+//! `T: const Trait` or `T: [const] Trait`.
use rustc_type_ir::fast_reject::DeepRejectCtxt;
use rustc_type_ir::inherent::*;
@@ -70,7 +70,7 @@ fn match_assumption(
then(ecx)
}
- /// Register additional assumptions for aliases corresponding to `~const` item bounds.
+ /// Register additional assumptions for aliases corresponding to `[const]` item bounds.
///
/// Unlike item bounds, they are not simply implied by the well-formedness of the alias.
/// Instead, they only hold if the const conditons on the alias also hold. This is why
@@ -159,7 +159,7 @@ fn consider_impl_candidate(
.map(|pred| goal.with(cx, pred));
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
- // For this impl to be `const`, we need to check its `~const` bounds too.
+ // For this impl to be `const`, we need to check its `[const]` bounds too.
let const_conditions = cx
.const_conditions(impl_def_id)
.iter_instantiated(cx, impl_args)
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 4f845ef..e68ea22c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -191,6 +191,7 @@ fn compute_const_arg_has_type_goal(
goal: Goal<I, (I::Const, I::Ty)>,
) -> QueryResult<I> {
let (ct, ty) = goal.predicate;
+ let ct = self.structurally_normalize_const(goal.param_env, ct)?;
let ct_ty = match ct.kind() {
ty::ConstKind::Infer(_) => {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a64bb42..1df0ccb 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2731,7 +2731,7 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
return first_pat;
}
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
- || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ || !self.look_ahead(1, |token| token.is_non_reserved_ident())
{
let mut snapshot_type = self.create_snapshot_for_diagnostic();
snapshot_type.bump(); // `:`
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 4e312aa..3cedc86 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3875,8 +3875,7 @@ fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
// Check if a colon exists one ahead. This means we're parsing a fieldname.
let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
// Proactively check whether parsing the field will be incorrect.
- let is_wrong = this.token.is_ident()
- && !this.token.is_reserved_ident()
+ let is_wrong = this.token.is_non_reserved_ident()
&& !this.look_ahead(1, |t| {
t == &token::Colon
|| t == &token::Eq
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index c05479f..af1d1a1 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -353,6 +353,20 @@ fn parse_where_clause_common(
if !self.eat_keyword(exp!(Where)) {
return Ok((where_clause, None));
}
+
+ if self.eat_noexpect(&token::Colon) {
+ let colon_span = self.prev_token.span;
+ self.dcx()
+ .struct_span_err(colon_span, "unexpected colon after `where`")
+ .with_span_suggestion_short(
+ colon_span,
+ "remove the colon",
+ "",
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+
where_clause.has_where_token = true;
let where_lo = self.prev_token.span;
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 5088caa..9ed7124 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1552,7 +1552,8 @@ fn parse_item_enum(&mut self) -> PResult<'a, ItemKind> {
})
.map_err(|mut err| {
err.span_label(ident.span, "while parsing this enum");
- if self.token == token::Colon {
+ // Try to recover `enum Foo { ident : Ty }`.
+ if self.prev_token.is_non_reserved_ident() && self.token == token::Colon {
let snapshot = self.create_snapshot_for_diagnostic();
self.bump();
match self.parse_ty() {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index b2e9025..cfc0399 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -685,7 +685,7 @@ fn eat_metavar_seq_with_matcher<T>(
/// Is the given keyword `kw` followed by a non-reserved identifier?
fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
- self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
+ self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_non_reserved_ident())
}
#[inline]
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 9bce2fa..1f4049f 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -126,7 +126,7 @@ pub(super) fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (P<QSelf>,
/// ```
fn recover_colon_before_qpath_proj(&mut self) -> bool {
if !self.check_noexpect(&TokenKind::Colon)
- || self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident())
+ || self.look_ahead(1, |t| !t.is_non_reserved_ident())
{
return false;
}
@@ -260,7 +260,7 @@ pub(super) fn parse_path_segments(
if self.may_recover()
&& style == PathStyle::Expr // (!)
&& self.token == token::Colon
- && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ && self.look_ahead(1, |token| token.is_non_reserved_ident())
{
// Emit a special error message for `a::b:c` to help users
// otherwise, `a: c` might have meant to introduce a new binding
@@ -334,9 +334,7 @@ pub(super) fn parse_path_segment(
self.expect_gt().map_err(|mut err| {
// Try to recover a `:` into a `::`
if self.token == token::Colon
- && self.look_ahead(1, |token| {
- token.is_ident() && !token.is_reserved_ident()
- })
+ && self.look_ahead(1, |token| token.is_non_reserved_ident())
{
err.cancel();
err = self.dcx().create_err(PathSingleColon {
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index c37cb08..2fa6520 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -798,7 +798,7 @@ fn recover_missing_dot(&mut self, err: &mut Diag<'_>) {
}
if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) {
// Likely `foo.await bar`
- } else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() {
+ } else if self.prev_token.is_non_reserved_ident() {
// Likely `foo bar`
} else if self.prev_token.kind == token::Question {
// `foo? bar`
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 620a340..d874a07 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -885,6 +885,7 @@ fn can_begin_bound(&mut self) -> bool {
|| self.check(exp!(Tilde))
|| self.check_keyword(exp!(For))
|| self.check(exp!(OpenParen))
+ || self.check(exp!(OpenBracket))
|| self.check_keyword(exp!(Const))
|| self.check_keyword(exp!(Async))
|| self.check_keyword(exp!(Use))
@@ -982,12 +983,12 @@ fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
Ok(())
}
- /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `~const Trait`.
+ /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`.
///
/// If no modifiers are present, this does not consume any tokens.
///
/// ```ebnf
- /// CONSTNESS = [["~"] "const"]
+ /// CONSTNESS = [["["] "const" ["]"]]
/// ASYNCNESS = ["async"]
/// POLARITY = ["?" | "!"]
/// ```
@@ -995,18 +996,7 @@ fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
/// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers.
fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
let modifier_lo = self.token.span;
- let constness = if self.eat(exp!(Tilde)) {
- let tilde = self.prev_token.span;
- self.expect_keyword(exp!(Const))?;
- let span = tilde.to(self.prev_token.span);
- self.psess.gated_spans.gate(sym::const_trait_impl, span);
- BoundConstness::Maybe(span)
- } else if self.eat_keyword(exp!(Const)) {
- self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span);
- BoundConstness::Always(self.prev_token.span)
- } else {
- BoundConstness::Never
- };
+ let constness = self.parse_bound_constness()?;
let asyncness = if self.token_uninterpolated_span().at_least_rust_2018()
&& self.eat_keyword(exp!(Async))
@@ -1068,13 +1058,41 @@ fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
Ok(TraitBoundModifiers { constness, asyncness, polarity })
}
+ pub fn parse_bound_constness(&mut self) -> PResult<'a, BoundConstness> {
+ // FIXME(const_trait_impl): remove `~const` parser support once bootstrap has the new syntax
+ // in rustfmt
+ Ok(if self.eat(exp!(Tilde)) {
+ let tilde = self.prev_token.span;
+ self.expect_keyword(exp!(Const))?;
+ let span = tilde.to(self.prev_token.span);
+ self.psess.gated_spans.gate(sym::const_trait_impl, span);
+ BoundConstness::Maybe(span)
+ } else if self.check(exp!(OpenBracket))
+ && self.look_ahead(1, |t| t.is_keyword(kw::Const))
+ && self.look_ahead(2, |t| *t == token::CloseBracket)
+ {
+ let start = self.token.span;
+ self.bump();
+ self.expect_keyword(exp!(Const)).unwrap();
+ self.bump();
+ let span = start.to(self.prev_token.span);
+ self.psess.gated_spans.gate(sym::const_trait_impl, span);
+ BoundConstness::Maybe(span)
+ } else if self.eat_keyword(exp!(Const)) {
+ self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span);
+ BoundConstness::Always(self.prev_token.span)
+ } else {
+ BoundConstness::Never
+ })
+ }
+
/// Parses a type bound according to:
/// ```ebnf
/// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
/// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH
/// ```
///
- /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`.
+ /// For example, this grammar accepts `for<'a: 'b> [const] ?m::Trait<'a>`.
fn parse_generic_ty_bound(
&mut self,
lo: Span,
@@ -1101,7 +1119,7 @@ fn parse_generic_ty_bound(
}
// Recover erroneous lifetime bound with modifiers or binder.
- // e.g. `T: for<'a> 'a` or `T: ~const 'a`.
+ // e.g. `T: for<'a> 'a` or `T: [const] 'a`.
if self.token.is_lifetime() {
let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);
return self.parse_generic_lt_bound(lo, has_parens);
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 68d78af..8b1d864 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -302,6 +302,7 @@ fn emit_malformed_attribute(
| sym::no_mangle
| sym::must_use
| sym::track_caller
+ | sym::link_name
) {
return;
}
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index e2995da..b1c7b0f 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -816,9 +816,6 @@
.suggestion = if this is intentional, prefix it with an underscore
-passes_used_compiler_linker =
- `used(compiler)` and `used(linker)` can't be used together
-
passes_used_static =
attribute must be applied to a `static` variable
.label = but this is a {$target}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 491b369..ae486a5 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -191,6 +191,9 @@ fn check_attributes(
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
}
+ Attribute::Parsed(AttributeKind::LinkName { span: attr_span, name }) => {
+ self.check_link_name(hir_id, *attr_span, *name, span, target)
+ }
Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
self.check_may_dangle(hir_id, *attr_span)
}
@@ -200,6 +203,9 @@ fn check_attributes(
Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => {
self.check_no_mangle(hir_id, *attr_span, span, target)
}
+ Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => {
+ self.check_used(*attr_span, target, span);
+ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
match attr.path().as_slice() {
@@ -280,7 +286,6 @@ fn check_attributes(
[sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
[sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
[sym::link, ..] => self.check_link(hir_id, attr, span, target),
- [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
[sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
[sym::macro_use, ..] | [sym::macro_escape, ..] => {
self.check_macro_use(hir_id, attr, target)
@@ -333,7 +338,6 @@ fn check_attributes(
| sym::cfi_encoding // FIXME(cfi_encoding)
| sym::pointee // FIXME(derive_coerce_pointee)
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
- | sym::used // handled elsewhere to restrict to static items
| sym::instruction_set // broken on stable!!!
| sym::windows_subsystem // broken on stable!!!
| sym::patchable_function_entry // FIXME(patchable_function_entry)
@@ -403,7 +407,6 @@ fn check_attributes(
}
self.check_repr(attrs, span, target, item, hir_id);
- self.check_used(attrs, target, span);
self.check_rustc_force_inline(hir_id, attrs, span, target);
self.check_mix_no_mangle_export(hir_id, attrs);
}
@@ -1603,7 +1606,14 @@ fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target
}
/// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
- fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+ fn check_link_name(
+ &self,
+ hir_id: HirId,
+ attr_span: Span,
+ name: Symbol,
+ span: Span,
+ target: Target,
+ ) {
match target {
Target::ForeignFn | Target::ForeignStatic => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -1611,27 +1621,18 @@ fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: T
// erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
- self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name");
+ self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_name");
}
_ => {
- // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
+ // FIXME: #[link_name] was previously allowed on non-functions/statics and some crates
// used this, so only emit a warning.
- let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span());
- if let Some(s) = attr.value_str() {
- self.tcx.emit_node_span_lint(
- UNUSED_ATTRIBUTES,
- hir_id,
- attr.span(),
- errors::LinkName { span, attr_span, value: s.as_str() },
- );
- } else {
- self.tcx.emit_node_span_lint(
- UNUSED_ATTRIBUTES,
- hir_id,
- attr.span(),
- errors::LinkName { span, attr_span, value: "..." },
- );
- };
+ let help_span = matches!(target, Target::ForeignMod).then_some(attr_span);
+ self.tcx.emit_node_span_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr_span,
+ errors::LinkName { span, help_span, value: name.as_str() },
+ );
}
}
}
@@ -2107,44 +2108,13 @@ fn check_align_value(&self, align: Align, span: Span) {
}
}
- fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
- let mut used_linker_span = None;
- let mut used_compiler_span = None;
- for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
- if target != Target::Static {
- self.dcx().emit_err(errors::UsedStatic {
- attr_span: attr.span(),
- span: target_span,
- target: target.name(),
- });
- }
- let inner = attr.meta_item_list();
- match inner.as_deref() {
- Some([item]) if item.has_name(sym::linker) => {
- if used_linker_span.is_none() {
- used_linker_span = Some(attr.span());
- }
- }
- Some([item]) if item.has_name(sym::compiler) => {
- if used_compiler_span.is_none() {
- used_compiler_span = Some(attr.span());
- }
- }
- Some(_) => {
- // This error case is handled in rustc_hir_analysis::collect.
- }
- None => {
- // Default case (compiler) when arg isn't defined.
- if used_compiler_span.is_none() {
- used_compiler_span = Some(attr.span());
- }
- }
- }
- }
- if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
- self.tcx
- .dcx()
- .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
+ fn check_used(&self, attr_span: Span, target: Target, target_span: Span) {
+ if target != Target::Static {
+ self.dcx().emit_err(errors::UsedStatic {
+ attr_span,
+ span: target_span,
+ target: target.name(),
+ });
}
}
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 3286ccc..eaff1cc 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -502,7 +502,7 @@ pub(crate) struct Link {
#[warning]
pub(crate) struct LinkName<'a> {
#[help]
- pub attr_span: Option<Span>,
+ pub help_span: Option<Span>,
#[label]
pub span: Span,
pub value: &'a str,
@@ -642,13 +642,6 @@ pub(crate) struct UsedStatic {
}
#[derive(Diagnostic)]
-#[diag(passes_used_compiler_linker)]
-pub(crate) struct UsedCompilerLinker {
- #[primary_span]
- pub spans: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
#[diag(passes_allow_internal_unstable)]
pub(crate) struct AllowInternalUnstable {
#[primary_span]
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 8bca350..18078b7 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2421,6 +2421,8 @@ pub(crate) fn report_path_resolution_error(
} else {
let suggestion = if suggestion.is_some() {
suggestion
+ } else if let Some(m) = self.undeclared_module_exists(ident) {
+ self.undeclared_module_suggest_declare(ident, m)
} else if was_invoked_from_cargo() {
Some((
vec![],
@@ -2442,6 +2444,55 @@ pub(crate) fn report_path_resolution_error(
}
}
+ fn undeclared_module_suggest_declare(
+ &mut self,
+ ident: Ident,
+ path: std::path::PathBuf,
+ ) -> Option<(Vec<(Span, String)>, String, Applicability)> {
+ Some((
+ vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))],
+ format!(
+ "to make use of source file {}, use `mod {ident}` \
+ in this file to declare the module",
+ path.display()
+ ),
+ Applicability::MaybeIncorrect,
+ ))
+ }
+
+ fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> {
+ let map = self.tcx.sess.source_map();
+
+ let src = map.span_to_filename(ident.span).into_local_path()?;
+ let i = ident.as_str();
+ // FIXME: add case where non parent using undeclared module (hard?)
+ let dir = src.parent()?;
+ let src = src.file_stem()?.to_str()?;
+ for file in [
+ // …/x.rs
+ dir.join(i).with_extension("rs"),
+ // …/x/mod.rs
+ dir.join(i).join("mod.rs"),
+ ] {
+ if file.exists() {
+ return Some(file);
+ }
+ }
+ if !matches!(src, "main" | "lib" | "mod") {
+ for file in [
+ // …/x/y.rs
+ dir.join(src).join(i).with_extension("rs"),
+ // …/x/y/mod.rs
+ dir.join(src).join(i).join("mod.rs"),
+ ] {
+ if file.exists() {
+ return Some(file);
+ }
+ }
+ }
+ None
+ }
+
/// Adds suggestions for a path that cannot be resolved.
#[instrument(level = "debug", skip(self, parent_scope))]
pub(crate) fn make_path_suggestion(
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 1b7a2c3..2e81b54 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -174,7 +174,14 @@ pub(crate) struct ImportData<'ra> {
pub parent_scope: ParentScope<'ra>,
pub module_path: Vec<Segment>,
- /// The resolution of `module_path`.
+ /// The resolution of `module_path`:
+ ///
+ /// | `module_path` | `imported_module` | remark |
+ /// |-|-|-|
+ /// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - |
+ /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions |
+ /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition |
+ /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - |
pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
pub vis: ty::Visibility,
}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 42b3e59..85e71ed 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -506,6 +506,9 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
AssertKind::NullPointerDereference => {
stable_mir::mir::AssertMessage::NullPointerDereference
}
+ AssertKind::InvalidEnumConstruction(source) => {
+ stable_mir::mir::AssertMessage::InvalidEnumConstruction(source.stable(tables))
+ }
}
}
}
diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs
index 660cd7d..e4b7659 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/body.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs
@@ -270,6 +270,7 @@ pub enum AssertMessage {
ResumedAfterDrop(CoroutineKind),
MisalignedPointerDereference { required: Operand, found: Operand },
NullPointerDereference,
+ InvalidEnumConstruction(Operand),
}
impl AssertMessage {
@@ -342,6 +343,9 @@ pub fn description(&self) -> Result<&'static str, Error> {
Ok("misaligned pointer dereference")
}
AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"),
+ AssertMessage::InvalidEnumConstruction(_) => {
+ Ok("trying to construct an enum from an invalid value")
+ }
}
}
}
diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
index ba20651..b068a9a 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
@@ -313,6 +313,10 @@ fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::R
AssertMessage::NullPointerDereference => {
write!(writer, "\"null pointer dereference occurred\"")
}
+ AssertMessage::InvalidEnumConstruction(op) => {
+ let pretty_op = pretty_operand(op);
+ write!(writer, "\"trying to construct an enum from an invalid value {{}}\",{pretty_op}")
+ }
AssertMessage::ResumedAfterReturn(_)
| AssertMessage::ResumedAfterPanic(_)
| AssertMessage::ResumedAfterDrop(_) => {
diff --git a/compiler/rustc_smir/src/stable_mir/mir/visit.rs b/compiler/rustc_smir/src/stable_mir/mir/visit.rs
index e21dc11..b7dd433 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/visit.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/visit.rs
@@ -367,7 +367,8 @@ fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Lo
}
AssertMessage::OverflowNeg(op)
| AssertMessage::DivisionByZero(op)
- | AssertMessage::RemainderByZero(op) => {
+ | AssertMessage::RemainderByZero(op)
+ | AssertMessage::InvalidEnumConstruction(op) => {
self.visit_operand(op, location);
}
AssertMessage::ResumedAfterReturn(_)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 368944f..4b8762d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -150,14 +150,10 @@
// As well as the symbols listed, there are symbols for the strings
// "0", "1", ..., "9", which are accessible via `sym::integer`.
//
- // The proc macro will abort if symbols are not in alphabetical order (as
- // defined by `impl Ord for str`) or if any symbols are duplicated. Vim
- // users can sort the list by selecting it and executing the command
- // `:'<,'>!LC_ALL=C sort`.
- //
// There is currently no checking that all symbols are used; that would be
// nice to have.
Symbols {
+ // tidy-alphabetical-start
Abi,
AcqRel,
Acquire,
@@ -175,18 +171,18 @@
AsyncGenPending,
AsyncGenReady,
AtomicBool,
- AtomicI128,
+ AtomicI8,
AtomicI16,
AtomicI32,
AtomicI64,
- AtomicI8,
+ AtomicI128,
AtomicIsize,
AtomicPtr,
- AtomicU128,
+ AtomicU8,
AtomicU16,
AtomicU32,
AtomicU64,
- AtomicU8,
+ AtomicU128,
AtomicUsize,
BTreeEntry,
BTreeMap,
@@ -607,10 +603,10 @@
catch_unwind,
cause,
cdylib,
- ceilf128,
ceilf16,
ceilf32,
ceilf64,
+ ceilf128,
cfg,
cfg_accessible,
cfg_attr,
@@ -747,10 +743,10 @@
copy,
copy_closures,
copy_nonoverlapping,
- copysignf128,
copysignf16,
copysignf32,
copysignf64,
+ copysignf128,
core,
core_panic,
core_panic_2015_macro,
@@ -763,10 +759,10 @@
coroutine_state,
coroutine_yield,
coroutines,
- cosf128,
cosf16,
cosf32,
cosf64,
+ cosf128,
count,
coverage,
coverage_attribute,
@@ -874,8 +870,8 @@
dotdot_in_tuple_patterns,
dotdoteq_in_patterns,
dreg,
- dreg_low16,
dreg_low8,
+ dreg_low16,
drop,
drop_in_place,
drop_types_in_const,
@@ -928,16 +924,16 @@
exhaustive_integer_patterns,
exhaustive_patterns,
existential_type,
- exp2f128,
exp2f16,
exp2f32,
exp2f64,
+ exp2f128,
expect,
expected,
- expf128,
expf16,
expf32,
expf64,
+ expf128,
explicit_extern_abis,
explicit_generic_args_with_impl_trait,
explicit_tail_calls,
@@ -958,9 +954,6 @@
external,
external_doc,
f,
- f128,
- f128_epsilon,
- f128_nan,
f16,
f16_epsilon,
f16_nan,
@@ -999,10 +992,13 @@
f64_legacy_const_neg_infinity,
f64_legacy_const_radix,
f64_nan,
- fabsf128,
+ f128,
+ f128_epsilon,
+ f128_nan,
fabsf16,
fabsf32,
fabsf64,
+ fabsf128,
fadd_algebraic,
fadd_fast,
fake_variadic,
@@ -1024,22 +1020,22 @@
flags,
float,
float_to_int_unchecked,
- floorf128,
floorf16,
floorf32,
floorf64,
- fmaf128,
+ floorf128,
fmaf16,
fmaf32,
fmaf64,
+ fmaf128,
fmt,
fmt_debug,
fmul_algebraic,
fmul_fast,
- fmuladdf128,
fmuladdf16,
fmuladdf32,
fmuladdf64,
+ fmuladdf128,
fn_align,
fn_body,
fn_delegation,
@@ -1140,13 +1136,12 @@
html_root_url,
hwaddress,
i,
- i128,
- i128_legacy_const_max,
- i128_legacy_const_min,
- i128_legacy_fn_max_value,
- i128_legacy_fn_min_value,
- i128_legacy_mod,
- i128_type,
+ i8,
+ i8_legacy_const_max,
+ i8_legacy_const_min,
+ i8_legacy_fn_max_value,
+ i8_legacy_fn_min_value,
+ i8_legacy_mod,
i16,
i16_legacy_const_max,
i16_legacy_const_min,
@@ -1165,12 +1160,13 @@
i64_legacy_fn_max_value,
i64_legacy_fn_min_value,
i64_legacy_mod,
- i8,
- i8_legacy_const_max,
- i8_legacy_const_min,
- i8_legacy_fn_max_value,
- i8_legacy_fn_min_value,
- i8_legacy_mod,
+ i128,
+ i128_legacy_const_max,
+ i128_legacy_const_min,
+ i128_legacy_fn_max_value,
+ i128_legacy_fn_min_value,
+ i128_legacy_mod,
+ i128_type,
ident,
if_let,
if_let_guard,
@@ -1292,19 +1288,19 @@
loaded_from_disk,
local,
local_inner_macros,
- log10f128,
- log10f16,
- log10f32,
- log10f64,
- log2f128,
log2f16,
log2f32,
log2f64,
+ log2f128,
+ log10f16,
+ log10f32,
+ log10f64,
+ log10f128,
log_syntax,
- logf128,
logf16,
logf32,
logf64,
+ logf128,
loongarch_target_feature,
loop_break_value,
loop_match,
@@ -1334,14 +1330,14 @@
match_beginning_vert,
match_default_bindings,
matches_macro,
- maximumf128,
maximumf16,
maximumf32,
maximumf64,
- maxnumf128,
+ maximumf128,
maxnumf16,
maxnumf32,
maxnumf64,
+ maxnumf128,
may_dangle,
may_unwind,
maybe_uninit,
@@ -1372,14 +1368,14 @@
min_generic_const_args,
min_specialization,
min_type_alias_impl_trait,
- minimumf128,
minimumf16,
minimumf32,
minimumf64,
- minnumf128,
+ minimumf128,
minnumf16,
minnumf32,
minnumf64,
+ minnumf128,
mips_target_feature,
mir_assume,
mir_basic_block,
@@ -1586,6 +1582,7 @@
panic_implementation,
panic_in_cleanup,
panic_info,
+ panic_invalid_enum_construction,
panic_location,
panic_misaligned_pointer_dereference,
panic_nounwind,
@@ -1633,14 +1630,14 @@
post_dash_lto: "post-lto",
postfix_match,
powerpc_target_feature,
- powf128,
powf16,
powf32,
powf64,
- powif128,
+ powf128,
powif16,
powif32,
powif64,
+ powif128,
pre_dash_lto: "pre-lto",
precise_capturing,
precise_capturing_in_traits,
@@ -1785,14 +1782,14 @@
ropi_rwpi: "ropi-rwpi",
rotate_left,
rotate_right,
- round_ties_even_f128,
round_ties_even_f16,
round_ties_even_f32,
round_ties_even_f64,
- roundf128,
+ round_ties_even_f128,
roundf16,
roundf32,
roundf64,
+ roundf128,
rt,
rtm_target_feature,
rust,
@@ -1876,6 +1873,7 @@
rustc_never_returns_null_ptr,
rustc_never_type_options,
rustc_no_implicit_autorefs,
+ rustc_no_implicit_bounds,
rustc_no_mir_inline,
rustc_nonnull_optimization_guaranteed,
rustc_nounwind,
@@ -1971,14 +1969,16 @@
simd_fexp2,
simd_ffi,
simd_flog,
- simd_flog10,
simd_flog2,
+ simd_flog10,
simd_floor,
simd_fma,
simd_fmax,
simd_fmin,
simd_fsin,
simd_fsqrt,
+ simd_funnel_shl,
+ simd_funnel_shr,
simd_gather,
simd_ge,
simd_gt,
@@ -2006,6 +2006,7 @@
simd_relaxed_fma,
simd_rem,
simd_round,
+ simd_round_ties_even,
simd_saturating_add,
simd_saturating_sub,
simd_scatter,
@@ -2020,10 +2021,10 @@
simd_with_exposed_provenance,
simd_xor,
since,
- sinf128,
sinf16,
sinf32,
sinf64,
+ sinf128,
size,
size_of,
size_of_val,
@@ -2045,10 +2046,10 @@
specialization,
speed,
spotlight,
- sqrtf128,
sqrtf16,
sqrtf32,
sqrtf64,
+ sqrtf128,
sreg,
sreg_low16,
sse,
@@ -2126,10 +2127,10 @@
target_has_atomic,
target_has_atomic_equal_alignment,
target_has_atomic_load_store,
- target_has_reliable_f128,
- target_has_reliable_f128_math,
target_has_reliable_f16,
target_has_reliable_f16_math,
+ target_has_reliable_f128,
+ target_has_reliable_f128_math,
target_os,
target_pointer_width,
target_thread_local,
@@ -2172,10 +2173,10 @@
transparent_enums,
transparent_unions,
trivial_bounds,
- truncf128,
truncf16,
truncf32,
truncf64,
+ truncf128,
try_blocks,
try_capture,
try_from,
@@ -2204,12 +2205,12 @@
type_name,
type_privacy_lints,
typed_swap_nonoverlapping,
- u128,
- u128_legacy_const_max,
- u128_legacy_const_min,
- u128_legacy_fn_max_value,
- u128_legacy_fn_min_value,
- u128_legacy_mod,
+ u8,
+ u8_legacy_const_max,
+ u8_legacy_const_min,
+ u8_legacy_fn_max_value,
+ u8_legacy_fn_min_value,
+ u8_legacy_mod,
u16,
u16_legacy_const_max,
u16_legacy_const_min,
@@ -2228,12 +2229,12 @@
u64_legacy_fn_max_value,
u64_legacy_fn_min_value,
u64_legacy_mod,
- u8,
- u8_legacy_const_max,
- u8_legacy_const_min,
- u8_legacy_fn_max_value,
- u8_legacy_fn_min_value,
- u8_legacy_mod,
+ u128,
+ u128_legacy_const_max,
+ u128_legacy_const_min,
+ u128_legacy_fn_max_value,
+ u128_legacy_fn_min_value,
+ u128_legacy_mod,
ub_checks,
unaligned_volatile_load,
unaligned_volatile_store,
@@ -2386,6 +2387,7 @@
zfh,
zfhmin,
zmm_reg,
+ // tidy-alphabetical-end
}
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 65e3155..02edf48 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -775,7 +775,7 @@ fn report_host_effect_error(
param_env: ty::ParamEnv<'tcx>,
span: Span,
) -> Diag<'a> {
- // FIXME(const_trait_impl): We should recompute the predicate with `~const`
+ // FIXME(const_trait_impl): We should recompute the predicate with `[const]`
// if it's `const`, and if it holds, explain that this bound only
// *conditionally* holds. If that fails, we should also do selection
// to drill this down to an impl or built-in source, so we can
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 89dab90..a52dbed 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -334,7 +334,7 @@ pub struct OnUnimplementedNote {
pub append_const_msg: Option<AppendConstMessage>,
}
-/// Append a message for `~const Trait` errors.
+/// Append a message for `[const] Trait` errors.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum AppendConstMessage {
#[default]
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index bdfe48a..8d049fe 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -593,7 +593,7 @@ fn receiver_is_dispatchable<'tcx>(
// will cause ambiguity that the user can't really avoid.
//
// We leave out certain complexities of the param-env query here. Specifically, we:
- // 1. Do not add `~const` bounds since there are no `dyn const Trait`s.
+ // 1. Do not add `[const]` bounds since there are no `dyn const Trait`s.
// 2. Do not add RPITIT self projection bounds for defaulted methods, since we
// are not constructing a param-env for "inside" of the body of the defaulted
// method, so we don't really care about projecting to a specific RPIT type,
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index e77d9e3..fc95e42 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -252,20 +252,20 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
let self_ty = obligation.predicate.self_ty();
let const_conditions = match *self_ty.kind() {
- // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it.
+ // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it.
ty::Adt(adt_def, _) if adt_def.is_manually_drop() => thin_vec![],
- // An ADT is `~const Destruct` only if all of the fields are,
- // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`.
+ // An ADT is `[const] Destruct` only if all of the fields are,
+ // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`.
ty::Adt(adt_def, args) => {
let mut const_conditions: ThinVec<_> = adt_def
.all_fields()
.map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)]))
.collect();
match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) {
- // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`.
+ // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`.
Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution),
- // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold.
+ // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold.
Some(hir::Constness::Const) => {
let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span);
let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]);
@@ -285,7 +285,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect()
}
- // Trivially implement `~const Destruct`
+ // Trivially implement `[const] Destruct`
ty::Bool
| ty::Char
| ty::Int(..)
@@ -300,14 +300,14 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
| ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
| ty::Error(_) => thin_vec![],
- // Coroutines and closures could implement `~const Drop`,
+ // Coroutines and closures could implement `[const] Drop`,
// but they don't really need to right now.
ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution),
- // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop`
+ // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
// if their inner type implements it.
ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution),
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index b30fadd..4bb1269 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -233,7 +233,7 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool
///
/// For the purposes of const traits, we also check that the specializing
/// impl is not more restrictive than the parent impl. That is, if the
-/// `parent_impl_def_id` is a const impl (conditionally based off of some `~const`
+/// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]`
/// bounds), then `specializing_impl_def_id` must also be const for the same
/// set of types.
#[instrument(skip(tcx), level = "debug")]
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 372b4f5..150f5d1 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -432,7 +432,9 @@ fn from_enum(
if variant_layout.is_uninhabited() {
return Ok(Self::uninhabited());
}
- let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index));
+ let tag = cx.tcx().tag_for_variant(
+ cx.typing_env.as_query_input((cx.tcx().erase_regions(ty), index)),
+ );
let variant_def = Def::Variant(def.variant(index));
Self::from_variant(
variant_def,
diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs
index c929de1..4b65c05 100644
--- a/compiler/rustc_ty_utils/src/layout/invariant.rs
+++ b/compiler/rustc_ty_utils/src/layout/invariant.rs
@@ -277,6 +277,12 @@ fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
if !variant.is_uninhabited() {
assert!(idx == *untagged_variant || niche_variants.contains(&idx));
}
+
+ // Ensure that for niche encoded tags the discriminant coincides with the variant index.
+ assert_eq!(
+ layout.ty.discriminant_for_variant(tcx, idx).unwrap().val,
+ u128::from(idx.as_u32()),
+ );
}
}
for variant in variants.iter() {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index d996ee2..553f5e0 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -175,7 +175,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
}
// We extend the param-env of our item with the const conditions of the item,
- // since we're allowed to assume `~const` bounds hold within the item itself.
+ // since we're allowed to assume `[const]` bounds hold within the item itself.
if tcx.is_conditionally_const(def_id) {
predicates.extend(
tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map(
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 927a2ce..a7b915c 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -622,6 +622,17 @@ pub fn instantiate<A>(self, cx: I, args: A) -> T
where
A: SliceLike<Item = I::GenericArg>,
{
+ // Nothing to fold, so let's avoid visiting things and possibly re-hashing/equating
+ // them when interning. Perf testing found this to be a modest improvement.
+ // See: <https://github.com/rust-lang/rust/pull/142317>
+ if args.is_empty() {
+ assert!(
+ !self.value.has_param(),
+ "{:?} has parameters, but no args were provided in instantiate",
+ self.value,
+ );
+ return self.value;
+ }
let mut folder = ArgFolder { cx, args: args.as_slice(), binders_passed: 0 };
self.value.fold_with(&mut folder)
}
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index b1768b3..7ffcf7b 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -179,7 +179,7 @@ fn elaborate(&mut self, elaboratable: &O) {
),
};
}
- // `T: ~const Trait` implies `T: ~const Supertrait`.
+ // `T: [const] Trait` implies `T: [const] Supertrait`.
ty::ClauseKind::HostEffect(data) => self.extend_deduped(
cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
elaboratable.child(
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 2bc12d0..8ba9e71 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -117,12 +117,20 @@ pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
}
pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
- TypingMode::Borrowck { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
+ let defining_opaque_types = cx.opaque_types_defined_by(body_def_id);
+ if defining_opaque_types.is_empty() {
+ TypingMode::non_body_analysis()
+ } else {
+ TypingMode::Borrowck { defining_opaque_types }
+ }
}
pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
- TypingMode::PostBorrowckAnalysis {
- defined_opaque_types: cx.opaque_types_defined_by(body_def_id),
+ let defined_opaque_types = cx.opaque_types_defined_by(body_def_id);
+ if defined_opaque_types.is_empty() {
+ TypingMode::non_body_analysis()
+ } else {
+ TypingMode::PostBorrowckAnalysis { defined_opaque_types }
}
}
}
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index f02d9c9..4643cd0 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -911,7 +911,7 @@ pub enum BoundConstness {
///
/// A bound is required to be unconditionally const, even in a runtime function.
Const,
- /// `Type: ~const Trait`
+ /// `Type: [const] Trait`
///
/// Requires resolving to const only when we are in a const context.
Maybe,
@@ -929,7 +929,7 @@ pub fn satisfies(self, goal: BoundConstness) -> bool {
pub fn as_str(self) -> &'static str {
match self {
Self::Const => "const",
- Self::Maybe => "~const",
+ Self::Maybe => "[const]",
}
}
}
@@ -938,7 +938,7 @@ impl fmt::Display for BoundConstness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Const => f.write_str("const"),
- Self::Maybe => f.write_str("~const"),
+ Self::Maybe => f.write_str("[const]"),
}
}
}
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index bbbeaa2..a6571ef 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -79,7 +79,7 @@ pub enum GoalSource {
TypeRelating,
/// We're proving a where-bound of an impl.
ImplWhereBound,
- /// Const conditions that need to hold for `~const` alias bounds to hold.
+ /// Const conditions that need to hold for `[const]` alias bounds to hold.
AliasBoundConstCondition,
/// Instantiating a higher-ranked goal and re-proving it.
InstantiateHigherRanked,
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index aa9e5fc..d50ce02 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -1517,9 +1517,7 @@ fn from_sorted_iter<I: Iterator<Item = T>>(iter: I, alloc: A) -> BTreeSet<T, A>
// use stable sort to preserve the insertion order.
arr.sort();
- let iter = IntoIterator::into_iter(arr).map(|k| (k, SetValZST::default()));
- let map = BTreeMap::bulk_build_from_sorted_iter(iter, Global);
- BTreeSet { map }
+ BTreeSet::from_sorted_iter(IntoIterator::into_iter(arr), Global)
}
}
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 40efc26..11533ab 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -126,6 +126,40 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
#[rustc_nounwind]
pub unsafe fn simd_shr<T>(lhs: T, rhs: T) -> T;
+/// Funnel Shifts vector left elementwise, with UB on overflow.
+///
+/// Concatenates `a` and `b` elementwise (with `a` in the most significant half),
+/// creating a vector of the same length, but with each element being twice as
+/// wide. Then shift this vector left elementwise by `shift`, shifting in zeros,
+/// and extract the most significant half of each of the elements. If `a` and `b`
+/// are the same, this is equivalent to an elementwise rotate left operation.
+///
+/// `T` must be a vector of integers.
+///
+/// # Safety
+///
+/// Each element of `shift` must be less than `<int>::BITS`.
+#[rustc_intrinsic]
+#[rustc_nounwind]
+pub unsafe fn simd_funnel_shl<T>(a: T, b: T, shift: T) -> T;
+
+/// Funnel Shifts vector right elementwise, with UB on overflow.
+///
+/// Concatenates `a` and `b` elementwise (with `a` in the most significant half),
+/// creating a vector of the same length, but with each element being twice as
+/// wide. Then shift this vector right elementwise by `shift`, shifting in zeros,
+/// and extract the least significant half of each of the elements. If `a` and `b`
+/// are the same, this is equivalent to an elementwise rotate right operation.
+///
+/// `T` must be a vector of integers.
+///
+/// # Safety
+///
+/// Each element of `shift` must be less than `<int>::BITS`.
+#[rustc_intrinsic]
+#[rustc_nounwind]
+pub unsafe fn simd_funnel_shr<T>(a: T, b: T, shift: T) -> T;
+
/// "Ands" vectors elementwise.
///
/// `T` must be a vector of integers.
@@ -678,6 +712,14 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
#[rustc_nounwind]
pub unsafe fn simd_round<T>(x: T) -> T;
+/// Rounds each element to the closest integer-valued float.
+/// Ties are resolved by rounding to the number with an even least significant digit
+///
+/// `T` must be a vector of floats.
+#[rustc_intrinsic]
+#[rustc_nounwind]
+pub unsafe fn simd_round_ties_even<T>(x: T) -> T;
+
/// Returns the integer part of each element as an integer-valued float.
/// In other words, non-integer values are truncated towards zero.
///
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs
index f1eeded..9722702 100644
--- a/library/core/src/panic/location.rs
+++ b/library/core/src/panic/location.rs
@@ -1,5 +1,7 @@
use crate::ffi::CStr;
use crate::fmt;
+use crate::marker::PhantomData;
+use crate::ptr::NonNull;
/// A struct containing information about the location of a panic.
///
@@ -33,14 +35,13 @@
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
- // Note: this filename will have exactly one nul byte at its end, but otherwise
- // it must never contain interior nul bytes. This is relied on for the conversion
- // to `CStr` below.
- //
- // The prefix of the string without the trailing nul byte will be a regular UTF8 `str`.
- file_bytes_with_nul: &'a [u8],
+ // A raw pointer is used rather than a reference because the pointer is valid for one more byte
+ // than the length stored in this pointer; the additional byte is the NUL-terminator used by
+ // `Location::file_with_nul`.
+ filename: NonNull<str>,
line: u32,
col: u32,
+ _filename: PhantomData<&'a str>,
}
#[stable(feature = "panic_hooks", since = "1.10.0")]
@@ -143,10 +144,8 @@ pub const fn caller() -> &'static Location<'static> {
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")]
pub const fn file(&self) -> &str {
- let str_len = self.file_bytes_with_nul.len() - 1;
- // SAFETY: `file_bytes_with_nul` without the trailing nul byte is guaranteed to be
- // valid UTF8.
- unsafe { crate::str::from_raw_parts(self.file_bytes_with_nul.as_ptr(), str_len) }
+ // SAFETY: The filename is valid.
+ unsafe { self.filename.as_ref() }
}
/// Returns the name of the source file as a nul-terminated `CStr`.
@@ -157,9 +156,17 @@ pub const fn file(&self) -> &str {
#[unstable(feature = "file_with_nul", issue = "141727")]
#[inline]
pub const fn file_with_nul(&self) -> &CStr {
- // SAFETY: `file_bytes_with_nul` is guaranteed to have a trailing nul byte and no
- // interior nul bytes.
- unsafe { CStr::from_bytes_with_nul_unchecked(self.file_bytes_with_nul) }
+ let filename = self.filename.as_ptr();
+
+ // SAFETY: The filename is valid for `filename_len+1` bytes, so this addition can't
+ // overflow.
+ let cstr_len = unsafe { crate::mem::size_of_val_raw(filename).unchecked_add(1) };
+
+ // SAFETY: The filename is valid for `filename_len+1` bytes.
+ let slice = unsafe { crate::slice::from_raw_parts(filename.cast(), cstr_len) };
+
+ // SAFETY: The filename is guaranteed to have a trailing nul byte and no interior nul bytes.
+ unsafe { CStr::from_bytes_with_nul_unchecked(slice) }
}
/// Returns the line number from which the panic originated.
@@ -220,3 +227,8 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}:{}:{}", self.file(), self.line, self.col)
}
}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+unsafe impl Send for Location<'_> {}
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+unsafe impl Sync for Location<'_> {}
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index d87f481..812bc5e 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -314,6 +314,22 @@ fn panic_null_pointer_dereference() -> ! {
)
}
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[track_caller]
+#[lang = "panic_invalid_enum_construction"] // needed by codegen for panic on invalid enum construction.
+#[rustc_nounwind] // `CheckEnums` MIR pass requires this function to never unwind
+fn panic_invalid_enum_construction(source: u128) -> ! {
+ if cfg!(feature = "panic_immediate_abort") {
+ super::intrinsics::abort()
+ }
+
+ panic_nounwind_fmt(
+ format_args!("trying to construct an enum from an invalid value {source:#x}"),
+ /* force_no_backtrace */ false,
+ )
+}
+
/// Panics because we cannot unwind out of a function.
///
/// This is a separate function to avoid the codesize impact of each crate containing the string to
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index ae71079..7c2a43e 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -93,7 +93,7 @@
'miniz_oxide/rustc-dep-of-std',
]
-panic-unwind = ["panic_unwind"]
+panic-unwind = ["dep:panic_unwind"]
compiler-builtins-c = ["alloc/compiler-builtins-c"]
compiler-builtins-mem = ["alloc/compiler-builtins-mem"]
compiler-builtins-no-asm = ["alloc/compiler-builtins-no-asm"]
diff --git a/library/std/src/os/illumos/mod.rs b/library/std/src/os/illumos/mod.rs
index e61926f..5fbe352 100644
--- a/library/std/src/os/illumos/mod.rs
+++ b/library/std/src/os/illumos/mod.rs
@@ -3,4 +3,5 @@
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod fs;
+pub mod net;
pub mod raw;
diff --git a/library/std/src/os/illumos/net.rs b/library/std/src/os/illumos/net.rs
new file mode 100644
index 0000000..5ef4e1e
--- /dev/null
+++ b/library/std/src/os/illumos/net.rs
@@ -0,0 +1,50 @@
+//! illumos-specific networking functionality.
+
+#![unstable(feature = "unix_socket_exclbind", issue = "123481")]
+
+use crate::io;
+use crate::os::unix::net;
+use crate::sealed::Sealed;
+use crate::sys_common::AsInner;
+
+/// illumos-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
+/// and [`UnixStream`].
+///
+/// [`UnixDatagram`]: net::UnixDatagram
+/// [`UnixStream`]: net::UnixStream
+#[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+pub trait UnixSocketExt: Sealed {
+ /// Enables exclusive binding on the socket.
+ ///
+ /// If true and if the socket had been set with `SO_REUSEADDR`,
+ /// it neutralises its effect.
+ /// See [`man 3 tcp`](https://docs.oracle.com/cd/E88353_01/html/E37843/setsockopt-3c.html)
+ #[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+ fn so_exclbind(&self, excl: bool) -> io::Result<()>;
+
+ /// Get the bind exclusivity bind state of the socket.
+ #[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+ fn exclbind(&self) -> io::Result<bool>;
+}
+
+#[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+impl UnixSocketExt for net::UnixDatagram {
+ fn exclbind(&self) -> io::Result<bool> {
+ self.as_inner().exclbind()
+ }
+
+ fn so_exclbind(&self, excl: bool) -> io::Result<()> {
+ self.as_inner().set_exclbind(excl)
+ }
+}
+
+#[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+impl UnixSocketExt for net::UnixStream {
+ fn exclbind(&self) -> io::Result<bool> {
+ self.as_inner().exclbind()
+ }
+
+ fn so_exclbind(&self, excl: bool) -> io::Result<()> {
+ self.as_inner().set_exclbind(excl)
+ }
+}
diff --git a/library/std/src/os/solaris/mod.rs b/library/std/src/os/solaris/mod.rs
index e4cfd53..b4e8362 100644
--- a/library/std/src/os/solaris/mod.rs
+++ b/library/std/src/os/solaris/mod.rs
@@ -3,4 +3,5 @@
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod fs;
+pub mod net;
pub mod raw;
diff --git a/library/std/src/os/solaris/net.rs b/library/std/src/os/solaris/net.rs
new file mode 100644
index 0000000..ca841f1
--- /dev/null
+++ b/library/std/src/os/solaris/net.rs
@@ -0,0 +1,50 @@
+//! solaris-specific networking functionality.
+
+#![unstable(feature = "unix_socket_exclbind", issue = "123481")]
+
+use crate::io;
+use crate::os::unix::net;
+use crate::sealed::Sealed;
+use crate::sys_common::AsInner;
+
+/// solaris-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
+/// and [`UnixStream`].
+///
+/// [`UnixDatagram`]: net::UnixDatagram
+/// [`UnixStream`]: net::UnixStream
+#[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+pub trait UnixSocketExt: Sealed {
+ /// Enables exclusive binding on the socket.
+ ///
+ /// If true and if the socket had been set with `SO_REUSEADDR`,
+ /// it neutralises its effect.
+ /// See [`man 3 tcp`](https://docs.oracle.com/cd/E88353_01/html/E37843/setsockopt-3c.html)
+ #[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+ fn so_exclbind(&self, excl: bool) -> io::Result<()>;
+
+ /// Get the bind exclusivity bind state of the socket.
+ #[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+ fn exclbind(&self) -> io::Result<bool>;
+}
+
+#[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+impl UnixSocketExt for net::UnixDatagram {
+ fn exclbind(&self) -> io::Result<bool> {
+ self.as_inner().exclbind()
+ }
+
+ fn so_exclbind(&self, excl: bool) -> io::Result<()> {
+ self.as_inner().set_exclbind(excl)
+ }
+}
+
+#[unstable(feature = "unix_socket_exclbind", issue = "123481")]
+impl UnixSocketExt for net::UnixStream {
+ fn exclbind(&self) -> io::Result<bool> {
+ self.as_inner().exclbind()
+ }
+
+ fn so_exclbind(&self, excl: bool) -> io::Result<()> {
+ self.as_inner().set_exclbind(excl)
+ }
+}
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 4f9259f..b776df3 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -408,24 +408,22 @@ pub trait OpenOptionsExt {
/// Pass custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
- /// ensure they do not interfere with the access mode set by Rusts options.
+ /// ensure they do not interfere with the access mode set by Rust's options.
///
- /// Custom flags can only set flags, not remove flags set by Rusts options.
- /// This options overwrites any previously set custom flags.
+ /// Custom flags can only set flags, not remove flags set by Rust's options.
+ /// This function overwrites any previously-set custom flags.
///
/// # Examples
///
/// ```no_run
- /// # #![feature(rustc_private)]
+ /// # mod libc { pub const O_NOFOLLOW: i32 = 0; }
/// use std::fs::OpenOptions;
/// use std::os::unix::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.write(true);
- /// if cfg!(unix) {
- /// options.custom_flags(libc::O_NOFOLLOW);
- /// }
+ /// options.custom_flags(libc::O_NOFOLLOW);
/// let file = options.open("foo.txt");
/// # }
/// ```
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index b2a4961..cc111f3 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -522,6 +522,21 @@ pub fn acceptfilter(&self) -> io::Result<&CStr> {
Ok(name)
}
+ #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+ pub fn set_exclbind(&self, excl: bool) -> io::Result<()> {
+ // not yet on libc crate
+ const SO_EXCLBIND: i32 = 0x1015;
+ setsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND, excl)
+ }
+
+ #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+ pub fn exclbind(&self) -> io::Result<bool> {
+ // not yet on libc crate
+ const SO_EXCLBIND: i32 = 0x1015;
+ let raw: c_int = getsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND)?;
+ Ok(raw != 0)
+ }
+
#[cfg(any(target_os = "android", target_os = "linux",))]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int)
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 1fe80c1..bbd03e2 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -968,8 +968,8 @@ pub fn kill(&self) -> io::Result<()> {
}
pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
- // If we've already waited on this process then the pid can be recycled
- // and used for another process, and we probably shouldn't be signaling
+ // If we've already waited on this process then the pid can be recycled and
+ // used for another process, and we probably shouldn't be sending signals to
// random processes, so return Ok because the process has exited already.
if self.status.is_some() {
return Ok(());
diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs
index 51ae8c5..2275cbb 100644
--- a/library/std/src/sys/process/unix/vxworks.rs
+++ b/library/std/src/sys/process/unix/vxworks.rs
@@ -151,8 +151,8 @@ pub fn kill(&self) -> io::Result<()> {
}
pub fn send_signal(&self, signal: i32) -> io::Result<()> {
- // If we've already waited on this process then the pid can be recycled
- // and used for another process, and we probably shouldn't be killing
+ // If we've already waited on this process then the pid can be recycled and
+ // used for another process, and we probably shouldn't be sending signals to
// random processes, so return Ok because the process has exited already.
if self.status.is_some() {
Ok(())
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index c149d51..3adc022 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -26,7 +26,7 @@
llvm-libunwind = ["std/llvm-libunwind"]
system-llvm-libunwind = ["std/system-llvm-libunwind"]
optimize_for_size = ["std/optimize_for_size"]
-panic-unwind = ["std/panic_unwind"]
+panic-unwind = ["std/panic-unwind"]
panic_immediate_abort = ["std/panic_immediate_abort"]
profiler = ["dep:profiler_builtins"]
std_detect_file_io = ["std/std_detect_file_io"]
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 77e645a..051d7dd 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -202,7 +202,9 @@ fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome)
}
fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, test: &TestOutcome) {
- if self.terse_tests_in_line != 0 && self.terse_tests_in_line % TERSE_TESTS_PER_LINE == 0 {
+ if self.terse_tests_in_line != 0
+ && self.terse_tests_in_line.is_multiple_of(TERSE_TESTS_PER_LINE)
+ {
if let Some(total) = self.tests_count {
let total = total.to_string();
let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len());
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh
index 064ac5b..924bdbc 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh
@@ -10,4 +10,7 @@
build-manifest bootstrap
# Use GCC for building GCC, as it seems to behave badly when built with Clang
-CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc
+# Only build GCC on full builds, not try builds
+if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then
+ CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc
+fi
diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md
index 18e827b..5b002b4 100644
--- a/src/doc/rustc/src/lints/levels.md
+++ b/src/doc/rustc/src/lints/levels.md
@@ -330,4 +330,105 @@
This feature is used heavily by Cargo; it will pass `--cap-lints allow` when
compiling your dependencies, so that if they have any warnings, they do not
-pollute the output of your build.
+pollute the output of your build. However, note that `--cap-lints allow` does **not** override lints marked as `force-warn`.
+
+## Priority of lint level sources
+
+Rust allows setting lint levels (`allow`, `warn`, `deny`, `forbid`, `force-warn`) through various sources:
+
+- **Attributes**: `#[allow(...)]`, `#![deny(...)]`, etc.
+- **Command-line options**: `--cap-lints`, `--force-warn`, `-A`, `-W`, `-D`, `-F`
+
+Here’s how these different lint controls interact:
+
+1. [`--force-warn`](#force-warn) forces a lint to warning level, and takes precedence over attributes and all other CLI flags.
+
+ ```rust,compile_fail
+ #[forbid(unused_variables)]
+ fn main() {
+ let x = 42;
+ }
+ ```
+
+ Compiled with:
+
+ ```bash
+ $ rustc --force-warn unused_variables lib.rs
+ warning: unused variable: `x`
+ --> lib.rs:3:9
+ |
+ 3 | let x = 42;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+ |
+ = note: requested on the command line with `--force-warn unused-variables`
+
+ warning: 1 warning emitted
+ ```
+
+2. [`--cap-lints`](#capping-lints) sets the maximum level of a lint, and takes precedence over attributes as well as the `-D`, `-W`, and `-F` CLI flags.
+
+ ```rust,compile_fail
+ #[deny(unused_variables)]
+ fn main() {
+ let x = 42;
+ }
+ ```
+
+ Compiled with:
+
+ ```bash
+ $ rustc --cap-lints=warn lib.rs
+ warning: unused variable: `x`
+ --> test1.rs:3:9
+ |
+ 3 | let x = 42;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+ |
+ note: the lint level is defined here
+ --> test1.rs:1:8
+ |
+ 1 | #[deny(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+
+ warning: 1 warning emitted
+ ```
+
+3. [CLI level flags](#via-compiler-flag) take precedence over attributes.
+
+ The order of the flags matter; flags on the right take precedence over earlier flags.
+
+ ```rust
+ fn main() {
+ let x = 42;
+ }
+ ```
+
+ Compiled with:
+
+ ```bash
+ $ rustc -A unused_variables -D unused_variables lib.rs
+ error: unused variable: `x`
+ --> test1.rs:2:9
+ |
+ 2 | let x = 42;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+ |
+ = note: requested on the command line with `-D unused-variables`
+
+ error: aborting due to 1 previous error
+ ```
+
+4. Within the source, [attributes](#via-an-attribute) at a lower-level in the syntax tree take precedence over attributes at a higher level, or from a previous attribute on the same entity as listed in left-to-right source order.
+
+ ```rust
+ #![deny(unused_variables)]
+
+ #[allow(unused_variables)]
+ fn main() {
+ let x = 42; // Allow wins
+ }
+ ```
+
+ - The exception is once a lint is set to "forbid", it is an error to try to change its level except for `deny`, which is allowed inside a forbid context, but is ignored.
+
+In terms of priority, [lint groups](groups.md) are treated as-if they are expanded to a list of all of the lints they contain. The exception is the `warnings` group which ignores attribute and CLI order and applies to all lints that would otherwise warn within the entity.
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index bba8e63..fdde830 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -8,23 +8,25 @@
path = "lib.rs"
[dependencies]
+# tidy-alphabetical-start
arrayvec = { version = "0.7", default-features = false }
askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] }
base64 = "0.21.7"
-itertools = "0.12"
indexmap = "2"
+itertools = "0.12"
minifier = { version = "0.3.5", default-features = false }
pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] }
regex = "1"
rustdoc-json-types = { path = "../rustdoc-json-types" }
-serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
smallvec = "1.8.1"
tempfile = "3"
+threadpool = "1.8.1"
tracing = "0.1"
tracing-tree = "0.3.0"
-threadpool = "1.8.1"
unicode-segmentation = "1.9"
+# tidy-alphabetical-end
[dependencies.tracing-subscriber]
version = "0.3.3"
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d77bdf0..3d027db 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -227,7 +227,7 @@ fn clean_generic_bound<'tcx>(
Some(match bound {
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
hir::GenericBound::Trait(t) => {
- // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+ // `T: [const] Destruct` is hidden because `T: Destruct` is a no-op.
if let hir::BoundConstness::Maybe(_) = t.modifiers.constness
&& cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
{
@@ -395,7 +395,7 @@ pub(crate) fn clean_predicate<'tcx>(
ty::ClauseKind::ConstEvaluatable(..)
| ty::ClauseKind::WellFormed(..)
| ty::ClauseKind::ConstArgHasType(..)
- // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `~const`.
+ // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `[const]`.
| ty::ClauseKind::HostEffect(_) => None,
}
}
@@ -404,7 +404,7 @@ fn clean_poly_trait_predicate<'tcx>(
pred: ty::PolyTraitPredicate<'tcx>,
cx: &mut DocContext<'tcx>,
) -> Option<WherePredicate> {
- // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+ // `T: [const] Destruct` is hidden because `T: Destruct` is a no-op.
// FIXME(const_trait_impl) check constness
if Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() {
return None;
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6ab1520..bcb3e57 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -268,7 +268,7 @@ pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match self {
clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
clean::GenericBound::TraitBound(ty, modifiers) => {
- // `const` and `~const` trait bounds are experimental; don't render them.
+ // `const` and `[const]` trait bounds are experimental; don't render them.
let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers;
f.write_str(match polarity {
hir::BoundPolarity::Positive => "",
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index e16acc9..e33bdc0 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1703,6 +1703,7 @@ fn render_enum_fields(
if v.is_stripped() {
continue;
}
+ write!(w, "{}", render_attributes_in_pre(v, TAB, cx))?;
w.write_str(TAB)?;
match v.kind {
clean::VariantItem(ref var) => match var.kind {
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index 6af1644..bbcd9604 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -4,6 +4,8 @@
/* eslint-disable */
declare global {
+ /** Search engine data used by main.js and search.js */
+ declare var searchState: rustdoc.SearchState;
/** Defined and documented in `storage.js` */
declare function nonnull(x: T|null, msg: string|undefined);
/** Defined and documented in `storage.js` */
@@ -17,8 +19,6 @@
RUSTDOC_TOOLTIP_HOVER_MS: number;
/** Used by the popover tooltip code. */
RUSTDOC_TOOLTIP_HOVER_EXIT_MS: number;
- /** Search engine data used by main.js and search.js */
- searchState: rustdoc.SearchState;
/** Global option, with a long list of "../"'s */
rootPath: string|null;
/**
@@ -102,20 +102,22 @@
currentTab: number;
focusedByTab: [number|null, number|null, number|null];
clearInputTimeout: function;
- outputElement: function(): HTMLElement|null;
- focus: function();
- defocus: function();
- showResults: function(HTMLElement|null|undefined);
- removeQueryParameters: function();
- hideResults: function();
- getQueryStringParams: function(): Object.<any, string>;
+ outputElement(): HTMLElement|null;
+ focus();
+ defocus();
+ // note: an optional param is not the same as
+ // a nullable/undef-able param.
+ showResults(elem?: HTMLElement|null);
+ removeQueryParameters();
+ hideResults();
+ getQueryStringParams(): Object.<any, string>;
origPlaceholder: string;
setup: function();
- setLoadingSearch: function();
+ setLoadingSearch();
descShards: Map<string, SearchDescShard[]>;
loadDesc: function({descShard: SearchDescShard, descIndex: number}): Promise<string|null>;
- loadedDescShard: function(string, number, string);
- isDisplayed: function(): boolean,
+ loadedDescShard(string, number, string);
+ isDisplayed(): boolean,
}
interface SearchDescShard {
@@ -237,7 +239,7 @@
query: ParsedQuery,
}
- type Results = Map<String, ResultObject>;
+ type Results = { max_dist?: number } & Map<number, ResultObject>
/**
* An annotated `Row`, used in the viewmodel.
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index a2c4870..15cad31 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -2515,13 +2515,17 @@
*
* @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} origParsedQuery
* - The parsed user query
- * @param {Object} [filterCrates] - Crate to search in if defined
- * @param {Object} [currentCrate] - Current crate, to rank results from this crate higher
+ * @param {Object} filterCrates - Crate to search in if defined
+ * @param {string} currentCrate - Current crate, to rank results from this crate higher
*
* @return {Promise<rustdoc.ResultsTable>}
*/
async execQuery(origParsedQuery, filterCrates, currentCrate) {
- const results_others = new Map(), results_in_args = new Map(),
+ /** @type {rustdoc.Results} */
+ const results_others = new Map(),
+ /** @type {rustdoc.Results} */
+ results_in_args = new Map(),
+ /** @type {rustdoc.Results} */
results_returned = new Map();
/** @type {rustdoc.ParsedQuery<rustdoc.QueryElement>} */
@@ -4365,7 +4369,7 @@
*
* The `results` map contains information which will be used to sort the search results:
*
- * * `fullId` is a `string`` used as the key of the object we use for the `results` map.
+ * * `fullId` is an `integer`` used as the key of the object we use for the `results` map.
* * `id` is the index in the `searchIndex` array for this element.
* * `index` is an `integer`` used to sort by the position of the word in the item's name.
* * `dist` is the main metric used to sort the search results.
@@ -4373,19 +4377,18 @@
* distance computed for everything other than the last path component.
*
* @param {rustdoc.Results} results
- * @param {string} fullId
+ * @param {number} fullId
* @param {number} id
* @param {number} index
* @param {number} dist
* @param {number} path_dist
+ * @param {number} maxEditDistance
*/
- // @ts-expect-error
function addIntoResults(results, fullId, id, index, dist, path_dist, maxEditDistance) {
if (dist <= maxEditDistance || index !== -1) {
if (results.has(fullId)) {
const result = results.get(fullId);
- // @ts-expect-error
- if (result.dontValidate || result.dist <= dist) {
+ if (result === undefined || result.dontValidate || result.dist <= dist) {
return;
}
}
@@ -4452,9 +4455,8 @@
return;
}
- // @ts-expect-error
results.max_dist = Math.max(results.max_dist || 0, tfpDist);
- addIntoResults(results, row.id.toString(), pos, 0, tfpDist, 0, Number.MAX_VALUE);
+ addIntoResults(results, row.id, pos, 0, tfpDist, 0, Number.MAX_VALUE);
}
/**
@@ -4495,7 +4497,7 @@
if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
const elem = parsedQuery.elems[0];
// use arrow functions to preserve `this`.
- // @ts-expect-error
+ /** @type {function(number): void} */
const handleNameSearch = id => {
const row = this.searchIndex[id];
if (!typePassesFilter(elem.typeFilter, row.ty) ||
@@ -4505,22 +4507,21 @@
let pathDist = 0;
if (elem.fullPath.length > 1) {
- // @ts-expect-error
- pathDist = checkPath(elem.pathWithoutLast, row);
- if (pathDist === null) {
+
+ const maybePathDist = checkPath(elem.pathWithoutLast, row);
+ if (maybePathDist === null) {
return;
}
+ pathDist = maybePathDist;
}
if (parsedQuery.literalSearch) {
if (row.word === elem.pathLast) {
- // @ts-expect-error
- addIntoResults(results_others, row.id, id, 0, 0, pathDist);
+ addIntoResults(results_others, row.id, id, 0, 0, pathDist, 0);
}
} else {
addIntoResults(
results_others,
- // @ts-expect-error
row.id,
id,
row.normalizedName.indexOf(elem.normalizedPathLast),
@@ -4561,31 +4562,23 @@
const returned = row.type && row.type.output
&& checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
if (in_args) {
- // @ts-expect-error
results_in_args.max_dist = Math.max(
- // @ts-expect-error
results_in_args.max_dist || 0,
tfpDist,
);
const maxDist = results_in_args.size < MAX_RESULTS ?
(tfpDist + 1) :
- // @ts-expect-error
results_in_args.max_dist;
- // @ts-expect-error
addIntoResults(results_in_args, row.id, i, -1, tfpDist, 0, maxDist);
}
if (returned) {
- // @ts-expect-error
results_returned.max_dist = Math.max(
- // @ts-expect-error
results_returned.max_dist || 0,
tfpDist,
);
const maxDist = results_returned.size < MAX_RESULTS ?
(tfpDist + 1) :
- // @ts-expect-error
results_returned.max_dist;
- // @ts-expect-error
addIntoResults(results_returned, row.id, i, -1, tfpDist, 0, maxDist);
}
}
@@ -4595,18 +4588,17 @@
// types with generic parameters go last.
// That's because of the way unification is structured: it eats off
// the end, and hits a fast path if the last item is a simple atom.
- // @ts-expect-error
+ /** @type {function(rustdoc.QueryElement, rustdoc.QueryElement): number} */
const sortQ = (a, b) => {
const ag = a.generics.length === 0 && a.bindings.size === 0;
const bg = b.generics.length === 0 && b.bindings.size === 0;
if (ag !== bg) {
- // @ts-expect-error
- return ag - bg;
+ // unary `+` converts booleans into integers.
+ return +ag - +bg;
}
- const ai = a.id > 0;
- const bi = b.id > 0;
- // @ts-expect-error
- return ai - bi;
+ const ai = a.id !== null && a.id > 0;
+ const bi = b.id !== null && b.id > 0;
+ return +ai - +bi;
};
parsedQuery.elems.sort(sortQ);
parsedQuery.returned.sort(sortQ);
@@ -4622,9 +4614,7 @@
const isType = parsedQuery.foundElems !== 1 || parsedQuery.hasReturnArrow;
const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
- // @ts-expect-error
sortResults(results_in_args, "elems", currentCrate),
- // @ts-expect-error
sortResults(results_returned, "returned", currentCrate),
// @ts-expect-error
sortResults(results_others, (isType ? "query" : null), currentCrate),
@@ -4724,7 +4714,6 @@
iter += 1;
});
if (foundCurrentTab && foundCurrentResultSet) {
- // @ts-expect-error
searchState.currentTab = nb;
// Corrections only kick in on type-based searches.
const correctionsElem = document.getElementsByClassName("search-corrections");
@@ -4777,7 +4766,6 @@
// @ts-expect-error
function nextTab(direction) {
- // @ts-expect-error
const next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
// @ts-expect-error
searchState.focusedByTab[searchState.currentTab] = document.activeElement;
@@ -4788,14 +4776,12 @@
// Focus the first search result on the active tab, or the result that
// was focused last time this tab was active.
function focusSearchResult() {
- // @ts-expect-error
const target = searchState.focusedByTab[searchState.currentTab] ||
document.querySelectorAll(".search-results.active a").item(0) ||
- // @ts-expect-error
document.querySelectorAll("#search-tabs button").item(searchState.currentTab);
- // @ts-expect-error
searchState.focusedByTab[searchState.currentTab] = null;
if (target) {
+ // @ts-expect-error
target.focus();
}
}
@@ -4947,7 +4933,6 @@
const fmtNbElems =
nbElems < 10 ? `\u{2007}(${nbElems})\u{2007}\u{2007}` :
nbElems < 100 ? `\u{2007}(${nbElems})\u{2007}` : `\u{2007}(${nbElems})`;
- // @ts-expect-error
if (searchState.currentTab === tabNb) {
return "<button class=\"selected\">" + text +
"<span class=\"count\">" + fmtNbElems + "</span></button>";
@@ -4961,7 +4946,6 @@
* @param {string} filterCrates
*/
async function showResults(results, go_to_first, filterCrates) {
- // @ts-expect-error
const search = searchState.outputElement();
if (go_to_first || (results.others.length === 1
&& getSettingValue("go-to-only-result") === "true")
@@ -4979,7 +4963,6 @@
// will be used, starting search again since the search input is not empty, leading you
// back to the previous page again.
window.onunload = () => { };
- // @ts-expect-error
searchState.removeQueryParameters();
const elem = document.createElement("a");
elem.href = results.others[0].href;
@@ -4999,7 +4982,6 @@
// Navigate to the relevant tab if the current tab is empty, like in case users search
// for "-> String". If they had selected another tab previously, they have to click on
// it again.
- // @ts-expect-error
let currentTab = searchState.currentTab;
if ((currentTab === 0 && results.others.length === 0) ||
(currentTab === 1 && results.in_args.length === 0) ||
@@ -5087,8 +5069,8 @@
resultsElem.appendChild(ret_in_args);
resultsElem.appendChild(ret_returned);
- search.innerHTML = output;
// @ts-expect-error
+ search.innerHTML = output;
if (searchState.rustdocToolbar) {
// @ts-expect-error
search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar);
@@ -5097,9 +5079,9 @@
if (crateSearch) {
crateSearch.addEventListener("input", updateCrate);
}
+ // @ts-expect-error
search.appendChild(resultsElem);
// Reset focused elements.
- // @ts-expect-error
searchState.showResults(search);
// @ts-expect-error
const elems = document.getElementById("search-tabs").childNodes;
@@ -5110,7 +5092,6 @@
const j = i;
// @ts-expect-error
elem.onclick = () => printTab(j);
- // @ts-expect-error
searchState.focusedByTab.push(null);
i += 1;
}
@@ -5122,7 +5103,6 @@
if (!browserSupportsHistoryApi()) {
return;
}
- // @ts-expect-error
const params = searchState.getQueryStringParams();
if (!history.state && !params.search) {
history.pushState(null, "", url);
@@ -5149,10 +5129,8 @@
return;
}
- // @ts-expect-error
searchState.setLoadingSearch();
- // @ts-expect-error
const params = searchState.getQueryStringParams();
// In case we have no information about the saved crate and there is a URL query parameter,
@@ -5162,7 +5140,6 @@
}
// Update document title to maintain a meaningful browser history
- // @ts-expect-error
searchState.title = "\"" + query.userQuery + "\" Search - Rust";
// Because searching is incremental by character, only the most
@@ -5184,33 +5161,28 @@
function onSearchSubmit(e) {
// @ts-expect-error
e.preventDefault();
- // @ts-expect-error
searchState.clearInputTimeout();
search();
}
function putBackSearch() {
- // @ts-expect-error
const search_input = searchState.input;
- // @ts-expect-error
if (!searchState.input) {
return;
}
// @ts-expect-error
if (search_input.value !== "" && !searchState.isDisplayed()) {
- // @ts-expect-error
searchState.showResults();
if (browserSupportsHistoryApi()) {
history.replaceState(null, "",
+ // @ts-expect-error
buildUrl(search_input.value, getFilterCrates()));
}
- // @ts-expect-error
document.title = searchState.title;
}
}
function registerSearchEvents() {
- // @ts-expect-error
const params = searchState.getQueryStringParams();
// Populate search bar with query string search term when provided,
@@ -5224,14 +5196,11 @@
}
const searchAfter500ms = () => {
- // @ts-expect-error
searchState.clearInputTimeout();
// @ts-expect-error
if (searchState.input.value.length === 0) {
- // @ts-expect-error
searchState.hideResults();
} else {
- // @ts-expect-error
searchState.timeout = setTimeout(search, 500);
}
};
@@ -5248,7 +5217,6 @@
return;
}
// Do NOT e.preventDefault() here. It will prevent pasting.
- // @ts-expect-error
searchState.clearInputTimeout();
// zero-timeout necessary here because at the time of event handler execution the
// pasted content is not in the input field yet. Shouldn’t make any difference for
@@ -5274,7 +5242,6 @@
// @ts-expect-error
previous.focus();
} else {
- // @ts-expect-error
searchState.focus();
}
e.preventDefault();
@@ -5327,7 +5294,6 @@
const previousTitle = document.title;
window.addEventListener("popstate", e => {
- // @ts-expect-error
const params = searchState.getQueryStringParams();
// Revert to the previous title manually since the History
// API ignores the title parameter.
@@ -5355,7 +5321,6 @@
searchState.input.value = "";
// When browsing back from search results the main page
// visibility must be reset.
- // @ts-expect-error
searchState.hideResults();
}
});
@@ -5368,7 +5333,6 @@
// that try to sync state between the URL and the search input. To work around it,
// do a small amount of re-init on page show.
window.onpageshow = () => {
- // @ts-expect-error
const qSearch = searchState.getQueryStringParams().search;
// @ts-expect-error
if (searchState.input.value === "" && qSearch) {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 025c135..a3cdc4f 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -1,8 +1,8 @@
+// tidy-alphabetical-start
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/"
)]
-#![feature(rustc_private)]
#![feature(ascii_char)]
#![feature(ascii_char_variants)]
#![feature(assert_matches)]
@@ -11,18 +11,12 @@
#![feature(file_buffered)]
#![feature(format_args_nl)]
#![feature(if_let_guard)]
-#![feature(impl_trait_in_assoc_type)]
#![feature(iter_intersperse)]
-#![feature(never_type)]
#![feature(round_char_boundary)]
+#![feature(rustc_private)]
#![feature(test)]
-#![feature(type_alias_impl_trait)]
-#![feature(type_ascription)]
-#![recursion_limit = "256"]
#![warn(rustc::internal)]
-#![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
-#![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::untranslatable_diagnostic)]
+// tidy-alphabetical-end
extern crate thin_vec;
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 4c53ea42..0520eff 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -14,6 +14,7 @@
static HOSTS: &[&str] = &[
"aarch64-apple-darwin",
+ "aarch64-pc-windows-gnullvm",
"aarch64-pc-windows-msvc",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
@@ -44,6 +45,7 @@
"x86_64-apple-darwin",
"x86_64-pc-solaris",
"x86_64-pc-windows-gnu",
+ "x86_64-pc-windows-gnullvm",
"x86_64-pc-windows-msvc",
"x86_64-unknown-freebsd",
"x86_64-unknown-illumos",
@@ -470,7 +472,7 @@ fn target_host_combination(&mut self, host: &str, manifest: &Manifest) -> Option
}
// so is rust-mingw if it's available for the target
PkgType::RustMingw => {
- if host.contains("pc-windows-gnu") {
+ if host.ends_with("pc-windows-gnu") {
components.push(host_component(pkg));
}
}
diff --git a/src/tools/cargo b/src/tools/cargo
index 409fed7..930b4f6 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 409fed7dc1553d49cb9a8c0637d12d65571346ce
+Subproject commit 930b4f62cfcd1f0eabdb30a56d91bf6844b739bf
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
index b49493e..4647406 100644
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
@@ -1,5 +1,7 @@
name: New lint suggestion
-description: Suggest a new Clippy lint.
+description: |
+ Suggest a new Clippy lint (currently not accepting new lints)
+ Check out the Clippy book for more information about the feature freeze.
labels: ["A-lint"]
body:
- type: markdown
diff --git a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
index 9e49f60..83bfd8e 100644
--- a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
+++ b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
@@ -32,6 +32,10 @@
Delete this line and everything above before opening your PR.
+Note that we are currently not taking in new PRs that add new lints. We are in a
+feature freeze. Check out the book for more information. If you open a
+feature-adding pull request, its review will be delayed.
+
---
*Please write a short comment explaining your change (or "none" for internal only changes)*
diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml
new file mode 100644
index 0000000..a5f8d4b
--- /dev/null
+++ b/src/tools/clippy/.github/workflows/feature_freeze.yml
@@ -0,0 +1,25 @@
+name: Feature freeze check
+
+on:
+ pull_request:
+ paths:
+ - 'clippy_lints/src/declared_lints.rs'
+
+jobs:
+ auto-comment:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check PR Changes
+ id: pr-changes
+ run: echo "::set-output name=changes::${{ toJson(github.event.pull_request.changed_files) }}"
+
+ - name: Create Comment
+ if: steps.pr-changes.outputs.changes != '[]'
+ run: |
+ # Use GitHub API to create a comment on the PR
+ PR_NUMBER=${{ github.event.pull_request.number }}
+ COMMENT="**Seems that you are trying to add a new lint!**\nWe are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to August 1st and focusing on bugfixes.\nThanks a lot for your contribution, and sorry for the inconvenience.\nWith ❤ from the Clippy team"
+ GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
+ COMMENT_URL="https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments"
+ curl -s -H "Authorization: token ${GITHUB_TOKEN}" -X POST $COMMENT_URL -d "{\"body\":\"$COMMENT\"}"
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 0cfe89a..a92fbdc 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,7 +6,94 @@
## Unreleased / Beta / In Rust Nightly
-[1e5237f4...master](https://github.com/rust-lang/rust-clippy/compare/1e5237f4...master)
+[03a5b6b9...master](https://github.com/rust-lang/rust-clippy/compare/03a5b6b9...master)
+
+## Rust 1.88
+
+Current stable, released 2025-06-26
+
+[View all 126 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-03-21T10%3A30%3A57Z..2025-05-01T08%3A03%3A26Z+base%3Amaster)
+
+### New Lints
+
+* Added [`swap_with_temporary`] to `complexity` [#14046](https://github.com/rust-lang/rust-clippy/pull/14046)
+* Added [`redundant_test_prefix`] to `restriction` [#13710](https://github.com/rust-lang/rust-clippy/pull/13710)
+* Added [`manual_dangling_ptr`] to `style` [#14107](https://github.com/rust-lang/rust-clippy/pull/14107)
+* Added [`char_indices_as_byte_indices`] to `correctness` [#13435](https://github.com/rust-lang/rust-clippy/pull/13435)
+* Added [`manual_abs_diff`] to `complexity` [#14482](https://github.com/rust-lang/rust-clippy/pull/14482)
+* Added [`ignore_without_reason`] to `pedantic` [#13931](https://github.com/rust-lang/rust-clippy/pull/13931)
+
+### Moves and Deprecations
+
+* Moved [`uninlined_format_args`] to `style` (from `pedantic`)
+ [#14160](https://github.com/rust-lang/rust-clippy/pull/14160)
+* [`match_on_vec_items`] deprecated in favor of [`indexing_slicing`]
+ [#14217](https://github.com/rust-lang/rust-clippy/pull/14217)
+* Removed superseded lints: `transmute_float_to_int`, `transmute_int_to_char`,
+ `transmute_int_to_float`, `transmute_num_to_bytes` (now in rustc)
+ [#14703](https://github.com/rust-lang/rust-clippy/pull/14703)
+
+### Enhancements
+
+* Configuration renamed from `lint-inconsistent-struct-field-initializers`
+ to `check-inconsistent-struct-field-initializers`
+ [#14280](https://github.com/rust-lang/rust-clippy/pull/14280)
+* Paths in `disallowed_*` configurations are now validated
+ [#14397](https://github.com/rust-lang/rust-clippy/pull/14397)
+* [`borrow_as_ptr`] now lints implicit casts as well
+ [#14408](https://github.com/rust-lang/rust-clippy/pull/14408)
+* [`iter_kv_map`] now recognizes references on maps
+ [#14596](https://github.com/rust-lang/rust-clippy/pull/14596)
+* [`empty_enum_variants_with_brackets`] no longer lints reachable enums or enums used
+ as functions within same crate [#12971](https://github.com/rust-lang/rust-clippy/pull/12971)
+* [`needless_lifetimes`] now checks for lifetime uses in closures
+ [#14608](https://github.com/rust-lang/rust-clippy/pull/14608)
+* [`wildcard_imports`] now lints on `pub use` when `warn_on_all_wildcard_imports` is enabled
+ [#14182](https://github.com/rust-lang/rust-clippy/pull/14182)
+* [`collapsible_if`] now recognizes the `let_chains` feature
+ [#14481](https://github.com/rust-lang/rust-clippy/pull/14481)
+* [`match_single_binding`] now allows macros in scrutinee and patterns
+ [#14635](https://github.com/rust-lang/rust-clippy/pull/14635)
+* [`needless_borrow`] does not contradict the compiler's
+ `dangerous_implicit_autorefs` lint even though the references
+ are not mandatory
+ [#14810](https://github.com/rust-lang/rust-clippy/pull/14810)
+
+### False Positive Fixes
+
+* [`double_ended_iterator_last`] and [`needless_collect`] fixed FP when iter has side effects
+ [#14490](https://github.com/rust-lang/rust-clippy/pull/14490)
+* [`mut_from_ref`] fixed FP where lifetimes nested in types were not considered
+ [#14471](https://github.com/rust-lang/rust-clippy/pull/14471)
+* [`redundant_clone`] fixed FP in overlapping lifetime
+ [#14237](https://github.com/rust-lang/rust-clippy/pull/14237)
+* [`map_entry`] fixed FP where lint would trigger without insert calls present
+ [#14568](https://github.com/rust-lang/rust-clippy/pull/14568)
+* [`iter_cloned_collect`] fixed FP with custom `From`/`IntoIterator` impl
+ [#14473](https://github.com/rust-lang/rust-clippy/pull/14473)
+* [`shadow_unrelated`] fixed FP in destructuring assignments
+ [#14381](https://github.com/rust-lang/rust-clippy/pull/14381)
+* [`redundant_clone`] fixed FP on enum cast
+ [#14395](https://github.com/rust-lang/rust-clippy/pull/14395)
+* [`collapsible_if`] fixed FP on block stmt before expr
+ [#14730](https://github.com/rust-lang/rust-clippy/pull/14730)
+
+### ICE Fixes
+
+* [`missing_const_for_fn`] fix ICE with `-Z validate-mir` compilation option
+ [#14776](https://github.com/rust-lang/rust-clippy/pull/14776)
+
+### Documentation Improvements
+
+* [`missing_asserts_for_indexing`] improved documentation and examples
+ [#14108](https://github.com/rust-lang/rust-clippy/pull/14108)
+
+### Others
+
+* We're testing with edition 2024 now
+ [#14602](https://github.com/rust-lang/rust-clippy/pull/14602)
+* Don't warn about unloaded crates in `clippy.toml` disallowed paths
+ [#14733](https://github.com/rust-lang/rust-clippy/pull/14733)
## Rust 1.87
@@ -5729,6 +5816,7 @@
[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
+[`doc_broken_link`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_broken_link
[`doc_comment_double_space_linebreaks`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_comment_double_space_linebreaks
[`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg
[`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
@@ -5967,6 +6055,7 @@
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
[`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite
+[`manual_is_multiple_of`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_multiple_of
[`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two
[`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and
[`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 13cf82a..1278427 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy"
-version = "0.1.89"
+version = "0.1.90"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -24,6 +24,7 @@
clippy_config = { path = "clippy_config" }
clippy_lints = { path = "clippy_lints" }
clippy_utils = { path = "clippy_utils" }
+declare_clippy_lint = { path = "declare_clippy_lint" }
rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
clippy_lints_internal = { path = "clippy_lints_internal", optional = true }
tempfile = { version = "3.20", optional = true }
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index 5d2c397..db73b49 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -1,5 +1,9 @@
# Clippy
+[### IMPORTANT NOTE FOR CONTRIBUTORS ================](development/feature_freeze.md)
+
+----
+
[](https://github.com/rust-lang/rust-clippy#license)
A collection of lints to catch common mistakes and improve your
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index 39fe735..b66c348 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -13,6 +13,7 @@
- [GitLab CI](continuous_integration/gitlab.md)
- [Travis CI](continuous_integration/travis.md)
- [Development](development/README.md)
+ - [IMPORTANT: FEATURE FREEZE](development/feature_freeze.md)
- [Basics](development/basics.md)
- [Adding Lints](development/adding_lints.md)
- [Defining Lints](development/defining_lints.md)
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index 2b89e94..a42a298 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -1,5 +1,8 @@
# Adding a new lint
+[### IMPORTANT NOTE FOR CONTRIBUTORS ================](feature_freeze.md)
+
+
You are probably here because you want to add a new lint to Clippy. If this is
the first time you're contributing to Clippy, this document guides you through
creating an example lint from scratch.
diff --git a/src/tools/clippy/book/src/development/feature_freeze.md b/src/tools/clippy/book/src/development/feature_freeze.md
new file mode 100644
index 0000000..260cb13
--- /dev/null
+++ b/src/tools/clippy/book/src/development/feature_freeze.md
@@ -0,0 +1,55 @@
+# IMPORTANT: FEATURE FREEZE
+
+This is a temporary notice.
+
+From the 26th of June until the 18th of September we will perform a feature freeze. Only bugfix PRs will be reviewed
+except already open ones. Every feature-adding PR opened in between those dates will be moved into a
+milestone to be reviewed separately at another time.
+
+We do this because of the long backlog of bugs that need to be addressed
+in order to continue being the state-of-the-art linter that Clippy has become known for being.
+
+## For contributors
+
+If you are a contributor or are planning to become one, **please do not open a lint-adding PR**, we have lots of open
+bugs of all levels of difficulty that you can address instead!
+
+We currently have about 800 lints, each one posing a maintainability challenge that needs to account to every possible
+use case of the whole ecosystem. Bugs are natural in every software, but the Clippy team considers that Clippy needs a
+refinement period.
+
+If you open a PR at this time, we will not review it but push it into a milestone until the refinement period ends,
+adding additional load into our reviewing schedules.
+
+## I want to help, what can I do
+
+Thanks a lot to everyone who wants to help Clippy become better software in this feature freeze period!
+If you'd like to help, making a bugfix, making sure that it works, and opening a PR is a great step!
+
+To find things to fix, go to the [tracking issue][tracking_issue], find an issue that you like, go there and claim that
+issue with `@rustbot claim`.
+
+As a general metric and always taking into account your skill and knowledge level, you can use this guide:
+
+- 🟥 [ICEs][search_ice], these are compiler errors that causes Clippy to panic and crash. Usually involves high-level
+debugging, sometimes interacting directly with the upstream compiler. Difficult to fix but a great challenge that
+improves a lot developer workflows!
+
+- 🟧 [Suggestion causes bug][sugg_causes_bug], Clippy suggested code that changed logic in some silent way.
+Unacceptable, as this may have disastrous consequences. Easier to fix than ICEs
+
+- 🟨 [Suggestion causes error][sugg_causes_error], Clippy suggested code snippet that caused a compiler error
+when applied. We need to make sure that Clippy doesn't suggest using a variable twice at the same time or similar
+easy-to-happen occurrences.
+
+- 🟩 [False positives][false_positive], a lint should not have fired, the easiest of them all, as this is "just"
+identifying the root of a false positive and making an exception for those cases.
+
+Note that false negatives do not have priority unless the case is very clear, as they are a feature-request in a
+trench coat.
+
+[search_ice]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc+state%3Aopen+label%3A%22I-ICE%22
+[sugg_causes_bug]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-bug
+[sugg_causes_error]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-error%20
+[false_positive]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-false-positive
+[tracking_issue]: https://github.com/rust-lang/rust-clippy/issues/15086
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 7c850b4..e9b7f42 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -488,6 +488,13 @@
## `disallowed-macros`
The list of disallowed macros, written as fully qualified paths.
+**Fields:**
+- `path` (required): the fully qualified path to the macro that should be disallowed
+- `reason` (optional): explanation why this macro is disallowed
+- `replacement` (optional): suggested alternative macro
+- `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+ if the path doesn't exist, instead of emitting an error
+
**Default Value:** `[]`
---
@@ -498,6 +505,13 @@
## `disallowed-methods`
The list of disallowed methods, written as fully qualified paths.
+**Fields:**
+- `path` (required): the fully qualified path to the method that should be disallowed
+- `reason` (optional): explanation why this method is disallowed
+- `replacement` (optional): suggested alternative method
+- `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+ if the path doesn't exist, instead of emitting an error
+
**Default Value:** `[]`
---
@@ -520,6 +534,13 @@
## `disallowed-types`
The list of disallowed types, written as fully qualified paths.
+**Fields:**
+- `path` (required): the fully qualified path to the type that should be disallowed
+- `reason` (optional): explanation why this type is disallowed
+- `replacement` (optional): suggested alternative type
+- `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+ if the path doesn't exist, instead of emitting an error
+
**Default Value:** `[]`
---
@@ -651,13 +672,14 @@
## `lint-commented-code`
-Whether collapsible `if` chains are linted if they contain comments inside the parts
+Whether collapsible `if` and `else if` chains are linted if they contain comments inside the parts
that would be collapsed.
**Default Value:** `false`
---
**Affected lints:**
+* [`collapsible_else_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if)
* [`collapsible_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if)
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 0606245..858366c 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_config"
-version = "0.1.89"
+version = "0.1.90"
edition = "2024"
publish = false
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 87158ce..841facd 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -575,10 +575,24 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
#[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
cyclomatic_complexity_threshold: u64 = 25,
/// The list of disallowed macros, written as fully qualified paths.
+ ///
+ /// **Fields:**
+ /// - `path` (required): the fully qualified path to the macro that should be disallowed
+ /// - `reason` (optional): explanation why this macro is disallowed
+ /// - `replacement` (optional): suggested alternative macro
+ /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+ /// if the path doesn't exist, instead of emitting an error
#[disallowed_paths_allow_replacements = true]
#[lints(disallowed_macros)]
disallowed_macros: Vec<DisallowedPath> = Vec::new(),
/// The list of disallowed methods, written as fully qualified paths.
+ ///
+ /// **Fields:**
+ /// - `path` (required): the fully qualified path to the method that should be disallowed
+ /// - `reason` (optional): explanation why this method is disallowed
+ /// - `replacement` (optional): suggested alternative method
+ /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+ /// if the path doesn't exist, instead of emitting an error
#[disallowed_paths_allow_replacements = true]
#[lints(disallowed_methods)]
disallowed_methods: Vec<DisallowedPath> = Vec::new(),
@@ -588,6 +602,13 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
#[lints(disallowed_names)]
disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(),
/// The list of disallowed types, written as fully qualified paths.
+ ///
+ /// **Fields:**
+ /// - `path` (required): the fully qualified path to the type that should be disallowed
+ /// - `reason` (optional): explanation why this type is disallowed
+ /// - `replacement` (optional): suggested alternative type
+ /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+ /// if the path doesn't exist, instead of emitting an error
#[disallowed_paths_allow_replacements = true]
#[lints(disallowed_types)]
disallowed_types: Vec<DisallowedPath> = Vec::new(),
@@ -641,9 +662,9 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
/// The maximum size of the `Err`-variant in a `Result` returned from a function
#[lints(result_large_err)]
large_error_threshold: u64 = 128,
- /// Whether collapsible `if` chains are linted if they contain comments inside the parts
+ /// Whether collapsible `if` and `else if` chains are linted if they contain comments inside the parts
/// that would be collapsed.
- #[lints(collapsible_if)]
+ #[lints(collapsible_else_if, collapsible_if)]
lint_commented_code: bool = false,
/// Whether to suggest reordering constructor fields when initializers are present.
/// DEPRECATED CONFIGURATION: lint-inconsistent-struct-field-initializers
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index e0e0367..0d66f16 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -13,7 +13,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>
if is_file {
exit_if_err(
- Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+ Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
.args(["run", "--bin", "clippy-driver", "--"])
.args(["-L", "./target/debug"])
.args(["-Z", "no-codegen"])
@@ -26,7 +26,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>
);
} else {
exit_if_err(
- Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+ Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
.arg("build")
.status(),
);
diff --git a/src/tools/clippy/clippy_dev/src/release.rs b/src/tools/clippy/clippy_dev/src/release.rs
index 62c1bee..15392dd 100644
--- a/src/tools/clippy/clippy_dev/src/release.rs
+++ b/src/tools/clippy/clippy_dev/src/release.rs
@@ -5,6 +5,7 @@
"clippy_config/Cargo.toml",
"clippy_lints/Cargo.toml",
"clippy_utils/Cargo.toml",
+ "declare_clippy_lint/Cargo.toml",
"Cargo.toml",
];
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index a2d1236..498ffeb 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -28,7 +28,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
.map(mtime);
if times.iter().any(|&time| index_time < time) {
- Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+ Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
.arg("collect-metadata")
.spawn()
.unwrap()
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 3b827cc..5f6e874 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -2,11 +2,11 @@
ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, expect_action, update_text_region_fn,
};
use itertools::Itertools;
-use rustc_lexer::{LiteralKind, TokenKind, tokenize};
use std::collections::HashSet;
use std::fmt::Write;
+use std::fs;
use std::ops::Range;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
use walkdir::{DirEntry, WalkDir};
const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\
@@ -37,123 +37,164 @@ pub fn generate_lint_files(
deprecated: &[DeprecatedLint],
renamed: &[RenamedLint],
) {
- FileUpdater::default().update_files_checked(
+ let mut updater = FileUpdater::default();
+ updater.update_file_checked(
"cargo dev update_lints",
update_mode,
- &mut [
- (
- "README.md",
- &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
- write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
- }),
- ),
- (
- "book/src/README.md",
- &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
- write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
- }),
- ),
- (
- "CHANGELOG.md",
- &mut update_text_region_fn(
- "<!-- begin autogenerated links to lint list -->\n",
- "<!-- end autogenerated links to lint list -->",
- |dst| {
- for lint in lints
- .iter()
- .map(|l| &*l.name)
- .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
- .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
- .sorted()
- {
- writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
- }
- },
- ),
- ),
- (
- "clippy_lints/src/lib.rs",
- &mut update_text_region_fn(
- "// begin lints modules, do not remove this comment, it's used in `update_lints`\n",
- "// end lints modules, do not remove this comment, it's used in `update_lints`",
- |dst| {
- for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() {
- writeln!(dst, "mod {lint_mod};").unwrap();
- }
- },
- ),
- ),
- ("clippy_lints/src/declared_lints.rs", &mut |_, src, dst| {
- dst.push_str(GENERATED_FILE_COMMENT);
- dst.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n");
- for (module_name, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() {
- writeln!(dst, " crate::{module_name}::{lint_name}_INFO,").unwrap();
+ "README.md",
+ &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+ write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+ }),
+ );
+ updater.update_file_checked(
+ "cargo dev update_lints",
+ update_mode,
+ "book/src/README.md",
+ &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+ write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+ }),
+ );
+ updater.update_file_checked(
+ "cargo dev update_lints",
+ update_mode,
+ "CHANGELOG.md",
+ &mut update_text_region_fn(
+ "<!-- begin autogenerated links to lint list -->\n",
+ "<!-- end autogenerated links to lint list -->",
+ |dst| {
+ for lint in lints
+ .iter()
+ .map(|l| &*l.name)
+ .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
+ .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
+ .sorted()
+ {
+ writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
}
- dst.push_str("];\n");
- UpdateStatus::from_changed(src != dst)
- }),
- ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| {
- let mut searcher = RustSearcher::new(src);
- assert!(
- searcher.find_token(Token::Ident("declare_with_version"))
- && searcher.find_token(Token::Ident("declare_with_version")),
- "error reading deprecated lints"
- );
- dst.push_str(&src[..searcher.pos() as usize]);
- dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
- for lint in deprecated {
- write!(
- dst,
- " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n",
- lint.version, lint.name, lint.reason,
- )
- .unwrap();
- }
- dst.push_str(
- "]}\n\n\
+ },
+ ),
+ );
+ updater.update_file_checked(
+ "cargo dev update_lints",
+ update_mode,
+ "clippy_lints/src/deprecated_lints.rs",
+ &mut |_, src, dst| {
+ let mut searcher = RustSearcher::new(src);
+ assert!(
+ searcher.find_token(Token::Ident("declare_with_version"))
+ && searcher.find_token(Token::Ident("declare_with_version")),
+ "error reading deprecated lints"
+ );
+ dst.push_str(&src[..searcher.pos() as usize]);
+ dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
+ for lint in deprecated {
+ write!(
+ dst,
+ " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n",
+ lint.version, lint.name, lint.reason,
+ )
+ .unwrap();
+ }
+ dst.push_str(
+ "]}\n\n\
#[rustfmt::skip]\n\
declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\
",
- );
- for lint in renamed {
- write!(
- dst,
- " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n",
- lint.version, lint.old_name, lint.new_name,
- )
- .unwrap();
- }
- dst.push_str("]}\n");
- UpdateStatus::from_changed(src != dst)
- }),
- ("tests/ui/deprecated.rs", &mut |_, src, dst| {
- dst.push_str(GENERATED_FILE_COMMENT);
- for lint in deprecated {
- writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
- }
- dst.push_str("\nfn main() {}\n");
- UpdateStatus::from_changed(src != dst)
- }),
- ("tests/ui/rename.rs", &mut move |_, src, dst| {
- let mut seen_lints = HashSet::new();
- dst.push_str(GENERATED_FILE_COMMENT);
- dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
- for lint in renamed {
- if seen_lints.insert(&lint.new_name) {
- writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
- }
- }
- seen_lints.clear();
- for lint in renamed {
- if seen_lints.insert(&lint.old_name) {
- writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
- }
- }
- dst.push_str("\nfn main() {}\n");
- UpdateStatus::from_changed(src != dst)
- }),
- ],
+ );
+ for lint in renamed {
+ write!(
+ dst,
+ " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n",
+ lint.version, lint.old_name, lint.new_name,
+ )
+ .unwrap();
+ }
+ dst.push_str("]}\n");
+ UpdateStatus::from_changed(src != dst)
+ },
);
+ updater.update_file_checked(
+ "cargo dev update_lints",
+ update_mode,
+ "tests/ui/deprecated.rs",
+ &mut |_, src, dst| {
+ dst.push_str(GENERATED_FILE_COMMENT);
+ for lint in deprecated {
+ writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
+ }
+ dst.push_str("\nfn main() {}\n");
+ UpdateStatus::from_changed(src != dst)
+ },
+ );
+ updater.update_file_checked(
+ "cargo dev update_lints",
+ update_mode,
+ "tests/ui/rename.rs",
+ &mut move |_, src, dst| {
+ let mut seen_lints = HashSet::new();
+ dst.push_str(GENERATED_FILE_COMMENT);
+ dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
+ for lint in renamed {
+ if seen_lints.insert(&lint.new_name) {
+ writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
+ }
+ }
+ seen_lints.clear();
+ for lint in renamed {
+ if seen_lints.insert(&lint.old_name) {
+ writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
+ }
+ }
+ dst.push_str("\nfn main() {}\n");
+ UpdateStatus::from_changed(src != dst)
+ },
+ );
+ for (crate_name, lints) in lints.iter().into_group_map_by(|&l| {
+ let Some(path::Component::Normal(name)) = l.path.components().next() else {
+ // All paths should start with `{crate_name}/src` when parsed from `find_lint_decls`
+ panic!("internal error: can't read crate name from path `{}`", l.path.display());
+ };
+ name
+ }) {
+ updater.update_file_checked(
+ "cargo dev update_lints",
+ update_mode,
+ Path::new(crate_name).join("src/lib.rs"),
+ &mut update_text_region_fn(
+ "// begin lints modules, do not remove this comment, it's used in `update_lints`\n",
+ "// end lints modules, do not remove this comment, it's used in `update_lints`",
+ |dst| {
+ for lint_mod in lints
+ .iter()
+ .filter(|l| !l.module.is_empty())
+ .map(|l| l.module.split_once("::").map_or(&*l.module, |x| x.0))
+ .sorted()
+ .dedup()
+ {
+ writeln!(dst, "mod {lint_mod};").unwrap();
+ }
+ },
+ ),
+ );
+ updater.update_file_checked(
+ "cargo dev update_lints",
+ update_mode,
+ Path::new(crate_name).join("src/declared_lints.rs"),
+ &mut |_, src, dst| {
+ dst.push_str(GENERATED_FILE_COMMENT);
+ dst.push_str("pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[\n");
+ for (module_path, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() {
+ if module_path.is_empty() {
+ writeln!(dst, " crate::{lint_name}_INFO,").unwrap();
+ } else {
+ writeln!(dst, " crate::{module_path}::{lint_name}_INFO,").unwrap();
+ }
+ }
+ dst.push_str("];\n");
+ UpdateStatus::from_changed(src != dst)
+ },
+ );
+ }
}
fn round_to_fifty(count: usize) -> usize {
@@ -187,13 +228,25 @@ pub struct RenamedLint {
pub fn find_lint_decls() -> Vec<Lint> {
let mut lints = Vec::with_capacity(1000);
let mut contents = String::new();
- for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) {
- parse_clippy_lint_decls(
- file.path(),
- File::open_read_to_cleared_string(file.path(), &mut contents),
- &module,
- &mut lints,
- );
+ for e in expect_action(fs::read_dir("."), ErrAction::Read, ".") {
+ let e = expect_action(e, ErrAction::Read, ".");
+ if !expect_action(e.file_type(), ErrAction::Read, ".").is_dir() {
+ continue;
+ }
+ let Ok(mut name) = e.file_name().into_string() else {
+ continue;
+ };
+ if name.starts_with("clippy_lints") && name != "clippy_lints_internal" {
+ name.push_str("/src");
+ for (file, module) in read_src_with_module(name.as_ref()) {
+ parse_clippy_lint_decls(
+ file.path(),
+ File::open_read_to_cleared_string(file.path(), &mut contents),
+ &module,
+ &mut lints,
+ );
+ }
+ }
}
lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
lints
@@ -205,7 +258,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirE
let e = expect_action(e, ErrAction::Read, src_root);
let path = e.path().as_os_str().as_encoded_bytes();
if let Some(path) = path.strip_suffix(b".rs")
- && let Some(path) = path.get("clippy_lints/src/".len()..)
+ && let Some(path) = path.get(src_root.as_os_str().len() + 1..)
{
if path == b"lib" {
Some((e, String::new()))
@@ -333,17 +386,13 @@ pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
/// Removes the line splices and surrounding quotes from a string literal
fn parse_str_lit(s: &str) -> String {
- let (s, mode) = if let Some(s) = s.strip_prefix("r") {
- (s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr)
- } else {
- (s, rustc_literal_escaper::Mode::Str)
- };
+ let s = s.strip_prefix("r").unwrap_or(s).trim_matches('#');
let s = s
.strip_prefix('"')
.and_then(|s| s.strip_suffix('"'))
.unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
let mut res = String::with_capacity(s.len());
- rustc_literal_escaper::unescape_str(s, |range, ch| {
+ rustc_literal_escaper::unescape_str(s, &mut |_, ch| {
if let Ok(ch) = ch {
res.push(ch);
}
diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs
index c4808b7..89962a1 100644
--- a/src/tools/clippy/clippy_dev/src/utils.rs
+++ b/src/tools/clippy/clippy_dev/src/utils.rs
@@ -383,21 +383,6 @@ pub fn update_file_checked(
self.update_file_checked_inner(tool, mode, path.as_ref(), update);
}
- #[expect(clippy::type_complexity)]
- pub fn update_files_checked(
- &mut self,
- tool: &str,
- mode: UpdateMode,
- files: &mut [(
- impl AsRef<Path>,
- &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus,
- )],
- ) {
- for (path, update) in files {
- self.update_file_checked_inner(tool, mode, path.as_ref(), update);
- }
- }
-
pub fn update_file(
&mut self,
path: impl AsRef<Path>,
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 39e4e2e..c03cc99 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
-version = "0.1.89"
+version = "0.1.90"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -13,6 +13,7 @@
cargo_metadata = "0.18"
clippy_config = { path = "../clippy_config" }
clippy_utils = { path = "../clippy_utils" }
+declare_clippy_lint = { path = "../declare_clippy_lint" }
itertools = "0.12"
quine-mc_cluskey = "0.2"
regex-syntax = "0.8"
diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
index 58e5112..b8f93ee 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
@@ -1,10 +1,10 @@
use super::INLINE_ALWAYS;
use clippy_utils::diagnostics::span_lint;
-use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr};
+use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr};
use rustc_hir::Attribute;
use rustc_lint::LateContext;
-use rustc_span::symbol::Symbol;
use rustc_span::Span;
+use rustc_span::symbol::Symbol;
pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
if span.from_expansion() {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index 9a12429..91c2dc7 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -207,7 +207,7 @@
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of the `#[allow]` attribute and suggests replacing it with
- /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
+ /// the `#[expect]` attribute (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
///
/// This lint only warns outer attributes (`#[allow]`), as inner attributes
/// (`#![allow]`) are usually used to enable or disable lints on a global scale.
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index a5ce213..7b66f91 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -46,11 +46,13 @@ pub(super) fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> b
}
fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool {
- block.stmts.first().map_or(
- block
- .expr
- .as_ref()
- .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)),
+ block.stmts.first().map_or_else(
+ || {
+ block
+ .expr
+ .as_ref()
+ .is_some_and(|e| is_relevant_expr(cx, typeck_results, e))
+ },
|stmt| match &stmt.kind {
StmtKind::Let(_) => true,
StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
index 7cde007..70c9c45 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
@@ -2,9 +2,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed, is_mutable};
+use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable};
use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, ExprKind, UnOp};
+use rustc_hir::{BorrowKind, Expr, ExprKind, Node, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::Mutability;
use rustc_middle::ty;
@@ -48,7 +48,7 @@
declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]);
impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, addrof_target) = e.kind
&& let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind
&& !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
@@ -76,6 +76,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
&& let e_ty = cx.typeck_results().expr_ty_adjusted(e)
// check if the reference is coercing to a mutable reference
&& (!matches!(e_ty.kind(), ty::Ref(_, _, Mutability::Mut)) || is_mutable(cx, deref_target))
+ // If the new borrow might be itself borrowed mutably and the original reference is not a temporary
+ // value, do not propose to use it directly.
+ && (is_expr_temporary_value(cx, deref_target) || !potentially_bound_to_mutable_ref(cx, e))
&& let Some(deref_text) = deref_target.span.get_source_text(cx)
{
span_lint_and_then(
@@ -110,3 +113,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
}
}
}
+
+/// Checks if `expr` is used as part of a `let` statement containing a `ref mut` binding.
+fn potentially_bound_to_mutable_ref<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+ matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::LetStmt(let_stmt)
+ if let_stmt.pat.contains_explicit_ref_binding() == Some(Mutability::Mut))
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 9a1ad8a..a70bd88 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -168,7 +168,7 @@ fn pow_call_result_sign(cx: &LateContext<'_>, base: &Expr<'_>, exponent: &Expr<'
// Rust's integer pow() functions take an unsigned exponent.
let exponent_val = get_const_unsigned_int_eval(cx, exponent, None);
- let exponent_is_even = exponent_val.map(|val| val % 2 == 0);
+ let exponent_is_even = exponent_val.map(|val| val.is_multiple_of(2));
match (base_sign, exponent_is_even) {
// Non-negative bases always return non-negative results, ignoring overflow.
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index 7f6ecea..1854d86 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -1,13 +1,16 @@
use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block, snippet_block_with_applicability};
+use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
+use clippy_utils::{span_contains_non_whitespace, tokenize_with_text};
use rustc_ast::BinOpKind;
use rustc_errors::Applicability;
use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
+use rustc_lexer::TokenKind;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
-use rustc_span::Span;
+use rustc_span::source_map::SourceMap;
+use rustc_span::{BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@@ -90,35 +93,74 @@ pub fn new(conf: &'static Conf) -> Self {
}
}
- fn check_collapsible_else_if(cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) {
- if !block_starts_with_comment(cx, else_block)
- && let Some(else_) = expr_block(else_block)
+ fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) {
+ if let Some(else_) = expr_block(else_block)
&& cx.tcx.hir_attrs(else_.hir_id).is_empty()
&& !else_.span.from_expansion()
- && let ExprKind::If(..) = else_.kind
+ && let ExprKind::If(else_if_cond, ..) = else_.kind
+ && !block_starts_with_significant_tokens(cx, else_block, else_, self.lint_commented_code)
{
- // Prevent "elseif"
- // Check that the "else" is followed by whitespace
- let up_to_else = then_span.between(else_block.span);
- let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
- !c.is_whitespace()
- } else {
- false
- };
-
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
+ span_lint_and_then(
cx,
COLLAPSIBLE_ELSE_IF,
else_block.span,
"this `else { if .. }` block can be collapsed",
- "collapse nested if block",
- format!(
- "{}{}",
- if requires_space { " " } else { "" },
- snippet_block_with_applicability(cx, else_.span, "..", Some(else_block.span), &mut applicability)
- ),
- applicability,
+ |diag| {
+ let up_to_else = then_span.between(else_block.span);
+ let else_before_if = else_.span.shrink_to_lo().with_hi(else_if_cond.span.lo() - BytePos(1));
+ if self.lint_commented_code
+ && let Some(else_keyword_span) =
+ span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else")
+ && let Some(else_if_keyword_span) =
+ span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if")
+ {
+ let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span();
+ let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span();
+ let else_closing_bracket = {
+ let end = else_block.span.shrink_to_hi();
+ end.with_lo(end.lo() - BytePos(1))
+ .with_leading_whitespace(cx)
+ .into_span()
+ };
+ let sugg = vec![
+ // Remove the outer else block `else`
+ (else_keyword_span, String::new()),
+ // Replace the inner `if` by `else if`
+ (else_if_keyword_span, String::from("else if")),
+ // Remove the outer else block `{`
+ (else_open_bracket, String::new()),
+ // Remove the outer else block '}'
+ (else_closing_bracket, String::new()),
+ ];
+ diag.multipart_suggestion("collapse nested if block", sugg, Applicability::MachineApplicable);
+ return;
+ }
+
+ // Prevent "elseif"
+ // Check that the "else" is followed by whitespace
+ let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
+ !c.is_whitespace()
+ } else {
+ false
+ };
+ let mut applicability = Applicability::MachineApplicable;
+ diag.span_suggestion(
+ else_block.span,
+ "collapse nested if block",
+ format!(
+ "{}{}",
+ if requires_space { " " } else { "" },
+ snippet_block_with_applicability(
+ cx,
+ else_.span,
+ "..",
+ Some(else_block.span),
+ &mut applicability
+ )
+ ),
+ applicability,
+ );
+ },
);
}
}
@@ -130,7 +172,7 @@ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check:
&& self.eligible_condition(cx, check_inner)
&& let ctxt = expr.span.ctxt()
&& inner.span.ctxt() == ctxt
- && (self.lint_commented_code || !block_starts_with_comment(cx, then))
+ && !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code)
{
span_lint_and_then(
cx,
@@ -141,7 +183,7 @@ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check:
let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span();
let then_closing_bracket = {
let end = then.span.shrink_to_hi();
- end.with_lo(end.lo() - rustc_span::BytePos(1))
+ end.with_lo(end.lo() - BytePos(1))
.with_leading_whitespace(cx)
.into_span()
};
@@ -179,7 +221,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let Some(else_) = else_
&& let ExprKind::Block(else_, None) = else_.kind
{
- Self::check_collapsible_else_if(cx, then.span, else_);
+ self.check_collapsible_else_if(cx, then.span, else_);
} else if else_.is_none()
&& self.eligible_condition(cx, cond)
&& let ExprKind::Block(then, None) = then.kind
@@ -190,12 +232,16 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
}
}
-fn block_starts_with_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
- // We trim all opening braces and whitespaces and then check if the next string is a comment.
- let trimmed_block_text = snippet_block(cx, block.span, "..", None)
- .trim_start_matches(|c: char| c.is_whitespace() || c == '{')
- .to_owned();
- trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
+// Check that nothing significant can be found but whitespaces between the initial `{` of `block`
+// and the beginning of `stop_at`.
+fn block_starts_with_significant_tokens(
+ cx: &LateContext<'_>,
+ block: &Block<'_>,
+ stop_at: &Expr<'_>,
+ lint_commented_code: bool,
+) -> bool {
+ let span = block.span.split_at(1).1.until(stop_at.span);
+ span_contains_non_whitespace(cx, span, lint_commented_code)
}
/// If `block` is a block with either one expression or a statement containing an expression,
@@ -226,3 +272,16 @@ fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> {
vec![]
}
}
+
+fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Span> {
+ let snippet = sm.span_to_snippet(span).ok()?;
+ tokenize_with_text(&snippet)
+ .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword))
+ .map(|(_, _, inner)| {
+ span.split_at(u32::try_from(inner.start).unwrap())
+ .1
+ .split_at(u32::try_from(inner.end - inner.start).unwrap())
+ .0
+ })
+ .next()
+}
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 5ef7266..2791869 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -11,7 +11,7 @@
use core::iter;
use core::ops::ControlFlow;
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind, intravisit};
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass;
@@ -295,7 +295,7 @@ fn lint_branches_sharing_code<'tcx>(
sugg,
Applicability::Unspecified,
);
- if !cx.typeck_results().expr_ty(expr).is_unit() {
+ if is_expr_parent_assignment(cx, expr) || !cx.typeck_results().expr_ty(expr).is_unit() {
diag.note("the end suggestion probably needs some adjustments to use the expression result correctly");
}
}
@@ -660,3 +660,17 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
);
}
}
+
+fn is_expr_parent_assignment(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ let parent = cx.tcx.parent_hir_node(expr.hir_id);
+ if let Node::LetStmt(LetStmt { init: Some(e), .. })
+ | Node::Expr(Expr {
+ kind: ExprKind::Assign(_, e, _),
+ ..
+ }) = parent
+ {
+ return e.hir_id == expr.hir_id;
+ }
+
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
deleted file mode 100644
index 9f82f87..0000000
--- a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-#[macro_export]
-#[allow(clippy::crate_in_macro_def)]
-macro_rules! declare_clippy_lint {
- (@
- $(#[doc = $lit:literal])*
- pub $lint_name:ident,
- $level:ident,
- $lintcategory:expr,
- $desc:literal,
- $version_expr:expr,
- $version_lit:literal
- $(, $eval_always: literal)?
- ) => {
- rustc_session::declare_tool_lint! {
- $(#[doc = $lit])*
- #[clippy::version = $version_lit]
- pub clippy::$lint_name,
- $level,
- $desc,
- report_in_external_macro:true
- $(, @eval_always = $eval_always)?
- }
-
- pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo {
- lint: &$lint_name,
- category: $lintcategory,
- explanation: concat!($($lit,"\n",)*),
- location: concat!(file!(), "#L", line!()),
- version: $version_expr
- };
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- restriction,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Allow, crate::LintCategory::Restriction, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- style,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Warn, crate::LintCategory::Style, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- correctness,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Deny, crate::LintCategory::Correctness, $desc,
- Some($version), $version
- $(, $eval_always)?
-
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- perf,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Warn, crate::LintCategory::Perf, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- complexity,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Warn, crate::LintCategory::Complexity, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- suspicious,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- nursery,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Allow, crate::LintCategory::Nursery, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- pedantic,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
- (
- $(#[doc = $lit:literal])*
- #[clippy::version = $version:literal]
- pub $lint_name:ident,
- cargo,
- $desc:literal
- $(, @eval_always = $eval_always: literal)?
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Allow, crate::LintCategory::Cargo, $desc,
- Some($version), $version
- $(, $eval_always)?
- }
- };
-}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 1e3907d..c3f8e02 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -2,7 +2,7 @@
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.
-pub static LINTS: &[&crate::LintInfo] = &[
+pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
crate::absolute_paths::ABSOLUTE_PATHS_INFO,
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
crate::approx_const::APPROX_CONSTANT_INFO,
@@ -112,6 +112,7 @@
crate::disallowed_names::DISALLOWED_NAMES_INFO,
crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
crate::disallowed_types::DISALLOWED_TYPES_INFO,
+ crate::doc::DOC_BROKEN_LINK_INFO,
crate::doc::DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS_INFO,
crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO,
crate::doc::DOC_LAZY_CONTINUATION_INFO,
@@ -590,6 +591,7 @@
crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
crate::operators::INEFFECTIVE_BIT_MASK_INFO,
crate::operators::INTEGER_DIVISION_INFO,
+ crate::operators::MANUAL_IS_MULTIPLE_OF_INFO,
crate::operators::MANUAL_MIDPOINT_INFO,
crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
crate::operators::MODULO_ARITHMETIC_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 9814d4f..d55aeae 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -40,6 +40,9 @@
/// # When using an inline table, can add a `reason` for why the macro
/// # is disallowed.
/// { path = "serde::Serialize", reason = "no serializing" },
+ /// # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,
+ /// # it will be silently ignored
+ /// { path = "std::invalid_macro", reason = "use alternative instead", allow-invalid = true }
/// ]
/// ```
/// ```no_run
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index fb970e1..8c06743 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -34,6 +34,9 @@
/// { path = "std::vec::Vec::leak", reason = "no leaking memory" },
/// # Can also add a `replacement` that will be offered as a suggestion.
/// { path = "std::sync::Mutex::new", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex::new" },
+ /// # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,
+ /// # it will be silently ignored
+ /// { path = "std::fs::InvalidPath", reason = "use alternative instead", allow-invalid = true },
/// ]
/// ```
///
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 7875cdd..9a82327 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -35,6 +35,9 @@
/// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
/// # Can also add a `replacement` that will be offered as a suggestion.
/// { path = "std::sync::Mutex", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex" },
+ /// # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,
+ /// # it will be silently ignored
+ /// { path = "std::invalid::Type", reason = "use alternative instead", allow-invalid = true }
/// ]
/// ```
///
diff --git a/src/tools/clippy/clippy_lints/src/doc/broken_link.rs b/src/tools/clippy/clippy_lints/src/doc/broken_link.rs
new file mode 100644
index 0000000..4af1051
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/broken_link.rs
@@ -0,0 +1,83 @@
+use clippy_utils::diagnostics::span_lint;
+use pulldown_cmark::BrokenLink as PullDownBrokenLink;
+use rustc_lint::LateContext;
+use rustc_resolve::rustdoc::{DocFragment, source_span_for_markdown_range};
+use rustc_span::{BytePos, Pos, Span};
+
+use super::DOC_BROKEN_LINK;
+
+/// Scan and report broken link on documents.
+/// It ignores false positives detected by `pulldown_cmark`, and only
+/// warns users when the broken link is consider a URL.
+// NOTE: We don't check these other cases because
+// rustdoc itself will check and warn about it:
+// - When a link url is broken across multiple lines in the URL path part
+// - When a link tag is missing the close parenthesis character at the end.
+// - When a link has whitespace within the url link.
+pub fn check(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragments: &[DocFragment]) {
+ warn_if_broken_link(cx, bl, doc, fragments);
+}
+
+fn warn_if_broken_link(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragments: &[DocFragment]) {
+ if let Some((span, _)) = source_span_for_markdown_range(cx.tcx, doc, &bl.span, fragments) {
+ let mut len = 0;
+
+ // grab raw link data
+ let (_, raw_link) = doc.split_at(bl.span.start);
+
+ // strip off link text part
+ let raw_link = match raw_link.split_once(']') {
+ None => return,
+ Some((prefix, suffix)) => {
+ len += prefix.len() + 1;
+ suffix
+ },
+ };
+
+ let raw_link = match raw_link.split_once('(') {
+ None => return,
+ Some((prefix, suffix)) => {
+ if !prefix.is_empty() {
+ // there is text between ']' and '(' chars, so it is not a valid link
+ return;
+ }
+ len += prefix.len() + 1;
+ suffix
+ },
+ };
+
+ if raw_link.starts_with("(http") {
+ // reduce chances of false positive reports
+ // by limiting this checking only to http/https links.
+ return;
+ }
+
+ for c in raw_link.chars() {
+ if c == ')' {
+ // it is a valid link
+ return;
+ }
+
+ if c == '\n' {
+ report_broken_link(cx, span, len);
+ break;
+ }
+
+ len += 1;
+ }
+ }
+}
+
+fn report_broken_link(cx: &LateContext<'_>, frag_span: Span, offset: usize) {
+ let start = frag_span.lo();
+ let end = start + BytePos::from_usize(offset);
+
+ let span = Span::new(start, end, frag_span.ctxt(), frag_span.parent());
+
+ span_lint(
+ cx,
+ DOC_BROKEN_LINK,
+ span,
+ "possible broken doc link: broken across multiple lines",
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
index d3c3968..3330cc5 100644
--- a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
@@ -49,11 +49,7 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
.filter(|attr| attr.span().overlaps(this_fragment.span))
.rev()
.find_map(|attr| {
- Some((
- attr,
- attr.doc_str_and_comment_kind()?,
- attr.doc_resolution_scope()?,
- ))
+ Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?))
})
.unwrap();
let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) {
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index d38588b..5ea55e1 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -24,6 +24,7 @@
use std::ops::Range;
use url::Url;
+mod broken_link;
mod doc_comment_double_space_linebreaks;
mod doc_suspicious_footnotes;
mod include_in_doc_without_cfg;
@@ -294,6 +295,34 @@
declare_clippy_lint! {
/// ### What it does
+ /// Checks the doc comments have unbroken links, mostly caused
+ /// by bad formatted links such as broken across multiple lines.
+ ///
+ /// ### Why is this bad?
+ /// Because documentation generated by rustdoc will be broken
+ /// since expected links won't be links and just text.
+ ///
+ /// ### Examples
+ /// This link is broken:
+ /// ```no_run
+ /// /// [example of a bad link](https://
+ /// /// github.com/rust-lang/rust-clippy/)
+ /// pub fn do_something() {}
+ /// ```
+ ///
+ /// It shouldn't be broken across multiple lines to work:
+ /// ```no_run
+ /// /// [example of a good link](https://github.com/rust-lang/rust-clippy/)
+ /// pub fn do_something() {}
+ /// ```
+ #[clippy::version = "1.84.0"]
+ pub DOC_BROKEN_LINK,
+ pedantic,
+ "broken document link"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Checks for the doc comments of publicly visible
/// safe functions and traits and warns if there is a `# Safety` section.
///
@@ -656,6 +685,7 @@ pub fn new(conf: &'static Conf) -> Self {
impl_lint_pass!(Documentation => [
DOC_LINK_CODE,
DOC_LINK_WITH_QUOTES,
+ DOC_BROKEN_LINK,
DOC_MARKDOWN,
DOC_NESTED_REFDEFS,
MISSING_SAFETY_DOC,
@@ -786,9 +816,9 @@ struct DocHeaders {
/// back in the various late lint pass methods if they need the final doc headers, like "Safety" or
/// "Panics" sections.
fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
- /// We don't want the parser to choke on intra doc links. Since we don't
- /// actually care about rendering them, just pretend that all broken links
- /// point to a fake address.
+ // We don't want the parser to choke on intra doc links. Since we don't
+ // actually care about rendering them, just pretend that all broken links
+ // point to a fake address.
#[expect(clippy::unnecessary_wraps)] // we're following a type signature
fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
Some(("fake".into(), "fake".into()))
@@ -828,14 +858,12 @@ fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowSt
return Some(DocHeaders::default());
}
- let mut cb = fake_broken_link_callback;
-
check_for_code_clusters(
cx,
pulldown_cmark::Parser::new_with_broken_link_callback(
&doc,
main_body_opts() - Options::ENABLE_SMART_PUNCTUATION,
- Some(&mut cb),
+ Some(&mut fake_broken_link_callback),
)
.into_offset_iter(),
&doc,
@@ -845,9 +873,17 @@ fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowSt
},
);
+ // NOTE: check_doc uses it own cb function,
+ // to avoid causing duplicated diagnostics for the broken link checker.
+ let mut full_fake_broken_link_callback = |bl: BrokenLink<'_>| -> Option<(CowStr<'_>, CowStr<'_>)> {
+ broken_link::check(cx, &bl, &doc, &fragments);
+ Some(("fake".into(), "fake".into()))
+ };
+
// disable smart punctuation to pick up ['link'] more easily
let opts = main_body_opts() - Options::ENABLE_SMART_PUNCTUATION;
- let parser = pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut cb));
+ let parser =
+ pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut full_fake_broken_link_callback));
Some(check_doc(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
index 7ba11c2..74283d7 100644
--- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -71,6 +71,7 @@ fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec
if !ignore {
get_test_spans(&item, *ident, &mut test_attr_spans);
}
+
let is_async = matches!(sig.header.coroutine_kind, Some(CoroutineKind::Async { .. }));
let returns_nothing = match &sig.decl.output {
FnRetTy::Default(..) => true,
@@ -89,9 +90,14 @@ fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec
// Another function was found; this case is ignored for needless_doctest_main
ItemKind::Fn(fn_) => {
eligible = false;
- if !ignore {
- get_test_spans(&item, fn_.ident, &mut test_attr_spans);
+ if ignore {
+ // If ignore is active invalidating one lint,
+ // and we already found another function thus
+ // invalidating the other one, we have no
+ // business continuing.
+ return (false, test_attr_spans);
}
+ get_test_spans(&item, fn_.ident, &mut test_attr_spans);
},
// Tests with one of these items are ignored
ItemKind::Static(..)
@@ -104,7 +110,10 @@ fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec
},
Ok(None) => break,
Err(e) => {
- e.cancel();
+ // See issue #15041. When calling `.cancel()` on the `Diag`, Clippy will unexpectedly panic
+ // when the `Diag` is unwinded. Meanwhile, we can just call `.emit()`, since the `DiagCtxt`
+ // is just a sink, nothing will be printed.
+ e.emit();
return (false, test_attr_spans);
},
}
@@ -119,6 +128,18 @@ fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec
let trailing_whitespace = text.len() - text.trim_end().len();
+ // We currently only test for "fn main". Checking for the real
+ // entrypoint (with tcx.entry_fn(())) in each block would be unnecessarily
+ // expensive, as those are probably intended and relevant. Same goes for
+ // macros and other weird ways of declaring a main function.
+ //
+ // Also, as we only check for attribute names and don't do macro expansion,
+ // we can check only for #[test]
+
+ if !((text.contains("main") && text.contains("fn")) || text.contains("#[test]")) {
+ return;
+ }
+
// Because of the global session, we need to create a new session in a different thread with
// the edition we need.
let text = text.to_owned();
diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
index 0c5f8bb..3bd7485 100644
--- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
@@ -10,7 +10,7 @@
use rustc_lexer::TokenKind;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_session::impl_lint_pass;
-use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw};
+use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw, sym};
declare_clippy_lint! {
/// ### What it does
@@ -129,10 +129,55 @@ struct Stop {
kind: StopKind,
first: usize,
last: usize,
+ name: Option<Symbol>,
}
impl Stop {
- fn convert_to_inner(&self) -> (Span, String) {
+ fn is_outer_attr_only(&self) -> bool {
+ let Some(name) = self.name else {
+ return false;
+ };
+ // Check if the attribute only has effect when as an outer attribute
+ // The below attributes are collected from the builtin attributes of The Rust Reference
+ // https://doc.rust-lang.org/reference/attributes.html#r-attributes.builtin
+ // And the comments below are from compiler errors and warnings
+ matches!(
+ name,
+ // Cannot be used at crate level
+ sym::repr | sym::test | sym::derive | sym::automatically_derived | sym::path | sym::global_allocator |
+ // Only has an effect on macro definitions
+ sym::macro_export |
+ // Only be applied to trait definitions
+ sym::on_unimplemented |
+ // Only be placed on trait implementations
+ sym::do_not_recommend |
+ // Only has an effect on items
+ sym::ignore | sym::should_panic | sym::proc_macro | sym::proc_macro_derive | sym::proc_macro_attribute |
+ // Has no effect when applied to a module
+ sym::must_use |
+ // Should be applied to a foreign function or static
+ sym::link_name | sym::link_ordinal | sym::link_section |
+ // Should be applied to an `extern crate` item
+ sym::no_link |
+ // Should be applied to a free function, impl method or static
+ sym::export_name | sym::no_mangle |
+ // Should be applied to a `static` variable
+ sym::used |
+ // Should be applied to function or closure
+ sym::inline |
+ // Should be applied to a function definition
+ sym::cold | sym::target_feature | sym::track_caller | sym::instruction_set |
+ // Should be applied to a struct or enum
+ sym::non_exhaustive |
+ // Note: No any warning when it as an inner attribute, but it has no effect
+ sym::panic_handler
+ )
+ }
+
+ fn convert_to_inner(&self) -> Option<(Span, String)> {
+ if self.is_outer_attr_only() {
+ return None;
+ }
let inner = match self.kind {
// #![...]
StopKind::Attr => InnerSpan::new(1, 1),
@@ -140,7 +185,7 @@ fn convert_to_inner(&self) -> (Span, String) {
// ^ ^
StopKind::Doc(_) => InnerSpan::new(2, 3),
};
- (self.span.from_inner(inner), "!".into())
+ Some((self.span.from_inner(inner), "!".into()))
}
fn comment_out(&self, cx: &EarlyContext<'_>, suggestions: &mut Vec<(Span, String)>) {
@@ -177,6 +222,7 @@ fn from_attr(cx: &EarlyContext<'_>, attr: &Attribute) -> Option<Self> {
},
first: file.lookup_line(file.relative_position(lo))?,
last: file.lookup_line(file.relative_position(hi))?,
+ name: attr.name(),
})
}
}
@@ -356,6 +402,12 @@ fn suggest_inner(&self, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>
if let Some(parent) = self.items.iter().rev().nth(1)
&& (parent.kind == "module" || parent.kind == "crate")
&& parent.mod_items == Some(id)
+ && let suggestions = gaps
+ .iter()
+ .flat_map(|gap| gap.prev_chunk)
+ .filter_map(Stop::convert_to_inner)
+ .collect::<Vec<_>>()
+ && !suggestions.is_empty()
{
let desc = if parent.kind == "module" {
"parent module"
@@ -367,10 +419,7 @@ fn suggest_inner(&self, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>
StopKind::Attr => format!("if the attribute should apply to the {desc} use an inner attribute"),
StopKind::Doc(_) => format!("if the comment should document the {desc} use an inner doc comment"),
},
- gaps.iter()
- .flat_map(|gap| gap.prev_chunk)
- .map(Stop::convert_to_inner)
- .collect(),
+ suggestions,
Applicability::MaybeIncorrect,
);
}
@@ -425,6 +474,7 @@ fn check_item_kind(
first: line.line,
// last doesn't need to be accurate here, we don't compare it with anything
last: line.line,
+ name: None,
});
}
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index b0077a9..0288747 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::higher::VecArgs;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::ty::get_type_diagnostic_name;
@@ -109,14 +109,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
{
let vec_crate = if is_no_std_crate(cx) { "alloc" } else { "std" };
// replace `|| vec![]` with `Vec::new`
- span_lint_and_sugg(
+ span_lint_hir_and_then(
cx,
REDUNDANT_CLOSURE,
+ expr.hir_id,
expr.span,
"redundant closure",
- "replace the closure with `Vec::new`",
- format!("{vec_crate}::vec::Vec::new"),
- Applicability::MachineApplicable,
+ |diag| {
+ diag.span_suggestion(
+ expr.span,
+ "replace the closure with `Vec::new`",
+ format!("{vec_crate}::vec::Vec::new"),
+ Applicability::MachineApplicable,
+ );
+ },
);
}
// skip `foo(|| macro!())`
@@ -198,41 +204,48 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
// For now ignore all callee types which reference a type parameter.
&& !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
{
- span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
- if let Some(mut snippet) = snippet_opt(cx, callee.span) {
- if path_to_local(callee).is_some_and(|l| {
- // FIXME: Do we really need this `local_used_in` check?
- // Isn't it checking something like... `callee(callee)`?
- // If somehow this check is needed, add some test for it,
- // 'cuz currently nothing changes after deleting this check.
- local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
- }) {
- match cx
- .tcx
- .infer_ctxt()
- .build(cx.typing_mode())
- .err_ctxt()
- .type_implements_fn_trait(
- cx.param_env,
- Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
- ty::PredicatePolarity::Positive,
- ) {
- // Mutable closure is used after current expr; we cannot consume it.
- Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
- Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
- snippet = format!("&{snippet}");
- },
- _ => (),
+ span_lint_hir_and_then(
+ cx,
+ REDUNDANT_CLOSURE,
+ expr.hir_id,
+ expr.span,
+ "redundant closure",
+ |diag| {
+ if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+ if path_to_local(callee).is_some_and(|l| {
+ // FIXME: Do we really need this `local_used_in` check?
+ // Isn't it checking something like... `callee(callee)`?
+ // If somehow this check is needed, add some test for it,
+ // 'cuz currently nothing changes after deleting this check.
+ local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
+ }) {
+ match cx
+ .tcx
+ .infer_ctxt()
+ .build(cx.typing_mode())
+ .err_ctxt()
+ .type_implements_fn_trait(
+ cx.param_env,
+ Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+ ty::PredicatePolarity::Positive,
+ ) {
+ // Mutable closure is used after current expr; we cannot consume it.
+ Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
+ Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
+ snippet = format!("&{snippet}");
+ },
+ _ => (),
+ }
}
+ diag.span_suggestion(
+ expr.span,
+ "replace the closure with the function itself",
+ snippet,
+ Applicability::MachineApplicable,
+ );
}
- diag.span_suggestion(
- expr.span,
- "replace the closure with the function itself",
- snippet,
- Applicability::MachineApplicable,
- );
- }
- });
+ },
+ );
}
},
ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
@@ -245,9 +258,10 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
Some(span) => format!("::{}", snippet_with_applicability(cx, span, "<..>", &mut app)),
None => String::new(),
};
- span_lint_and_then(
+ span_lint_hir_and_then(
cx,
REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+ expr.hir_id,
expr.span,
"redundant closure",
|diag| {
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 1fb0e4d..86d9038 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -76,7 +76,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
"exported enums should not be exhaustive",
[].as_slice(),
),
- ItemKind::Struct(_, _, v) => (
+ ItemKind::Struct(_, _, v) if v.fields().iter().all(|f| f.default.is_none()) => (
EXHAUSTIVE_STRUCTS,
"exported structs should not be exhaustive",
v.fields(),
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 3c7e83b..b3c9e86 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -5,14 +5,13 @@
eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate,
numeric_literal, peel_blocks, sugg, sym,
};
+use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
-
-use rustc_ast::ast;
use std::f32::consts as f32_consts;
use std::f64::consts as f64_consts;
use sugg::Sugg;
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index c0c23e2..d959981 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -14,9 +14,9 @@
use clippy_utils::ty::is_must_use_ty;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{return_ty, trait_ref_of_method};
-use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
-use rustc_span::Symbol;
use rustc_attr_data_structures::{AttributeKind, find_attr};
+use rustc_span::Symbol;
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use core::ops::ControlFlow;
@@ -34,7 +34,17 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
if let Some((attr_span, reason)) = attr {
- check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig);
+ check_needless_must_use(
+ cx,
+ sig.decl,
+ item.owner_id,
+ item.span,
+ fn_header_span,
+ *attr_span,
+ *reason,
+ attrs,
+ sig,
+ );
} else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) {
check_must_use_candidate(
cx,
@@ -54,9 +64,20 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir_attrs(item.hir_id());
- let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
+ let attr =
+ find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
if let Some((attr_span, reason)) = attr {
- check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig);
+ check_needless_must_use(
+ cx,
+ sig.decl,
+ item.owner_id,
+ item.span,
+ fn_header_span,
+ *attr_span,
+ *reason,
+ attrs,
+ sig,
+ );
} else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() {
check_must_use_candidate(
cx,
@@ -77,9 +98,20 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir_attrs(item.hir_id());
- let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
+ let attr =
+ find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
if let Some((attr_span, reason)) = attr {
- check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig);
+ check_needless_must_use(
+ cx,
+ sig.decl,
+ item.owner_id,
+ item.span,
+ fn_header_span,
+ *attr_span,
+ *reason,
+ attrs,
+ sig,
+ );
} else if let hir::TraitFn::Provided(eid) = *eid {
let body = cx.tcx.hir_body(eid);
if attr.is_none() && is_public && !is_proc_macro(attrs) {
@@ -121,12 +153,7 @@ fn check_needless_must_use(
fn_header_span,
"this unit-returning function has a `#[must_use]` attribute",
|diag| {
- diag.span_suggestion(
- attr_span,
- "remove the attribute",
- "",
- Applicability::MachineApplicable,
- );
+ diag.span_suggestion(attr_span, "remove the attribute", "", Applicability::MachineApplicable);
},
);
} else {
diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs
index 45f9aa0..ab7a965 100644
--- a/src/tools/clippy/clippy_lints/src/if_not_else.rs
+++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::consts::is_zero_integer_const;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::is_else_clause;
use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet};
@@ -48,13 +48,6 @@
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
-fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
- if let Some(value) = ConstEvalCtxt::new(cx).eval_simple(expr) {
- return Constant::Int(0) == value;
- }
- false
-}
-
impl LateLintPass<'_> for IfNotElse {
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
if let ExprKind::If(cond, cond_inner, Some(els)) = e.kind
@@ -68,7 +61,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
),
// Don't lint on `… != 0`, as these are likely to be bit tests.
// For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order.
- ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_const(rhs, cx) => (
+ ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_integer_const(cx, rhs) => (
"unnecessary `!=` operation",
"change to `==` and swap the blocks of the `if`/`else`",
),
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 617c006..ffe6ad1 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::DiagExt;
-use rustc_attr_data_structures::{find_attr, AttributeKind};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_errors::Applicability;
use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -33,10 +33,10 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
&& let Some(attr_span) = find_attr!(cx
- .tcx
- .hir_attrs(item.hir_id()),
- AttributeKind::Inline(_, span) => *span
- )
+ .tcx
+ .hir_attrs(item.hir_id()),
+ AttributeKind::Inline(_, span) => *span
+ )
{
span_lint_and_then(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index be9142b..96a6dee 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -59,10 +59,10 @@
extern crate thin_vec;
#[macro_use]
-mod declare_clippy_lint;
+extern crate clippy_utils;
#[macro_use]
-extern crate clippy_utils;
+extern crate declare_clippy_lint;
mod utils;
@@ -411,108 +411,9 @@
use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation};
use clippy_utils::macros::FormatArgsStorage;
use rustc_data_structures::fx::FxHashSet;
-use rustc_lint::{Lint, LintId};
+use rustc_lint::Lint;
use utils::attr_collector::{AttrCollector, AttrStorage};
-#[derive(Default)]
-struct RegistrationGroups {
- all: Vec<LintId>,
- cargo: Vec<LintId>,
- complexity: Vec<LintId>,
- correctness: Vec<LintId>,
- nursery: Vec<LintId>,
- pedantic: Vec<LintId>,
- perf: Vec<LintId>,
- restriction: Vec<LintId>,
- style: Vec<LintId>,
- suspicious: Vec<LintId>,
-}
-
-impl RegistrationGroups {
- #[rustfmt::skip]
- fn register(self, store: &mut rustc_lint::LintStore) {
- store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
- store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
- store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
- store.register_group(true, "clippy::correctness", Some("clippy_correctness"), self.correctness);
- store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
- store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
- store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
- store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction);
- store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
- store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum LintCategory {
- Cargo,
- Complexity,
- Correctness,
- Nursery,
- Pedantic,
- Perf,
- Restriction,
- Style,
- Suspicious,
-}
-
-#[allow(clippy::enum_glob_use)]
-use LintCategory::*;
-
-impl LintCategory {
- fn is_all(self) -> bool {
- matches!(self, Correctness | Suspicious | Style | Complexity | Perf)
- }
-
- fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> {
- match self {
- Cargo => &mut groups.cargo,
- Complexity => &mut groups.complexity,
- Correctness => &mut groups.correctness,
- Nursery => &mut groups.nursery,
- Pedantic => &mut groups.pedantic,
- Perf => &mut groups.perf,
- Restriction => &mut groups.restriction,
- Style => &mut groups.style,
- Suspicious => &mut groups.suspicious,
- }
- }
-}
-
-pub struct LintInfo {
- /// Double reference to maintain pointer equality
- pub lint: &'static &'static Lint,
- category: LintCategory,
- pub explanation: &'static str,
- /// e.g. `clippy_lints/src/absolute_paths.rs#43`
- pub location: &'static str,
- pub version: Option<&'static str>,
-}
-
-impl LintInfo {
- /// Returns the lint name in lowercase without the `clippy::` prefix
- #[allow(clippy::missing_panics_doc)]
- pub fn name_lower(&self) -> String {
- self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase()
- }
-
- /// Returns the name of the lint's category in lowercase (`style`, `pedantic`)
- pub fn category_str(&self) -> &'static str {
- match self.category {
- Cargo => "cargo",
- Complexity => "complexity",
- Correctness => "correctness",
- Nursery => "nursery",
- Pedantic => "pedantic",
- Perf => "perf",
- Restriction => "restriction",
- Style => "style",
- Suspicious => "suspicious",
- }
- }
-}
-
pub fn explain(name: &str) -> i32 {
let target = format!("clippy::{}", name.to_ascii_uppercase());
@@ -535,30 +436,11 @@ pub fn explain(name: &str) -> i32 {
}
}
-fn register_categories(store: &mut rustc_lint::LintStore) {
- let mut groups = RegistrationGroups::default();
-
- for LintInfo { lint, category, .. } in declared_lints::LINTS {
- if category.is_all() {
- groups.all.push(LintId::of(lint));
- }
-
- category.group(&mut groups).push(LintId::of(lint));
- }
-
- let lints: Vec<&'static Lint> = declared_lints::LINTS.iter().map(|info| *info.lint).collect();
-
- store.register_lints(&lints);
- groups.register(store);
-}
-
/// Register all lints and lint groups with the rustc lint store
///
/// Used in `./src/driver.rs`.
#[expect(clippy::too_many_lines)]
-pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
- register_categories(store);
-
+pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
for (old_name, new_name) in deprecated_lints::RENAMED {
store.register_renamed(old_name, new_name);
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 388034c..e792edb 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -163,15 +163,14 @@ fn visit_stmt(&mut self, s: &'tcx Stmt<'_>) {
StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr),
_ => {},
}
+ }
+ // Current statement is a push ...check whether another
+ // push had been previously done
+ else if self.vec_push.is_none() {
+ self.vec_push = vec_push_option;
} else {
- // Current statement is a push ...check whether another
- // push had been previously done
- if self.vec_push.is_none() {
- self.vec_push = vec_push_option;
- } else {
- // There are multiple pushes ... don't lint
- self.multiple_pushes = true;
- }
+ // There are multiple pushes ... don't lint
+ self.multiple_pushes = true;
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 0b3bec7..9ff82cd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -13,7 +13,6 @@
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LintContext};
-
use rustc_span::Span;
use rustc_span::symbol::{Symbol, sym};
use std::slice;
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index 4959908..edbb556 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline};
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::option_arg_ty;
+use clippy_utils::ty::{option_arg_ty, peel_mid_ty_refs_is_mutable};
use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res, peel_blocks, span_contains_comment};
-use rustc_ast::BindingMode;
+use rustc_ast::{BindingMode, Mutability};
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr};
use rustc_hir::def::{DefKind, Res};
@@ -133,7 +133,21 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok
Applicability::MachineApplicable
};
let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren();
- let sugg = format!("{scrut}.{method}()");
+
+ let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee);
+ let (_, n_ref, mutability) = peel_mid_ty_refs_is_mutable(scrutinee_ty);
+ let prefix = if n_ref > 0 {
+ if mutability == Mutability::Mut {
+ ".as_mut()"
+ } else {
+ ".as_ref()"
+ }
+ } else {
+ ""
+ };
+
+ let sugg = format!("{scrut}{prefix}.{method}()");
+
// If the expression being expanded is the `if …` part of an `else if …`, it must be blockified.
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let ExprKind::If(_, _, Some(else_part)) = parent_expr.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 24b4a67..70a03ff 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
use rustc_errors::Applicability;
@@ -116,11 +117,12 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
let format_suggestion = |variant: &VariantDef| {
format!(
"{}{}{}{}",
- if let Some(ident) = wildcard_ident {
- format!("{} @ ", ident.name)
- } else {
- String::new()
- },
+ wildcard_ident.map_or(String::new(), |ident| {
+ ident
+ .span
+ .get_source_text(cx)
+ .map_or_else(|| format!("{} @ ", ident.name), |s| format!("{s} @ "))
+ }),
if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
let mut s = String::new();
for seg in path_prefix {
@@ -138,7 +140,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
Some(CtorKind::Fn) if variant.fields.len() == 1 => "(_)",
Some(CtorKind::Fn) => "(..)",
Some(CtorKind::Const) => "",
- None => "{ .. }",
+ None => " { .. }",
}
)
};
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 347960e..f2dabdd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -4426,7 +4426,7 @@
/// ```no_run
/// use std::io::{BufReader, Read};
/// use std::fs::File;
- /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap());
+ /// let file = BufReader::new(File::open("./bytes.txt").unwrap());
/// file.bytes();
/// ```
#[clippy::version = "1.87.0"]
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 7bdd999..2139466 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -136,7 +136,7 @@ fn check_or_fn_call<'tcx>(
fun_span: Option<Span>,
) -> bool {
// (path, fn_has_argument, methods, suffix)
- const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [
+ const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 5] = [
(sym::BTreeEntry, false, &[sym::or_insert], "with"),
(sym::HashMapEntry, false, &[sym::or_insert], "with"),
(
@@ -145,16 +145,17 @@ fn check_or_fn_call<'tcx>(
&[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or],
"else",
),
- (sym::Result, true, &[sym::or, sym::unwrap_or], "else"),
+ (sym::Option, false, &[sym::get_or_insert], "with"),
+ (sym::Result, true, &[sym::map_or, sym::or, sym::unwrap_or], "else"),
];
if KNOW_TYPES.iter().any(|k| k.2.contains(&name))
&& switch_to_lazy_eval(cx, arg)
&& !contains_return(arg)
&& let self_ty = cx.typeck_results().expr_ty(self_expr)
- && let Some(&(_, fn_has_arguments, poss, suffix)) =
- KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0))
- && poss.contains(&name)
+ && let Some(&(_, fn_has_arguments, _, suffix)) = KNOW_TYPES
+ .iter()
+ .find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0) && i.2.contains(&name))
{
let ctxt = span.ctxt();
let mut app = Applicability::HasPlaceholders;
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index f835bbb..25c95d2 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint;
-use rustc_attr_data_structures::{find_attr, AttributeKind};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_hir as hir;
use rustc_hir::Attribute;
use rustc_lint::{LateContext, LateLintPass, LintContext};
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index 8d2f802..17d251a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -161,7 +161,7 @@ fn path_has_args(p: &QPath<'_>) -> bool {
/// - `Copy` itself, or
/// - the only use of a mutable reference, or
/// - not a variable (created by a function call)
-#[expect(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
fn needless_borrow_count<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
@@ -232,11 +232,11 @@ fn needless_borrow_count<'tcx>(
let mut args_with_referent_ty = callee_args.to_vec();
let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| {
- if let ExprKind::Field(base, _) = &referent.kind {
- let base_ty = cx.typeck_results().expr_ty(base);
- if drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) {
- return false;
- }
+ if let ExprKind::Field(base, _) = &referent.kind
+ && let base_ty = cx.typeck_results().expr_ty(base)
+ && drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[]))
+ {
+ return false;
}
let referent_ty = cx.typeck_results().expr_ty(referent);
diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
index 8a62106..021a115 100644
--- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -5,7 +5,6 @@
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
-
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 9aede1d..c97ecce 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -124,8 +124,10 @@ fn check_fn(
// Note that we do not want to deal with qualified predicates here.
match pred.kind().no_bound_vars() {
Some(ty::ClauseKind::Trait(pred))
- if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait
- => Some(pred),
+ if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait =>
+ {
+ Some(pred)
+ },
_ => None,
}
})
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
index 0159c5d..dee8efe 100644
--- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{snippet, snippet_with_applicability};
use rustc_abi::ExternAbi;
+use rustc_attr_data_structures::AttributeKind;
use rustc_errors::Applicability;
-use rustc_hir::{Item, ItemKind};
+use rustc_hir::{Attribute, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Pos};
-use rustc_attr_data_structures::AttributeKind;
-use rustc_hir::Attribute;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index a27c6aa..5f10e19 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -617,7 +617,7 @@ fn is_non_freeze_init_borrowed(
// Then a type check. Note we only check the type here as the result
// gets cached.
- let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args);
+ let ty = typeck.expr_ty(src_expr);
// Normalized as we need to check if this is an array later.
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index e1fd095..3efbb89 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -1,12 +1,13 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt, integer_const, is_zero_integer_const};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{clip, peel_hir_expr_refs, unsext};
+use clippy_utils::{ExprUseNode, clip, expr_use_ctxt, peel_hir_expr_refs, unsext};
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{BinOpKind, Expr, ExprKind, Node, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::Span;
+use rustc_span::{Span, kw};
use super::IDENTITY_OP;
@@ -17,7 +18,7 @@ pub(crate) fn check<'tcx>(
left: &'tcx Expr<'_>,
right: &'tcx Expr<'_>,
) {
- if !is_allowed(cx, op, left, right) {
+ if !is_allowed(cx, expr, op, left, right) {
return;
}
@@ -165,14 +166,27 @@ fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, child: &Expr<'_>)
Parens::Needed
}
-fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> bool {
+fn is_allowed<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ cmp: BinOpKind,
+ left: &Expr<'tcx>,
+ right: &Expr<'tcx>,
+) -> bool {
+ // Exclude case where the left or right side is associated function call returns a type which is
+ // `Self` that is not given explicitly, and the expression is not a let binding's init
+ // expression and the let binding has a type annotation, or a function's return value.
+ if (is_assoc_fn_without_type_instance(cx, left) || is_assoc_fn_without_type_instance(cx, right))
+ && !is_expr_used_with_type_annotation(cx, expr)
+ {
+ return false;
+ }
+
// This lint applies to integers and their references
cx.typeck_results().expr_ty(left).peel_refs().is_integral()
&& cx.typeck_results().expr_ty(right).peel_refs().is_integral()
// `1 << 0` is a common pattern in bit manipulation code
- && !(cmp == BinOpKind::Shl
- && ConstEvalCtxt::new(cx).eval_simple(right) == Some(Constant::Int(0))
- && ConstEvalCtxt::new(cx).eval_simple(left) == Some(Constant::Int(1)))
+ && !(cmp == BinOpKind::Shl && is_zero_integer_const(cx, right) && integer_const(cx, left) == Some(1))
}
fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) {
@@ -234,3 +248,47 @@ fn span_ineffective_operation(
applicability,
);
}
+
+fn is_expr_used_with_type_annotation<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+ match expr_use_ctxt(cx, expr).use_node(cx) {
+ ExprUseNode::LetStmt(letstmt) => letstmt.ty.is_some(),
+ ExprUseNode::Return(_) => true,
+ _ => false,
+ }
+}
+
+/// Check if the expression is an associated function without a type instance.
+/// Example:
+/// ```
+/// trait Def {
+/// fn def() -> Self;
+/// }
+/// impl Def for usize {
+/// fn def() -> Self {
+/// 0
+/// }
+/// }
+/// fn test() {
+/// let _ = 0usize + &Default::default();
+/// let _ = 0usize + &Def::def();
+/// }
+/// ```
+fn is_assoc_fn_without_type_instance<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
+ if let ExprKind::Call(func, _) = peel_hir_expr_refs(expr).0.kind
+ && let ExprKind::Path(QPath::Resolved(
+ // If it's not None, don't need to go further.
+ None,
+ Path {
+ res: Res::Def(DefKind::AssocFn, def_id),
+ ..
+ },
+ )) = func.kind
+ && let output_ty = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output()
+ && let ty::Param(ty::ParamTy {
+ name: kw::SelfUpper, ..
+ }) = output_ty.kind()
+ {
+ return true;
+ }
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs
new file mode 100644
index 0000000..821178a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs
@@ -0,0 +1,66 @@
+use clippy_utils::consts::is_zero_integer_const;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use rustc_ast::BinOpKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::MANUAL_IS_MULTIPLE_OF;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &Expr<'_>,
+ op: BinOpKind,
+ lhs: &'tcx Expr<'tcx>,
+ rhs: &'tcx Expr<'tcx>,
+ msrv: Msrv,
+) {
+ if msrv.meets(cx, msrvs::UNSIGNED_IS_MULTIPLE_OF)
+ && let Some(operand) = uint_compare_to_zero(cx, op, lhs, rhs)
+ && let ExprKind::Binary(operand_op, operand_left, operand_right) = operand.kind
+ && operand_op.node == BinOpKind::Rem
+ {
+ let mut app = Applicability::MachineApplicable;
+ let divisor = Sugg::hir_with_applicability(cx, operand_right, "_", &mut app);
+ span_lint_and_sugg(
+ cx,
+ MANUAL_IS_MULTIPLE_OF,
+ expr.span,
+ "manual implementation of `.is_multiple_of()`",
+ "replace with",
+ format!(
+ "{}{}.is_multiple_of({divisor})",
+ if op == BinOpKind::Eq { "" } else { "!" },
+ Sugg::hir_with_applicability(cx, operand_left, "_", &mut app).maybe_paren()
+ ),
+ app,
+ );
+ }
+}
+
+// If we have a `x == 0`, `x != 0` or `x > 0` (or the reverted ones), return the non-zero operand
+fn uint_compare_to_zero<'tcx>(
+ cx: &LateContext<'tcx>,
+ op: BinOpKind,
+ lhs: &'tcx Expr<'tcx>,
+ rhs: &'tcx Expr<'tcx>,
+) -> Option<&'tcx Expr<'tcx>> {
+ let operand = if matches!(lhs.kind, ExprKind::Binary(..))
+ && matches!(op, BinOpKind::Eq | BinOpKind::Ne | BinOpKind::Gt)
+ && is_zero_integer_const(cx, rhs)
+ {
+ lhs
+ } else if matches!(rhs.kind, ExprKind::Binary(..))
+ && matches!(op, BinOpKind::Eq | BinOpKind::Ne | BinOpKind::Lt)
+ && is_zero_integer_const(cx, lhs)
+ {
+ rhs
+ } else {
+ return None;
+ };
+
+ matches!(cx.typeck_results().expr_ty_adjusted(operand).kind(), ty::Uint(_)).then_some(operand)
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 2f4e8e9..bdbbb34 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -11,6 +11,7 @@
mod float_equality_without_abs;
mod identity_op;
mod integer_division;
+mod manual_is_multiple_of;
mod manual_midpoint;
mod misrefactored_assign_op;
mod modulo_arithmetic;
@@ -830,12 +831,42 @@
"manual implementation of `midpoint` which can overflow"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for manual implementation of `.is_multiple_of()` on
+ /// unsigned integer types.
+ ///
+ /// ### Why is this bad?
+ /// `a.is_multiple_of(b)` is a clearer way to check for divisibility
+ /// of `a` by `b`. This expression can never panic.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// # let (a, b) = (3u64, 4u64);
+ /// if a % b == 0 {
+ /// println!("{a} is divisible by {b}");
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// # let (a, b) = (3u64, 4u64);
+ /// if a.is_multiple_of(b) {
+ /// println!("{a} is divisible by {b}");
+ /// }
+ /// ```
+ #[clippy::version = "1.89.0"]
+ pub MANUAL_IS_MULTIPLE_OF,
+ complexity,
+ "manual implementation of `.is_multiple_of()`"
+}
+
pub struct Operators {
arithmetic_context: numeric_arithmetic::Context,
verbose_bit_mask_threshold: u64,
modulo_arithmetic_allow_comparison_to_zero: bool,
msrv: Msrv,
}
+
impl Operators {
pub fn new(conf: &'static Conf) -> Self {
Self {
@@ -874,6 +905,7 @@ pub fn new(conf: &'static Conf) -> Self {
NEEDLESS_BITWISE_BOOL,
SELF_ASSIGNMENT,
MANUAL_MIDPOINT,
+ MANUAL_IS_MULTIPLE_OF,
]);
impl<'tcx> LateLintPass<'tcx> for Operators {
@@ -891,6 +923,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
identity_op::check(cx, e, op.node, lhs, rhs);
needless_bitwise_bool::check(cx, e, op.node, lhs, rhs);
manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv);
+ manual_is_multiple_of::check(cx, e, op.node, lhs, rhs, self.msrv);
}
self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
bit_mask::check(cx, e, op.node, lhs, rhs);
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index e18bdfb..b8005df 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -3,10 +3,10 @@
use clippy_utils::source::snippet;
use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
use clippy_utils::{is_self, is_self_ty};
-use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr};
-use rustc_data_structures::fx::FxHashSet;
use core::ops::ControlFlow;
use rustc_abi::ExternAbi;
+use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr};
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index c02e5e0..de12a25 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -142,6 +142,7 @@ fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) -
&& let Some(ret) = find_let_else_ret_expression(els)
&& let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret)
&& !span_contains_comment(cx.tcx.sess.source_map(), els.span)
+ && !span_contains_cfg(cx, els.span)
{
let mut applicability = Applicability::MaybeIncorrect;
let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren();
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
index 96ea485..7bbbd0d 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_then;
-
use clippy_utils::macros::span_is_local;
use rustc_hir::{Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index 6b1dc86..acd8404 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -3,11 +3,10 @@
use clippy_utils::source::snippet;
use clippy_utils::{get_enclosing_block, sym};
-use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind};
use rustc_errors::Applicability;
-use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{Visitor, walk_expr};
+use rustc_hir::{self as hir, Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 1b304dc..25929b8 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -1,14 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_must_use_ty;
use clippy_utils::{nth_arg, return_ty};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass;
-use rustc_span::{Span};
-use rustc_attr_data_structures::AttributeKind;
-use rustc_attr_data_structures::find_attr;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 6293991..38cf7e3 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -219,22 +219,21 @@ fn track_uses(
}
}
}
- } else {
- // keep track of `use self::some_module` usages
- if segments[0].ident.name == kw::SelfLower {
- // simple case such as `use self::module::SomeStruct`
- if segments.len() > 1 {
- imports_reused_with_self.push(segments[1].ident.name);
- return;
- }
+ }
+ // keep track of `use self::some_module` usages
+ else if segments[0].ident.name == kw::SelfLower {
+ // simple case such as `use self::module::SomeStruct`
+ if segments.len() > 1 {
+ imports_reused_with_self.push(segments[1].ident.name);
+ return;
+ }
- // nested case such as `use self::{module1::Struct1, module2::Struct2}`
- if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
- for tree in items {
- let segments = &tree.0.prefix.segments;
- if !segments.is_empty() {
- imports_reused_with_self.push(segments[0].ident.name);
- }
+ // nested case such as `use self::{module1::Struct1, module2::Struct2}`
+ if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
+ for tree in items {
+ let segments = &tree.0.prefix.segments;
+ if !segments.is_empty() {
+ imports_reused_with_self.push(segments[0].ident.name);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index a2938c8..9242747 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -606,32 +606,31 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
let ctxt = span.ctxt();
if ctxt == SyntaxContext::root() {
HasSafetyComment::Maybe
- } else {
- // From a macro expansion. Get the text from the start of the macro declaration to start of the
- // unsafe block.
- // macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; }
- // ^--------------------------------------------^
- if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
- && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo())
- && Arc::ptr_eq(&unsafe_line.sf, ¯o_line.sf)
- && let Some(src) = unsafe_line.sf.src.as_deref()
- {
- if macro_line.line < unsafe_line.line {
- match text_has_safety_comment(
- src,
- &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line],
- unsafe_line.sf.start_pos,
- ) {
- Some(b) => HasSafetyComment::Yes(b),
- None => HasSafetyComment::No,
- }
- } else {
- HasSafetyComment::No
+ }
+ // From a macro expansion. Get the text from the start of the macro declaration to start of the
+ // unsafe block.
+ // macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; }
+ // ^--------------------------------------------^
+ else if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
+ && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo())
+ && Arc::ptr_eq(&unsafe_line.sf, ¯o_line.sf)
+ && let Some(src) = unsafe_line.sf.src.as_deref()
+ {
+ if macro_line.line < unsafe_line.line {
+ match text_has_safety_comment(
+ src,
+ &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line],
+ unsafe_line.sf.start_pos,
+ ) {
+ Some(b) => HasSafetyComment::Yes(b),
+ None => HasSafetyComment::No,
}
} else {
- // Problem getting source text. Pretend a comment was found.
- HasSafetyComment::Maybe
+ HasSafetyComment::No
}
+ } else {
+ // Problem getting source text. Pretend a comment was found.
+ HasSafetyComment::Maybe
}
}
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 615c099..73291aa 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
-version = "0.1.89"
+version = "0.1.90"
edition = "2024"
description = "Helpful tools for writing lints, provided as they are used in Clippy"
repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 1aa16e3..649748d 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@
<!-- begin autogenerated nightly -->
```
-nightly-2025-06-12
+nightly-2025-06-26
```
<!-- end autogenerated nightly -->
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 1ec5d11..aaa071f 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -958,3 +958,18 @@ fn field_of_struct<'tcx>(
None
}
}
+
+/// If `expr` evaluates to an integer constant, return its value.
+pub fn integer_const(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
+ if let Some(Constant::Int(value)) = ConstEvalCtxt::new(cx).eval_simple(expr) {
+ Some(value)
+ } else {
+ None
+ }
+}
+
+/// Check if `expr` evaluates to an integer constant of 0.
+#[inline]
+pub fn is_zero_integer_const(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ integer_const(cx, expr) == Some(0)
+}
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index cd2098a..dc240dd 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -109,7 +109,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
});
}
-/// Same as `span_lint` but with an extra `help` message.
+/// Same as [`span_lint`] but with an extra `help` message.
///
/// Use this if you want to provide some general help but
/// can't provide a specific machine applicable suggestion.
@@ -166,7 +166,7 @@ pub fn span_lint_and_help<T: LintContext>(
});
}
-/// Like `span_lint` but with a `note` section instead of a `help` message.
+/// Like [`span_lint`] but with a `note` section instead of a `help` message.
///
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
@@ -226,7 +226,7 @@ pub fn span_lint_and_note<T: LintContext>(
});
}
-/// Like `span_lint` but allows to add notes, help and suggestions using a closure.
+/// Like [`span_lint`] but allows to add notes, help and suggestions using a closure.
///
/// If you need to customize your lint output a lot, use this function.
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 9135893..a8b3341 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -122,7 +122,7 @@
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{Ident, Symbol, kw};
use rustc_span::{InnerSpan, Span};
-use source::walk_span_to_context;
+use source::{SpanRangeExt, walk_span_to_context};
use visitors::{Visitable, for_each_unconsumed_temporary};
use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
@@ -1886,10 +1886,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
_ => None,
};
- did.is_some_and(|did| find_attr!(
- cx.tcx.get_all_attrs(did),
- AttributeKind::MustUse { ..}
- ))
+ did.is_some_and(|did| find_attr!(cx.tcx.get_all_attrs(did), AttributeKind::MustUse { .. }))
}
/// Checks if a function's body represents the identity function. Looks for bodies of the form:
@@ -2713,7 +2710,7 @@ pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
}
/// Gets the context an expression's value is used in.
-pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprUseCtxt<'tcx> {
+pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtxt<'tcx> {
let mut adjustments = [].as_slice();
let mut is_ty_unified = false;
let mut moved_before_use = false;
@@ -2790,6 +2787,19 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
});
}
+/// Checks whether a given span has any significant token. A significant token is a non-whitespace
+/// token, including comments unless `skip_comments` is set.
+/// This is useful to determine if there are any actual code tokens in the span that are omitted in
+/// the late pass, such as platform-specific code.
+pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
+ matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)|
+ match token {
+ TokenKind::Whitespace => false,
+ TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
+ _ => true,
+ }
+ ))
+}
/// Returns all the comments a given span contains
///
/// Comments are returned wrapped with their relevant delimiters
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index a5e66ad..7a0bef1 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -24,7 +24,7 @@ macro_rules! msrv_aliases {
// names may refer to stabilized feature flags or library items
msrv_aliases! {
1,88,0 { LET_CHAINS }
- 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
+ 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF }
1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
@@ -42,6 +42,7 @@ macro_rules! msrv_aliases {
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF }
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN }
+ 1,61,0 { CONST_FN_TRAIT_BOUND }
1,60,0 { ABS_DIFF }
1,59,0 { THREAD_LOCAL_CONST_INIT }
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index e629012..8f1ebb8 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -32,6 +32,21 @@ pub fn is_min_const_fn<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, msrv: Ms
for local in &body.local_decls {
check_ty(cx, local.ty, local.source_info.span, msrv)?;
}
+ if !msrv.meets(cx, msrvs::CONST_FN_TRAIT_BOUND)
+ && let Some(sized_did) = cx.tcx.lang_items().sized_trait()
+ && let Some(meta_sized_did) = cx.tcx.lang_items().meta_sized_trait()
+ && cx.tcx.param_env(def_id).caller_bounds().iter().any(|bound| {
+ bound.as_trait_clause().is_some_and(|clause| {
+ let did = clause.def_id();
+ did != sized_did && did != meta_sized_did
+ })
+ })
+ {
+ return Err((
+ body.span,
+ "non-`Sized` trait clause before `const_fn_trait_bound` is stabilized".into(),
+ ));
+ }
// impl trait is gone in MIR, so check the return type manually
check_ty(
cx,
@@ -436,7 +451,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
// FIXME(const_trait_impl, fee1-dead) revert to const destruct once it works again
#[expect(unused)]
fn is_ty_const_destruct_unused<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool {
- // If this doesn't need drop at all, then don't select `~const Destruct`.
+ // If this doesn't need drop at all, then don't select `[const] Destruct`.
if !ty.needs_drop(tcx, body.typing_env(tcx)) {
return false;
}
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 6974e65..7a24d07 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -494,7 +494,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
/// operators have the same
/// precedence.
pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
- Sugg::MaybeParen(format!("{op}{}", expr.maybe_paren()).into())
+ // If the `expr` starts with `op` already, do not add wrap it in
+ // parentheses.
+ let expr = if let Sugg::MaybeParen(ref sugg) = expr
+ && !has_enclosing_paren(sugg)
+ && sugg.starts_with(op)
+ {
+ expr
+ } else {
+ expr.maybe_paren()
+ };
+ Sugg::MaybeParen(format!("{op}{expr}").into())
}
/// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
@@ -1016,6 +1026,16 @@ fn binop_maybe_paren() {
let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "(1 + 1)".into(), "(1 + 1)".into());
assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_paren().to_string());
}
+
+ #[test]
+ fn unop_parenthesize() {
+ let sugg = Sugg::NonParen("x".into()).mut_addr();
+ assert_eq!("&mut x", sugg.to_string());
+ let sugg = sugg.mut_addr();
+ assert_eq!("&mut &mut x", sugg.to_string());
+ assert_eq!("(&mut &mut x)", sugg.maybe_paren().to_string());
+ }
+
#[test]
fn not_op() {
use ast::BinOpKind::{Add, And, Eq, Ge, Gt, Le, Lt, Ne, Or};
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 3b58dba..8a8218c 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -46,7 +46,6 @@ macro_rules! generate {
DOUBLE_QUOTE: "\"",
Deserialize,
EarlyLintPass,
- ErrorKind,
IntoIter,
Itertools,
LF: "\n",
@@ -65,7 +64,6 @@ macro_rules! generate {
RegexBuilder,
RegexSet,
Start,
- Step,
Symbol,
SyntaxContext,
TBD,
@@ -158,7 +156,6 @@ macro_rules! generate {
from_ne_bytes,
from_ptr,
from_raw,
- from_ref,
from_str,
from_str_radix,
fs,
@@ -166,6 +163,7 @@ macro_rules! generate {
futures_util,
get,
get_mut,
+ get_or_insert,
get_or_insert_with,
get_unchecked,
get_unchecked_mut,
@@ -216,7 +214,6 @@ macro_rules! generate {
max_by_key,
max_value,
maximum,
- mem,
min,
min_by,
min_by_key,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 782b079..bffbcf0 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -6,6 +6,7 @@
use itertools::Itertools;
use rustc_abi::VariantIdx;
use rustc_ast::ast::Mutability;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -20,8 +21,8 @@
use rustc_middle::ty::layout::ValidityRequirement;
use rustc_middle::ty::{
self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
- GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
- TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+ GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+ TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
};
use rustc_span::symbol::Ident;
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -31,8 +32,6 @@
use std::assert_matches::debug_assert_matches;
use std::collections::hash_map::Entry;
use std::iter;
-use rustc_attr_data_structures::find_attr;
-use rustc_attr_data_structures::AttributeKind;
use crate::path_res;
use crate::paths::{PathNS, lookup_path_str};
@@ -328,14 +327,8 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
// Returns whether the type has #[must_use] attribute
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind() {
- ty::Adt(adt, _) => find_attr!(
- cx.tcx.get_all_attrs(adt.did()),
- AttributeKind::MustUse { ..}
- ),
- ty::Foreign(did) => find_attr!(
- cx.tcx.get_all_attrs(*did),
- AttributeKind::MustUse { ..}
- ),
+ ty::Adt(adt, _) => find_attr!(cx.tcx.get_all_attrs(adt.did()), AttributeKind::MustUse { .. }),
+ ty::Foreign(did) => find_attr!(cx.tcx.get_all_attrs(*did), AttributeKind::MustUse { .. }),
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => {
// for the Array case we don't need to care for the len == 0 case
// because we don't want to lint functions returning empty arrays
@@ -345,7 +338,10 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
- && find_attr!(cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id), AttributeKind::MustUse { ..})
+ && find_attr!(
+ cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id),
+ AttributeKind::MustUse { .. }
+ )
{
return true;
}
@@ -355,7 +351,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty::Dynamic(binder, _, _) => {
for predicate in *binder {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
- && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { ..})
+ && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. })
{
return true;
}
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
new file mode 100644
index 0000000..bd6b4df
--- /dev/null
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "declare_clippy_lint"
+version = "0.1.90"
+edition = "2024"
+repository = "https://github.com/rust-lang/rust-clippy"
+license = "MIT OR Apache-2.0"
+
+[package.metadata.rust-analyzer]
+# This crate uses #[feature(rustc_private)]
+rustc_private = true
diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs
new file mode 100644
index 0000000..f7d9c64
--- /dev/null
+++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs
@@ -0,0 +1,280 @@
+#![feature(macro_metavar_expr_concat, rustc_private)]
+
+extern crate rustc_lint;
+
+use rustc_lint::{Lint, LintId, LintStore};
+
+// Needed by `declare_clippy_lint!`.
+pub extern crate rustc_session;
+
+#[derive(Default)]
+pub struct LintListBuilder {
+ lints: Vec<&'static Lint>,
+ all: Vec<LintId>,
+ cargo: Vec<LintId>,
+ complexity: Vec<LintId>,
+ correctness: Vec<LintId>,
+ nursery: Vec<LintId>,
+ pedantic: Vec<LintId>,
+ perf: Vec<LintId>,
+ restriction: Vec<LintId>,
+ style: Vec<LintId>,
+ suspicious: Vec<LintId>,
+}
+impl LintListBuilder {
+ pub fn insert(&mut self, lints: &[&LintInfo]) {
+ #[allow(clippy::enum_glob_use)]
+ use LintCategory::*;
+
+ self.lints.extend(lints.iter().map(|&x| x.lint));
+ for &&LintInfo { lint, category, .. } in lints {
+ let (all, cat) = match category {
+ Complexity => (Some(&mut self.all), &mut self.complexity),
+ Correctness => (Some(&mut self.all), &mut self.correctness),
+ Perf => (Some(&mut self.all), &mut self.perf),
+ Style => (Some(&mut self.all), &mut self.style),
+ Suspicious => (Some(&mut self.all), &mut self.suspicious),
+ Cargo => (None, &mut self.cargo),
+ Nursery => (None, &mut self.nursery),
+ Pedantic => (None, &mut self.pedantic),
+ Restriction => (None, &mut self.restriction),
+ };
+ if let Some(all) = all {
+ all.push(LintId::of(lint));
+ }
+ cat.push(LintId::of(lint));
+ }
+ }
+
+ pub fn register(self, store: &mut LintStore) {
+ store.register_lints(&self.lints);
+ store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
+ store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
+ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
+ store.register_group(
+ true,
+ "clippy::correctness",
+ Some("clippy_correctness"),
+ self.correctness,
+ );
+ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
+ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
+ store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
+ store.register_group(
+ true,
+ "clippy::restriction",
+ Some("clippy_restriction"),
+ self.restriction,
+ );
+ store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
+ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum LintCategory {
+ Cargo,
+ Complexity,
+ Correctness,
+ Nursery,
+ Pedantic,
+ Perf,
+ Restriction,
+ Style,
+ Suspicious,
+}
+impl LintCategory {
+ #[must_use]
+ pub fn name(self) -> &'static str {
+ match self {
+ Self::Cargo => "cargo",
+ Self::Complexity => "complexity",
+ Self::Correctness => "correctness",
+ Self::Nursery => "nursery",
+ Self::Pedantic => "pedantic",
+ Self::Perf => "perf",
+ Self::Restriction => "restriction",
+ Self::Style => "style",
+ Self::Suspicious => "suspicious",
+ }
+ }
+}
+
+pub struct LintInfo {
+ pub lint: &'static Lint,
+ pub category: LintCategory,
+ pub explanation: &'static str,
+ /// e.g. `clippy_lints/src/absolute_paths.rs#43`
+ pub location: &'static str,
+ pub version: &'static str,
+}
+
+impl LintInfo {
+ /// Returns the lint name in lowercase without the `clippy::` prefix
+ #[must_use]
+ #[expect(clippy::missing_panics_doc)]
+ pub fn name_lower(&self) -> String {
+ self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase()
+ }
+}
+
+#[macro_export]
+macro_rules! declare_clippy_lint_inner {
+ (
+ $(#[doc = $docs:literal])*
+ #[clippy::version = $version:literal]
+ $vis:vis $lint_name:ident,
+ $level:ident,
+ $category:ident,
+ $desc:literal
+ $(, @eval_always = $eval_always:literal)?
+ ) => {
+ $crate::rustc_session::declare_tool_lint! {
+ $(#[doc = $docs])*
+ #[clippy::version = $version]
+ $vis clippy::$lint_name,
+ $level,
+ $desc,
+ report_in_external_macro:true
+ $(, @eval_always = $eval_always)?
+ }
+
+ pub(crate) static ${concat($lint_name, _INFO)}: &'static $crate::LintInfo = &$crate::LintInfo {
+ lint: $lint_name,
+ category: $crate::LintCategory::$category,
+ explanation: concat!($($docs,"\n",)*),
+ location: concat!(file!(), "#L", line!()),
+ version: $version,
+ };
+ };
+}
+
+#[macro_export]
+macro_rules! declare_clippy_lint {
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ correctness,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Deny,
+ Correctness,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ complexity,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Warn,
+ Complexity,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ perf,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Warn,
+ Perf,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ style,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Warn,
+ Style,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ suspicious,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Warn,
+ Suspicious,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ cargo,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Allow,
+ Cargo,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ nursery,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Allow,
+ Nursery,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ pedantic,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Allow,
+ Pedantic,
+ $($rest)*
+ }
+ };
+ (
+ $(#[$($meta:tt)*])*
+ $vis:vis $lint_name:ident,
+ restriction,
+ $($rest:tt)*
+ ) => {
+ $crate::declare_clippy_lint_inner! {
+ $(#[$($meta)*])*
+ $vis $lint_name,
+ Allow,
+ Restriction,
+ $($rest)*
+ }
+ };
+}
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 8418383..eb390ee 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -45,7 +45,7 @@
#[must_use]
pub fn target_dir() -> String {
- env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned())
+ env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target".to_owned())
}
fn lintcheck_sources() -> String {
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index 3fc5a12..124756a 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
[toolchain]
# begin autogenerated nightly
-channel = "nightly-2025-06-12"
+channel = "nightly-2025-06-26"
# end autogenerated nightly
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
profile = "minimal"
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 426ba87..c4076cb 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -19,6 +19,7 @@
extern crate tikv_jemalloc_sys as jemalloc_sys;
use clippy_utils::sym;
+use declare_clippy_lint::LintListBuilder;
use rustc_interface::interface;
use rustc_session::EarlyDiagCtxt;
use rustc_session::config::ErrorOutputType;
@@ -156,8 +157,13 @@ fn config(&mut self, config: &mut interface::Config) {
(previous)(sess, lint_store);
}
+ let mut list_builder = LintListBuilder::default();
+ list_builder.insert(clippy_lints::declared_lints::LINTS);
+ list_builder.register(lint_store);
+
let conf = clippy_config::Conf::read(sess, &conf_path);
- clippy_lints::register_lints(lint_store, conf);
+ clippy_lints::register_lint_passes(lint_store, conf);
+
#[cfg(feature = "internal")]
clippy_lints_internal::register_lints(lint_store);
}));
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index c9853e5..3c2eec1 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -107,7 +107,7 @@ fn path() -> PathBuf {
}
fn into_std_cmd(self) -> Command {
- let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into()));
+ let mut cmd = Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()));
let clippy_args: String = self
.clippy_args
.iter()
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 99a0125..cefe654 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -7,9 +7,9 @@
use cargo_metadata::Message;
use cargo_metadata::diagnostic::{Applicability, Diagnostic};
use clippy_config::ClippyConfiguration;
-use clippy_lints::LintInfo;
use clippy_lints::declared_lints::LINTS;
use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED};
+use declare_clippy_lint::LintInfo;
use pulldown_cmark::{Options, Parser, html};
use serde::Deserialize;
use test_utils::IS_RUSTC_TEST_SUITE;
@@ -568,10 +568,10 @@ fn new(lint: &LintInfo, applicabilities: &HashMap<String, Applicability>, config
Self {
id: name,
id_location: Some(lint.location),
- group: lint.category_str(),
+ group: lint.category.name(),
level: lint.lint.default_level.as_str(),
docs,
- version: lint.version.unwrap(),
+ version: lint.version,
applicability,
}
}
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 4ac2bd5..3896168 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -40,6 +40,7 @@ fn dogfood() {
"clippy_lints",
"clippy_utils",
"clippy_config",
+ "declare_clippy_lint",
"lintcheck",
"rustc_tools_util",
] {
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed
new file mode 100644
index 0000000..0dc0fc2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed
@@ -0,0 +1,50 @@
+#![allow(clippy::eq_op, clippy::nonminimal_bool)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+ let (x, y) = ("hello", "world");
+
+ if x == "hello" {
+ todo!()
+ }
+ // Comment must be kept
+ else if y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ } // Inner comment
+ else if y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ }
+ /* Inner comment */
+ else if y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ } /* Inner comment */
+ else if y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ } /* This should not be removed */ /* So does this */
+ // Comment must be kept
+ else if y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^^ collapsible_else_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs
new file mode 100644
index 0000000..8344c12
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs
@@ -0,0 +1,55 @@
+#![allow(clippy::eq_op, clippy::nonminimal_bool)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+ let (x, y) = ("hello", "world");
+
+ if x == "hello" {
+ todo!()
+ } else {
+ // Comment must be kept
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ } else { // Inner comment
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ } else {
+ /* Inner comment */
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ } else { /* Inner comment */
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^ collapsible_else_if
+
+ if x == "hello" {
+ todo!()
+ } /* This should not be removed */ else /* So does this */ {
+ // Comment must be kept
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^^ collapsible_else_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr
new file mode 100644
index 0000000..0ffe5f0
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr
@@ -0,0 +1,105 @@
+error: this `else { if .. }` block can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:10:12
+ |
+LL | } else {
+ | ____________^
+LL | | // Comment must be kept
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::collapsible-else-if` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::collapsible_else_if)]`
+help: collapse nested if block
+ |
+LL ~ }
+LL | // Comment must be kept
+LL ~ else if y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: this `else { if .. }` block can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:20:12
+ |
+LL | } else { // Inner comment
+ | ____________^
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ } // Inner comment
+LL ~ else if y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: this `else { if .. }` block can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:29:12
+ |
+LL | } else {
+ | ____________^
+LL | | /* Inner comment */
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ }
+LL | /* Inner comment */
+LL ~ else if y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: this `else { if .. }` block can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:39:12
+ |
+LL | } else { /* Inner comment */
+ | ____________^
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ } /* Inner comment */
+LL ~ else if y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: this `else { if .. }` block can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:48:64
+ |
+LL | } /* This should not be removed */ else /* So does this */ {
+ | ________________________________________________________________^
+LL | | // Comment must be kept
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ } /* This should not be removed */ /* So does this */
+LL | // Comment must be kept
+LL ~ else if y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
index 3bc6885..99beea8 100644
--- a/src/tools/clippy/tests/ui/assign_ops.fixed
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -91,7 +91,7 @@
impl<T> const NumberConstants for T
where
- T: Number + ~const core::ops::Add,
+ T: Number + [const] core::ops::Add,
{
fn constant(value: usize) -> Self {
let mut res = Self::ZERO;
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
index f1f8f9d..900d5ad 100644
--- a/src/tools/clippy/tests/ui/assign_ops.rs
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -91,7 +91,7 @@ pub trait NumberConstants {
impl<T> const NumberConstants for T
where
- T: Number + ~const core::ops::Add,
+ T: Number + [const] core::ops::Add,
{
fn constant(value: usize) -> Self {
let mut res = Self::ZERO;
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
index 765dd75..6d06fcc 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
@@ -124,3 +124,50 @@
//~^ borrow_deref_ref
}
}
+
+fn issue_14934() {
+ let x: &'static str = "x";
+ let y = "y".to_string();
+ {
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*x; // Do not lint
+ *x = &*y;
+ }
+ {
+ let mut x = x;
+ //~^ borrow_deref_ref
+ x = &*y;
+ }
+ {
+ #[expect(clippy::toplevel_ref_arg, clippy::needless_borrow)]
+ let ref x = x;
+ //~^ borrow_deref_ref
+ }
+ {
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = std::convert::identity(x);
+ //~^ borrow_deref_ref
+ *x = &*y;
+ }
+ {
+ #[derive(Clone)]
+ struct S(&'static str);
+ let s = S("foo");
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*s.0; // Do not lint
+ *x = "bar";
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = s.clone().0;
+ //~^ borrow_deref_ref
+ *x = "bar";
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*std::convert::identity(&s).0;
+ *x = "bar";
+ }
+ {
+ let y = &1;
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = { y };
+ //~^ borrow_deref_ref
+ }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs
index 8ee66bf..b43f4c9 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs
@@ -124,3 +124,50 @@ fn bar() {
//~^ borrow_deref_ref
}
}
+
+fn issue_14934() {
+ let x: &'static str = "x";
+ let y = "y".to_string();
+ {
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*x; // Do not lint
+ *x = &*y;
+ }
+ {
+ let mut x = &*x;
+ //~^ borrow_deref_ref
+ x = &*y;
+ }
+ {
+ #[expect(clippy::toplevel_ref_arg, clippy::needless_borrow)]
+ let ref x = &*x;
+ //~^ borrow_deref_ref
+ }
+ {
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*std::convert::identity(x);
+ //~^ borrow_deref_ref
+ *x = &*y;
+ }
+ {
+ #[derive(Clone)]
+ struct S(&'static str);
+ let s = S("foo");
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*s.0; // Do not lint
+ *x = "bar";
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*s.clone().0;
+ //~^ borrow_deref_ref
+ *x = "bar";
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = &*std::convert::identity(&s).0;
+ *x = "bar";
+ }
+ {
+ let y = &1;
+ #[expect(clippy::toplevel_ref_arg)]
+ let ref mut x = { &*y };
+ //~^ borrow_deref_ref
+ }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
index 3d55da2..3a1f968 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
@@ -25,5 +25,35 @@
LL | (&*s).foo();
| ^^^^^ help: if you would like to reborrow, try removing `&*`: `s`
-error: aborting due to 4 previous errors
+error: deref on an immutable reference
+ --> tests/ui/borrow_deref_ref.rs:137:21
+ |
+LL | let mut x = &*x;
+ | ^^^ help: if you would like to reborrow, try removing `&*`: `x`
+
+error: deref on an immutable reference
+ --> tests/ui/borrow_deref_ref.rs:143:21
+ |
+LL | let ref x = &*x;
+ | ^^^ help: if you would like to reborrow, try removing `&*`: `x`
+
+error: deref on an immutable reference
+ --> tests/ui/borrow_deref_ref.rs:148:25
+ |
+LL | let ref mut x = &*std::convert::identity(x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `std::convert::identity(x)`
+
+error: deref on an immutable reference
+ --> tests/ui/borrow_deref_ref.rs:160:25
+ |
+LL | let ref mut x = &*s.clone().0;
+ | ^^^^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `s.clone().0`
+
+error: deref on an immutable reference
+ --> tests/ui/borrow_deref_ref.rs:170:27
+ |
+LL | let ref mut x = { &*y };
+ | ^^^ help: if you would like to reborrow, try removing `&*`: `y`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
index 0f439f7..674450a 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
@@ -218,4 +218,20 @@ impl S {
let _ = &S::VALUE.1; //~ borrow_interior_mutable_const
let _ = &S::VALUE.2;
}
+ {
+ pub struct Foo<T, const N: usize>(pub Entry<N>, pub T);
+
+ pub struct Entry<const N: usize>(pub Cell<[u32; N]>);
+
+ impl<const N: usize> Entry<N> {
+ const INIT: Self = Self(Cell::new([42; N]));
+ }
+
+ impl<T, const N: usize> Foo<T, N> {
+ pub fn make_foo(v: T) -> Self {
+ // Used to ICE due to incorrect instantiation.
+ Foo(Entry::INIT, v)
+ }
+ }
+ }
}
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 80000f5..ed00494 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -126,7 +126,7 @@
impl Bar for Foo {}
fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
- if i % 2 == 0 {
+ if i.is_multiple_of(2) {
Some(Box::new(Foo::default()))
} else {
None
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index 4681016..801d92f 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -126,7 +126,7 @@ pub trait Bar {}
impl Bar for Foo {}
fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
- if i % 2 == 0 {
+ if i.is_multiple_of(2) {
Some(Box::new(Foo::default()))
} else {
None
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
index 922d304..fa322dc 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
@@ -276,3 +276,27 @@ fn share_on_bottom() {
}
}
}
+
+fn issue15004() {
+ let a = 12u32;
+ let b = 13u32;
+ let mut c = 8u32;
+
+ let mut result = if b > a {
+ c += 1;
+ 0
+ } else {
+ c += 2;
+ 0
+ //~^ branches_sharing_code
+ };
+
+ result = if b > a {
+ c += 1;
+ 1
+ } else {
+ c += 2;
+ 1
+ //~^ branches_sharing_code
+ };
+}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
index f437db8..1c470fb 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
@@ -172,5 +172,35 @@
LL + let y = 1;
|
-error: aborting due to 10 previous errors
+error: all if blocks contain the same code at the end
+ --> tests/ui/branches_sharing_code/shared_at_bottom.rs:290:5
+ |
+LL | / 0
+LL | |
+LL | | };
+ | |_____^
+ |
+ = note: the end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving these statements after the if
+ |
+LL ~ }
+LL ~ 0;
+ |
+
+error: all if blocks contain the same code at the end
+ --> tests/ui/branches_sharing_code/shared_at_bottom.rs:299:5
+ |
+LL | / 1
+LL | |
+LL | | };
+ | |_____^
+ |
+ = note: the end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving these statements after the if
+ |
+LL ~ }
+LL ~ 1;
+ |
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
index 9f530ad..fed7524 100644
--- a/src/tools/clippy/tests/ui/collapsible_else_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
@@ -86,3 +86,21 @@
}else if false {}
//~^^^ collapsible_else_if
}
+
+fn issue14799() {
+ use std::ops::ControlFlow;
+
+ let c: ControlFlow<_, ()> = ControlFlow::Break(Some(42));
+ if let ControlFlow::Break(Some(_)) = c {
+ todo!();
+ } else {
+ #[cfg(target_os = "freebsd")]
+ todo!();
+
+ if let ControlFlow::Break(None) = c {
+ todo!();
+ } else {
+ todo!();
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs
index 2c646cd..e50e781 100644
--- a/src/tools/clippy/tests/ui/collapsible_else_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs
@@ -102,3 +102,21 @@ fn issue_7318() {
}
//~^^^ collapsible_else_if
}
+
+fn issue14799() {
+ use std::ops::ControlFlow;
+
+ let c: ControlFlow<_, ()> = ControlFlow::Break(Some(42));
+ if let ControlFlow::Break(Some(_)) = c {
+ todo!();
+ } else {
+ #[cfg(target_os = "freebsd")]
+ todo!();
+
+ if let ControlFlow::Break(None) = c {
+ todo!();
+ } else {
+ todo!();
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed
index b553182..77bc791 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_if.fixed
@@ -154,3 +154,12 @@
None
};
}
+
+fn issue14799() {
+ if true {
+ #[cfg(target_os = "freebsd")]
+ todo!();
+
+ if true {}
+ };
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs
index f599845..d30df15 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_if.rs
@@ -164,3 +164,12 @@ fn issue14722() {
None
};
}
+
+fn issue14799() {
+ if true {
+ #[cfg(target_os = "freebsd")]
+ todo!();
+
+ if true {}
+ };
+}
diff --git a/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs b/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs
index 633a435..8c32176 100644
--- a/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs
@@ -1,5 +1,3 @@
-//@ check-pass
-
#![warn(clippy::needless_doctest_main)]
//! issue 10491:
//! ```rust,no_test
@@ -19,4 +17,114 @@
/// ```
fn foo() {}
+#[rustfmt::skip]
+/// Description
+/// ```rust
+/// fn main() {
+//~^ error: needless `fn main` in doctest
+/// let a = 0;
+/// }
+/// ```
+fn mulpipulpi() {}
+
+#[rustfmt::skip]
+/// With a `#[no_main]`
+/// ```rust
+/// #[no_main]
+/// fn a() {
+/// let _ = 0;
+/// }
+/// ```
+fn pulpimulpi() {}
+
+// Without a `#[no_main]` attribute
+/// ```rust
+/// fn a() {
+/// let _ = 0;
+/// }
+/// ```
+fn plumilupi() {}
+
+#[rustfmt::skip]
+/// Additional function, shouldn't trigger
+/// ```rust
+/// fn additional_function() {
+/// let _ = 0;
+/// // Thus `fn main` is actually relevant!
+/// }
+/// fn main() {
+/// let _ = 0;
+/// }
+/// ```
+fn mlupipupi() {}
+
+#[rustfmt::skip]
+/// Additional function AFTER main, shouldn't trigger
+/// ```rust
+/// fn main() {
+/// let _ = 0;
+/// }
+/// fn additional_function() {
+/// let _ = 0;
+/// // Thus `fn main` is actually relevant!
+/// }
+/// ```
+fn lumpimupli() {}
+
+#[rustfmt::skip]
+/// Ignore code block, should not lint at all
+/// ```rust, ignore
+/// fn main() {
+//~^ error: needless `fn main` in doctest
+/// // Hi!
+/// let _ = 0;
+/// }
+/// ```
+fn mpulpilumi() {}
+
+#[rustfmt::skip]
+/// Spaces in weird positions (including an \u{A0} after `main`)
+/// ```rust
+/// fn main (){
+//~^ error: needless `fn main` in doctest
+/// let _ = 0;
+/// }
+/// ```
+fn plumpiplupi() {}
+
+/// 4 Functions, this should not lint because there are several function
+///
+/// ```rust
+/// fn a() {let _ = 0; }
+/// fn b() {let _ = 0; }
+/// fn main() { let _ = 0; }
+/// fn d() { let _ = 0; }
+/// ```
+fn pulmipulmip() {}
+
+/// 3 Functions but main is first, should also not lint
+///
+///```rust
+/// fn main() { let _ = 0; }
+/// fn b() { let _ = 0; }
+/// fn c() { let _ = 0; }
+/// ```
+fn pmuplimulip() {}
+
fn main() {}
+
+fn issue8244() -> Result<(), ()> {
+ //! ```compile_fail
+ //! fn test() -> Result< {}
+ //! ```
+ Ok(())
+}
+
+/// # Examples
+///
+/// ```
+/// use std::error::Error;
+/// fn main() -> Result<(), Box<dyn Error>/* > */ {
+/// }
+/// ```
+fn issue15041() {}
diff --git a/src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr b/src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr
new file mode 100644
index 0000000..dd5474c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr
@@ -0,0 +1,36 @@
+error: needless `fn main` in doctest
+ --> tests/ui/doc/needless_doctest_main.rs:23:5
+ |
+LL | /// fn main() {
+ | _____^
+LL | |
+LL | | /// let a = 0;
+LL | | /// }
+ | |_____^
+ |
+ = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]`
+
+error: needless `fn main` in doctest
+ --> tests/ui/doc/needless_doctest_main.rs:77:5
+ |
+LL | /// fn main() {
+ | _____^
+LL | |
+LL | | /// // Hi!
+LL | | /// let _ = 0;
+LL | | /// }
+ | |_____^
+
+error: needless `fn main` in doctest
+ --> tests/ui/doc/needless_doctest_main.rs:88:5
+ |
+LL | /// fn main (){
+ | _____^
+LL | |
+LL | | /// let _ = 0;
+LL | | /// }
+ | |_____^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc_broken_link.rs b/src/tools/clippy/tests/ui/doc_broken_link.rs
new file mode 100644
index 0000000..7d9c0ef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_broken_link.rs
@@ -0,0 +1,72 @@
+#![warn(clippy::doc_broken_link)]
+
+fn main() {}
+
+pub struct FakeType {}
+
+/// This might be considered a link false positive
+/// and should be ignored by this lint rule:
+/// Example of referencing some code with brackets [FakeType].
+pub fn doc_ignore_link_false_positive_1() {}
+
+/// This might be considered a link false positive
+/// and should be ignored by this lint rule:
+/// [`FakeType`]. Continue text after brackets,
+/// then (something in
+/// parenthesis).
+pub fn doc_ignore_link_false_positive_2() {}
+
+/// Test valid link, whole link single line.
+/// [doc valid link](https://test.fake/doc_valid_link)
+pub fn doc_valid_link() {}
+
+/// Test valid link, whole link single line but it has special chars such as brackets and
+/// parenthesis. [doc invalid link url invalid char](https://test.fake/doc_valid_link_url_invalid_char?foo[bar]=1&bar(foo)=2)
+pub fn doc_valid_link_url_invalid_char() {}
+
+/// Test valid link, text tag broken across multiple lines.
+/// [doc valid link broken
+/// text](https://test.fake/doc_valid_link_broken_text)
+pub fn doc_valid_link_broken_text() {}
+
+/// Test valid link, url tag broken across multiple lines, but
+/// the whole url part in a single line.
+/// [doc valid link broken url tag two lines first](https://test.fake/doc_valid_link_broken_url_tag_two_lines_first
+/// )
+pub fn doc_valid_link_broken_url_tag_two_lines_first() {}
+
+/// Test valid link, url tag broken across multiple lines, but
+/// the whole url part in a single line.
+/// [doc valid link broken url tag two lines second](
+/// https://test.fake/doc_valid_link_broken_url_tag_two_lines_second)
+pub fn doc_valid_link_broken_url_tag_two_lines_second() {}
+
+/// Test valid link, url tag broken across multiple lines, but
+/// the whole url part in a single line, but the closing pharentesis
+/// in a third line.
+/// [doc valid link broken url tag three lines](
+/// https://test.fake/doc_valid_link_broken_url_tag_three_lines
+/// )
+pub fn doc_valid_link_broken_url_tag_three_lines() {}
+
+/// Test invalid link, url part broken across multiple lines.
+/// [doc invalid link broken url scheme part](https://
+/// test.fake/doc_invalid_link_broken_url_scheme_part)
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+pub fn doc_invalid_link_broken_url_scheme_part() {}
+
+/// Test invalid link, url part broken across multiple lines.
+/// [doc invalid link broken url host part](https://test
+/// .fake/doc_invalid_link_broken_url_host_part)
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+pub fn doc_invalid_link_broken_url_host_part() {}
+
+/// Test invalid link, for multiple urls in the same block of comment.
+/// There is a [fist link - invalid](https://test
+/// .fake) then it continues
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+/// with a [second link - valid](https://test.fake/doc_valid_link) and another [third link - invalid](https://test
+/// .fake). It ends with another
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+/// line of comment.
+pub fn doc_multiple_invalid_link_broken_url() {}
diff --git a/src/tools/clippy/tests/ui/doc_broken_link.stderr b/src/tools/clippy/tests/ui/doc_broken_link.stderr
new file mode 100644
index 0000000..179ed97
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_broken_link.stderr
@@ -0,0 +1,29 @@
+error: possible broken doc link: broken across multiple lines
+ --> tests/ui/doc_broken_link.rs:53:5
+ |
+LL | /// [doc invalid link broken url scheme part](https://
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::doc-broken-link` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::doc_broken_link)]`
+
+error: possible broken doc link: broken across multiple lines
+ --> tests/ui/doc_broken_link.rs:59:5
+ |
+LL | /// [doc invalid link broken url host part](https://test
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible broken doc link: broken across multiple lines
+ --> tests/ui/doc_broken_link.rs:65:16
+ |
+LL | /// There is a [fist link - invalid](https://test
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible broken doc link: broken across multiple lines
+ --> tests/ui/doc_broken_link.rs:68:80
+ |
+LL | /// with a [second link - valid](https://test.fake/doc_valid_link) and another [third link - invalid](https://test
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed
index 36d80a2..e36e3c2 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed
@@ -105,4 +105,13 @@
")]
pub struct Args;
+mod issue_14980 {
+ //~v empty_line_after_outer_attr
+ #[repr(align(536870912))]
+ enum Aligned {
+ Zero = 0,
+ One = 1,
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed
index 0e8e412..b0908fc 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed
@@ -108,4 +108,13 @@
")]
pub struct Args;
+mod issue_14980 {
+ //~v empty_line_after_outer_attr
+ #[repr(align(536870912))]
+ enum Aligned {
+ Zero = 0,
+ One = 1,
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs
index 1295088..4ae113c 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs
@@ -116,4 +116,14 @@ fn foo() -> Vec<u8> {
")]
pub struct Args;
+mod issue_14980 {
+ //~v empty_line_after_outer_attr
+ #[repr(align(536870912))]
+
+ enum Aligned {
+ Zero = 0,
+ One = 1,
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
index 519ba6e..331bc7c 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
@@ -111,5 +111,16 @@
|
= help: if the empty lines are unintentional, remove them
-error: aborting due to 9 previous errors
+error: empty line after outer attribute
+ --> tests/ui/empty_line_after/outer_attribute.rs:121:5
+ |
+LL | / #[repr(align(536870912))]
+LL | |
+ | |_^
+LL | enum Aligned {
+ | ------------ the attribute applies to this enum
+ |
+ = help: if the empty line is unintentional, remove it
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 0ba631f..c93b83f 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -543,3 +543,21 @@
//~^ redundant_closure
}
}
+
+fn issue_14789() {
+ _ = Some(1u8).map(
+ #[expect(clippy::redundant_closure)]
+ |a| foo(a),
+ );
+
+ _ = Some("foo").map(
+ #[expect(clippy::redundant_closure_for_method_calls)]
+ |s| s.to_owned(),
+ );
+
+ let _: Vec<u8> = None.map_or_else(
+ #[expect(clippy::redundant_closure)]
+ || vec![],
+ std::convert::identity,
+ );
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 4d8b29d..273c8b2 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -543,3 +543,21 @@ pub fn foo() {
//~^ redundant_closure
}
}
+
+fn issue_14789() {
+ _ = Some(1u8).map(
+ #[expect(clippy::redundant_closure)]
+ |a| foo(a),
+ );
+
+ _ = Some("foo").map(
+ #[expect(clippy::redundant_closure_for_method_calls)]
+ |s| s.to_owned(),
+ );
+
+ let _: Vec<u8> = None.map_or_else(
+ #[expect(clippy::redundant_closure)]
+ || vec![],
+ std::convert::identity,
+ );
+}
diff --git a/src/tools/clippy/tests/ui/exhaustive_items.fixed b/src/tools/clippy/tests/ui/exhaustive_items.fixed
index 79c74ae..3b2f33d 100644
--- a/src/tools/clippy/tests/ui/exhaustive_items.fixed
+++ b/src/tools/clippy/tests/ui/exhaustive_items.fixed
@@ -1,3 +1,4 @@
+#![feature(default_field_values)]
#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
#![allow(unused)]
@@ -90,3 +91,9 @@
pub bar: String,
}
}
+
+pub mod issue14992 {
+ pub struct A {
+ pub a: isize = 42,
+ }
+}
diff --git a/src/tools/clippy/tests/ui/exhaustive_items.rs b/src/tools/clippy/tests/ui/exhaustive_items.rs
index 4e851f4..b0a6a71 100644
--- a/src/tools/clippy/tests/ui/exhaustive_items.rs
+++ b/src/tools/clippy/tests/ui/exhaustive_items.rs
@@ -1,3 +1,4 @@
+#![feature(default_field_values)]
#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
#![allow(unused)]
@@ -87,3 +88,9 @@ struct NonExhaustivePrivate {
pub bar: String,
}
}
+
+pub mod issue14992 {
+ pub struct A {
+ pub a: isize = 42,
+ }
+}
diff --git a/src/tools/clippy/tests/ui/exhaustive_items.stderr b/src/tools/clippy/tests/ui/exhaustive_items.stderr
index c92c8a9..55928fa 100644
--- a/src/tools/clippy/tests/ui/exhaustive_items.stderr
+++ b/src/tools/clippy/tests/ui/exhaustive_items.stderr
@@ -1,5 +1,5 @@
error: exported enums should not be exhaustive
- --> tests/ui/exhaustive_items.rs:9:5
+ --> tests/ui/exhaustive_items.rs:10:5
|
LL | / pub enum Exhaustive {
LL | |
@@ -11,7 +11,7 @@
| |_____^
|
note: the lint level is defined here
- --> tests/ui/exhaustive_items.rs:1:9
+ --> tests/ui/exhaustive_items.rs:2:9
|
LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@
|
error: exported enums should not be exhaustive
- --> tests/ui/exhaustive_items.rs:19:5
+ --> tests/ui/exhaustive_items.rs:20:5
|
LL | / pub enum ExhaustiveWithAttrs {
LL | |
@@ -40,7 +40,7 @@
|
error: exported structs should not be exhaustive
- --> tests/ui/exhaustive_items.rs:55:5
+ --> tests/ui/exhaustive_items.rs:56:5
|
LL | / pub struct Exhaustive {
LL | |
@@ -50,7 +50,7 @@
| |_____^
|
note: the lint level is defined here
- --> tests/ui/exhaustive_items.rs:1:35
+ --> tests/ui/exhaustive_items.rs:2:35
|
LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed
index a1b5560..4e14e1a 100644
--- a/src/tools/clippy/tests/ui/identity_op.fixed
+++ b/src/tools/clippy/tests/ui/identity_op.fixed
@@ -312,3 +312,49 @@
let _: u64 = 1u64 + ((x as i32 + y as i32) as u64);
//~^ identity_op
}
+
+fn issue_14932() {
+ let _ = 0usize + &Default::default(); // no error
+
+ 0usize + &Default::default(); // no error
+
+ <usize as Default>::default();
+ //~^ identity_op
+
+ let _ = usize::default();
+ //~^ identity_op
+
+ let _n: usize = Default::default();
+ //~^ identity_op
+}
+
+// Expr's type can be inferred by the function's return type
+fn issue_14932_2() -> usize {
+ Default::default()
+ //~^ identity_op
+}
+
+trait Def {
+ fn def() -> Self;
+}
+
+impl Def for usize {
+ fn def() -> Self {
+ 0
+ }
+}
+
+fn issue_14932_3() {
+ let _ = 0usize + &Def::def(); // no error
+
+ 0usize + &Def::def(); // no error
+
+ <usize as Def>::def();
+ //~^ identity_op
+
+ let _ = usize::def();
+ //~^ identity_op
+
+ let _n: usize = Def::def();
+ //~^ identity_op
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs
index f603e10..ebbef57 100644
--- a/src/tools/clippy/tests/ui/identity_op.rs
+++ b/src/tools/clippy/tests/ui/identity_op.rs
@@ -312,3 +312,49 @@ fn issue_13470() {
let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
//~^ identity_op
}
+
+fn issue_14932() {
+ let _ = 0usize + &Default::default(); // no error
+
+ 0usize + &Default::default(); // no error
+
+ 0usize + &<usize as Default>::default();
+ //~^ identity_op
+
+ let _ = 0usize + &usize::default();
+ //~^ identity_op
+
+ let _n: usize = 0usize + &Default::default();
+ //~^ identity_op
+}
+
+// Expr's type can be inferred by the function's return type
+fn issue_14932_2() -> usize {
+ 0usize + &Default::default()
+ //~^ identity_op
+}
+
+trait Def {
+ fn def() -> Self;
+}
+
+impl Def for usize {
+ fn def() -> Self {
+ 0
+ }
+}
+
+fn issue_14932_3() {
+ let _ = 0usize + &Def::def(); // no error
+
+ 0usize + &Def::def(); // no error
+
+ 0usize + &<usize as Def>::def();
+ //~^ identity_op
+
+ let _ = 0usize + &usize::def();
+ //~^ identity_op
+
+ let _n: usize = 0usize + &Def::def();
+ //~^ identity_op
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr
index 8f9c2b6..24fa5db 100644
--- a/src/tools/clippy/tests/ui/identity_op.stderr
+++ b/src/tools/clippy/tests/ui/identity_op.stderr
@@ -379,5 +379,47 @@
LL | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)`
-error: aborting due to 63 previous errors
+error: this operation has no effect
+ --> tests/ui/identity_op.rs:321:5
+ |
+LL | 0usize + &<usize as Default>::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `<usize as Default>::default()`
+
+error: this operation has no effect
+ --> tests/ui/identity_op.rs:324:13
+ |
+LL | let _ = 0usize + &usize::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `usize::default()`
+
+error: this operation has no effect
+ --> tests/ui/identity_op.rs:327:21
+ |
+LL | let _n: usize = 0usize + &Default::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Default::default()`
+
+error: this operation has no effect
+ --> tests/ui/identity_op.rs:333:5
+ |
+LL | 0usize + &Default::default()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Default::default()`
+
+error: this operation has no effect
+ --> tests/ui/identity_op.rs:352:5
+ |
+LL | 0usize + &<usize as Def>::def();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `<usize as Def>::def()`
+
+error: this operation has no effect
+ --> tests/ui/identity_op.rs:355:13
+ |
+LL | let _ = 0usize + &usize::def();
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `usize::def()`
+
+error: this operation has no effect
+ --> tests/ui/identity_op.rs:358:21
+ |
+LL | let _n: usize = 0usize + &Def::def();
+ | ^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Def::def()`
+
+error: aborting due to 70 previous errors
diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs
index 002a791..701a865 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.rs
+++ b/src/tools/clippy/tests/ui/infinite_iter.rs
@@ -38,7 +38,7 @@ fn infinite_iters() {
//~^ infinite_iter
// infinite iter
- (0_u64..).filter(|x| x % 2 == 0).last();
+ (0_u64..).filter(|x| x.is_multiple_of(2)).last();
//~^ infinite_iter
// not an infinite, because ranges are double-ended
diff --git a/src/tools/clippy/tests/ui/infinite_iter.stderr b/src/tools/clippy/tests/ui/infinite_iter.stderr
index 47133a2..b9e7c00 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.stderr
+++ b/src/tools/clippy/tests/ui/infinite_iter.stderr
@@ -42,8 +42,8 @@
error: infinite iteration detected
--> tests/ui/infinite_iter.rs:41:5
|
-LL | (0_u64..).filter(|x| x % 2 == 0).last();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | (0_u64..).filter(|x| x.is_multiple_of(2)).last();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: possible infinite iteration detected
--> tests/ui/infinite_iter.rs:53:5
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed
index 874f749..b18dda3 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.fixed
+++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed
@@ -30,15 +30,19 @@
let _ = map.clone().values().collect::<Vec<_>>();
//~^ iter_kv_map
- let _ = map.keys().filter(|x| *x % 2 == 0).count();
+ let _ = map.keys().filter(|x| x.is_multiple_of(2)).count();
//~^ iter_kv_map
// Don't lint
- let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map
+ .iter()
+ .filter(|(_, val)| val.is_multiple_of(2))
+ .map(|(key, _)| key)
+ .count();
let _ = map.iter().map(get_key).collect::<Vec<_>>();
// Linting the following could be an improvement to the lint
- // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+ // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
// Lint
let _ = map.keys().map(|key| key * 9).count();
@@ -84,15 +88,19 @@
let _ = map.clone().values().collect::<Vec<_>>();
//~^ iter_kv_map
- let _ = map.keys().filter(|x| *x % 2 == 0).count();
+ let _ = map.keys().filter(|x| x.is_multiple_of(2)).count();
//~^ iter_kv_map
// Don't lint
- let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map
+ .iter()
+ .filter(|(_, val)| val.is_multiple_of(2))
+ .map(|(key, _)| key)
+ .count();
let _ = map.iter().map(get_key).collect::<Vec<_>>();
// Linting the following could be an improvement to the lint
- // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+ // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
// Lint
let _ = map.keys().map(|key| key * 9).count();
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs
index f570e3c..729e4e8 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.rs
+++ b/src/tools/clippy/tests/ui/iter_kv_map.rs
@@ -30,15 +30,19 @@ fn ref_acceptor(v: &u32) -> u32 {
let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
//~^ iter_kv_map
- let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+ let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
//~^ iter_kv_map
// Don't lint
- let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map
+ .iter()
+ .filter(|(_, val)| val.is_multiple_of(2))
+ .map(|(key, _)| key)
+ .count();
let _ = map.iter().map(get_key).collect::<Vec<_>>();
// Linting the following could be an improvement to the lint
- // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+ // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
// Lint
let _ = map.iter().map(|(key, _value)| key * 9).count();
@@ -86,15 +90,19 @@ fn ref_acceptor(v: &u32) -> u32 {
let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
//~^ iter_kv_map
- let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+ let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
//~^ iter_kv_map
// Don't lint
- let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map
+ .iter()
+ .filter(|(_, val)| val.is_multiple_of(2))
+ .map(|(key, _)| key)
+ .count();
let _ = map.iter().map(get_key).collect::<Vec<_>>();
// Linting the following could be an improvement to the lint
- // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+ // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
// Lint
let _ = map.iter().map(|(key, _value)| key * 9).count();
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr
index 31ee76c..8f73541 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.stderr
+++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr
@@ -52,29 +52,29 @@
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:33:13
|
-LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:44:13
+ --> tests/ui/iter_kv_map.rs:48:13
|
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:46:13
+ --> tests/ui/iter_kv_map.rs:50:13
|
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:50:13
+ --> tests/ui/iter_kv_map.rs:54:13
|
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:54:13
+ --> tests/ui/iter_kv_map.rs:58:13
|
LL | let _ = map
| _____________^
@@ -97,85 +97,85 @@
|
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:65:13
+ --> tests/ui/iter_kv_map.rs:69:13
|
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:70:13
+ --> tests/ui/iter_kv_map.rs:74:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:72:13
+ --> tests/ui/iter_kv_map.rs:76:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:74:13
+ --> tests/ui/iter_kv_map.rs:78:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:77:13
+ --> tests/ui/iter_kv_map.rs:81:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:79:13
+ --> tests/ui/iter_kv_map.rs:83:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:82:13
+ --> tests/ui/iter_kv_map.rs:86:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:84:13
+ --> tests/ui/iter_kv_map.rs:88:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:87:13
+ --> tests/ui/iter_kv_map.rs:91:13
|
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:89:13
+ --> tests/ui/iter_kv_map.rs:93:13
|
-LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:100:13
+ --> tests/ui/iter_kv_map.rs:108:13
|
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:102:13
+ --> tests/ui/iter_kv_map.rs:110:13
|
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:106:13
+ --> tests/ui/iter_kv_map.rs:114:13
|
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:110:13
+ --> tests/ui/iter_kv_map.rs:118:13
|
LL | let _ = map
| _____________^
@@ -198,73 +198,73 @@
|
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:121:13
+ --> tests/ui/iter_kv_map.rs:129:13
|
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:137:13
+ --> tests/ui/iter_kv_map.rs:145:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:140:13
+ --> tests/ui/iter_kv_map.rs:148:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:143:13
+ --> tests/ui/iter_kv_map.rs:151:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:152:13
+ --> tests/ui/iter_kv_map.rs:160:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:155:13
+ --> tests/ui/iter_kv_map.rs:163:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:158:13
+ --> tests/ui/iter_kv_map.rs:166:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:161:13
+ --> tests/ui/iter_kv_map.rs:169:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's keys
- --> tests/ui/iter_kv_map.rs:164:13
+ --> tests/ui/iter_kv_map.rs:172:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:167:13
+ --> tests/ui/iter_kv_map.rs:175:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:170:13
+ --> tests/ui/iter_kv_map.rs:178:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's values
- --> tests/ui/iter_kv_map.rs:185:13
+ --> tests/ui/iter_kv_map.rs:193:13
|
LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()`
diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed
index 5e7a2ad..304eace 100644
--- a/src/tools/clippy/tests/ui/let_unit.fixed
+++ b/src/tools/clippy/tests/ui/let_unit.fixed
@@ -61,7 +61,7 @@
//~^ let_unit_value
.into_iter()
.map(|i| i * 2)
- .filter(|i| i % 2 == 0)
+ .filter(|i| i.is_multiple_of(2))
.map(|_| ())
.next()
.unwrap();
diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs
index 7b06f69..a02cb34 100644
--- a/src/tools/clippy/tests/ui/let_unit.rs
+++ b/src/tools/clippy/tests/ui/let_unit.rs
@@ -61,7 +61,7 @@ fn multiline_sugg() {
//~^ let_unit_value
.into_iter()
.map(|i| i * 2)
- .filter(|i| i % 2 == 0)
+ .filter(|i| i.is_multiple_of(2))
.map(|_| ())
.next()
.unwrap();
diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr
index d7d01d3..d743110 100644
--- a/src/tools/clippy/tests/ui/let_unit.stderr
+++ b/src/tools/clippy/tests/ui/let_unit.stderr
@@ -25,7 +25,7 @@
LL +
LL + .into_iter()
LL + .map(|i| i * 2)
-LL + .filter(|i| i % 2 == 0)
+LL + .filter(|i| i.is_multiple_of(2))
LL + .map(|_| ())
LL + .next()
LL + .unwrap();
diff --git a/src/tools/clippy/tests/ui/manual_contains.fixed b/src/tools/clippy/tests/ui/manual_contains.fixed
index d26c948..18171f0 100644
--- a/src/tools/clippy/tests/ui/manual_contains.fixed
+++ b/src/tools/clippy/tests/ui/manual_contains.fixed
@@ -58,7 +58,7 @@
let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
let values = &vec[..];
- let _ = values.iter().any(|&v| v % 2 == 0);
+ let _ = values.iter().any(|&v| v.is_multiple_of(2));
let _ = values.iter().any(|&v| v * 2 == 6);
let _ = values.iter().any(|&v| v == v);
let _ = values.iter().any(|&v| 4 == 4);
diff --git a/src/tools/clippy/tests/ui/manual_contains.rs b/src/tools/clippy/tests/ui/manual_contains.rs
index fe67d2e..918f4d6 100644
--- a/src/tools/clippy/tests/ui/manual_contains.rs
+++ b/src/tools/clippy/tests/ui/manual_contains.rs
@@ -58,7 +58,7 @@ fn should_not_lint() {
let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
let values = &vec[..];
- let _ = values.iter().any(|&v| v % 2 == 0);
+ let _ = values.iter().any(|&v| v.is_multiple_of(2));
let _ = values.iter().any(|&v| v * 2 == 6);
let _ = values.iter().any(|&v| v == v);
let _ = values.iter().any(|&v| 4 == 4);
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.fixed b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
index 01b3eba..c69b0cb 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.fixed
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
@@ -11,7 +11,7 @@
}
fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> {
- arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)
+ arr.into_iter().map(|(a, _)| a).find(|&a| a.is_multiple_of(2))
}
struct Data {
@@ -63,7 +63,7 @@
fn with_else(arr: Vec<u32>) -> Option<u32> {
for el in arr {
- if el % 2 == 0 {
+ if el.is_multiple_of(2) {
return Some(el);
} else {
println!("{}", el);
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.rs b/src/tools/clippy/tests/ui/manual_find_fixable.rs
index ce62a4b..db7092f 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.rs
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.rs
@@ -19,7 +19,7 @@ fn lookup(n: u32) -> Option<u32> {
fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> {
for (a, _) in arr {
//~^ manual_find
- if a % 2 == 0 {
+ if a.is_multiple_of(2) {
return Some(a);
}
}
@@ -111,7 +111,7 @@ fn with_side_effects(arr: Vec<u32>) -> Option<u32> {
fn with_else(arr: Vec<u32>) -> Option<u32> {
for el in arr {
- if el % 2 == 0 {
+ if el.is_multiple_of(2) {
return Some(el);
} else {
println!("{}", el);
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.stderr b/src/tools/clippy/tests/ui/manual_find_fixable.stderr
index 020635d..0c05c0d 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.stderr
@@ -17,11 +17,11 @@
|
LL | / for (a, _) in arr {
LL | |
-LL | | if a % 2 == 0 {
+LL | | if a.is_multiple_of(2) {
LL | | return Some(a);
... |
LL | | None
- | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)`
+ | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a.is_multiple_of(2))`
error: manual implementation of `Iterator::find`
--> tests/ui/manual_find_fixable.rs:34:5
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed
new file mode 100644
index 0000000..6735b99
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed
@@ -0,0 +1,25 @@
+//@aux-build: proc_macros.rs
+#![warn(clippy::manual_is_multiple_of)]
+
+fn main() {}
+
+#[clippy::msrv = "1.87"]
+fn f(a: u64, b: u64) {
+ let _ = a.is_multiple_of(b); //~ manual_is_multiple_of
+ let _ = (a + 1).is_multiple_of(b + 1); //~ manual_is_multiple_of
+ let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of
+ let _ = !(a + 1).is_multiple_of(b + 1); //~ manual_is_multiple_of
+
+ let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of
+ let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of
+
+ proc_macros::external! {
+ let a: u64 = 23424;
+ let _ = a % 4096 == 0;
+ }
+}
+
+#[clippy::msrv = "1.86"]
+fn g(a: u64, b: u64) {
+ let _ = a % b == 0;
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.rs b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs
new file mode 100644
index 0000000..00b638e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs
@@ -0,0 +1,25 @@
+//@aux-build: proc_macros.rs
+#![warn(clippy::manual_is_multiple_of)]
+
+fn main() {}
+
+#[clippy::msrv = "1.87"]
+fn f(a: u64, b: u64) {
+ let _ = a % b == 0; //~ manual_is_multiple_of
+ let _ = (a + 1) % (b + 1) == 0; //~ manual_is_multiple_of
+ let _ = a % b != 0; //~ manual_is_multiple_of
+ let _ = (a + 1) % (b + 1) != 0; //~ manual_is_multiple_of
+
+ let _ = a % b > 0; //~ manual_is_multiple_of
+ let _ = 0 < a % b; //~ manual_is_multiple_of
+
+ proc_macros::external! {
+ let a: u64 = 23424;
+ let _ = a % 4096 == 0;
+ }
+}
+
+#[clippy::msrv = "1.86"]
+fn g(a: u64, b: u64) {
+ let _ = a % b == 0;
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr
new file mode 100644
index 0000000..0b1ae70
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr
@@ -0,0 +1,41 @@
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:8:13
+ |
+LL | let _ = a % b == 0;
+ | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(b)`
+ |
+ = note: `-D clippy::manual-is-multiple-of` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::manual_is_multiple_of)]`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:9:13
+ |
+LL | let _ = (a + 1) % (b + 1) == 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(a + 1).is_multiple_of(b + 1)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:10:13
+ |
+LL | let _ = a % b != 0;
+ | ^^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:11:13
+ |
+LL | let _ = (a + 1) % (b + 1) != 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `!(a + 1).is_multiple_of(b + 1)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:13:13
+ |
+LL | let _ = a % b > 0;
+ | ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)`
+
+error: manual implementation of `.is_multiple_of()`
+ --> tests/ui/manual_is_multiple_of.rs:14:13
+ |
+LL | let _ = 0 < a % b;
+ | ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
index 18a7218..6425f32 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
@@ -77,7 +77,7 @@
let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
// Should not lint.
- let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true);
+ let _ = Foo::<u32>(0).map(|x| x.is_multiple_of(2)) == Some(true);
let _ = Some(2).map(|x| x % 2 == 0) != foo();
let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true));
let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true);
@@ -96,11 +96,11 @@
});
let _ = res.is_ok_and(|x| x > 1);
- let _ = Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+ let _ = Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2));
//~^ manual_is_variant_and
- let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+ let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2));
//~^ manual_is_variant_and
- let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+ let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2));
//~^ manual_is_variant_and
// won't fix because the return type of the closure is not `bool`
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.rs b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
index a92f7c0..e069e97 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.rs
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
@@ -83,7 +83,7 @@ fn option_methods() {
let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
// Should not lint.
- let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true);
+ let _ = Foo::<u32>(0).map(|x| x.is_multiple_of(2)) == Some(true);
let _ = Some(2).map(|x| x % 2 == 0) != foo();
let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true));
let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true);
@@ -105,11 +105,11 @@ fn result_methods() {
//~^ manual_is_variant_and
.unwrap_or_default();
- let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true);
+ let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) == Ok(true);
//~^ manual_is_variant_and
- let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+ let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
//~^ manual_is_variant_and
- let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+ let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
//~^ manual_is_variant_and
// won't fix because the return type of the closure is not `bool`
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
index 1fb437a..f770319 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
@@ -105,20 +105,20 @@
error: called `.map() == Ok()`
--> tests/ui/manual_is_variant_and.rs:108:13
|
-LL | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+LL | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) == Ok(true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))`
error: called `.map() != Ok()`
--> tests/ui/manual_is_variant_and.rs:110:13
|
-LL | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+LL | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))`
error: called `.map() != Ok()`
--> tests/ui/manual_is_variant_and.rs:112:13
|
-LL | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+LL | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))`
error: called `map(<f>).unwrap_or_default()` on a `Result` value
--> tests/ui/manual_is_variant_and.rs:119:18
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.fixed b/src/tools/clippy/tests/ui/manual_ok_err.fixed
index e6f799a..9b70ce0 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.fixed
+++ b/src/tools/clippy/tests/ui/manual_ok_err.fixed
@@ -103,3 +103,27 @@
};
//~^^^^^ manual_ok_err
}
+
+mod issue15051 {
+ struct Container {
+ field: Result<bool, ()>,
+ }
+
+ #[allow(clippy::needless_borrow)]
+ fn with_addr_of(x: &Container) -> Option<&bool> {
+ (&x.field).as_ref().ok()
+ }
+
+ fn from_fn(x: &Container) -> Option<&bool> {
+ let result_with_ref = || &x.field;
+ result_with_ref().as_ref().ok()
+ }
+
+ fn result_with_ref_mut(x: &mut Container) -> &mut Result<bool, ()> {
+ &mut x.field
+ }
+
+ fn from_fn_mut(x: &mut Container) -> Option<&mut bool> {
+ result_with_ref_mut(x).as_mut().ok()
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.rs b/src/tools/clippy/tests/ui/manual_ok_err.rs
index 972b2c4..dee90463 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.rs
+++ b/src/tools/clippy/tests/ui/manual_ok_err.rs
@@ -141,3 +141,39 @@ fn issue14239() {
};
//~^^^^^ manual_ok_err
}
+
+mod issue15051 {
+ struct Container {
+ field: Result<bool, ()>,
+ }
+
+ #[allow(clippy::needless_borrow)]
+ fn with_addr_of(x: &Container) -> Option<&bool> {
+ match &x.field {
+ //~^ manual_ok_err
+ Ok(panel) => Some(panel),
+ Err(_) => None,
+ }
+ }
+
+ fn from_fn(x: &Container) -> Option<&bool> {
+ let result_with_ref = || &x.field;
+ match result_with_ref() {
+ //~^ manual_ok_err
+ Ok(panel) => Some(panel),
+ Err(_) => None,
+ }
+ }
+
+ fn result_with_ref_mut(x: &mut Container) -> &mut Result<bool, ()> {
+ &mut x.field
+ }
+
+ fn from_fn_mut(x: &mut Container) -> Option<&mut bool> {
+ match result_with_ref_mut(x) {
+ //~^ manual_ok_err
+ Ok(panel) => Some(panel),
+ Err(_) => None,
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.stderr b/src/tools/clippy/tests/ui/manual_ok_err.stderr
index 040e170..448fbff 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.stderr
+++ b/src/tools/clippy/tests/ui/manual_ok_err.stderr
@@ -111,5 +111,35 @@
LL ~ };
|
-error: aborting due to 9 previous errors
+error: manual implementation of `ok`
+ --> tests/ui/manual_ok_err.rs:152:9
+ |
+LL | / match &x.field {
+LL | |
+LL | | Ok(panel) => Some(panel),
+LL | | Err(_) => None,
+LL | | }
+ | |_________^ help: replace with: `(&x.field).as_ref().ok()`
+
+error: manual implementation of `ok`
+ --> tests/ui/manual_ok_err.rs:161:9
+ |
+LL | / match result_with_ref() {
+LL | |
+LL | | Ok(panel) => Some(panel),
+LL | | Err(_) => None,
+LL | | }
+ | |_________^ help: replace with: `result_with_ref().as_ref().ok()`
+
+error: manual implementation of `ok`
+ --> tests/ui/manual_ok_err.rs:173:9
+ |
+LL | / match result_with_ref_mut(x) {
+LL | |
+LL | | Ok(panel) => Some(panel),
+LL | | Err(_) => None,
+LL | | }
+ | |_________^ help: replace with: `result_with_ref_mut(x).as_mut().ok()`
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
index 7e0d4fc..f1d5579 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
@@ -25,7 +25,7 @@
0u64.method();
}
-// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
+// False negative, see FIXME comment in `clippy_utils::qualify_min_const_fn`
fn could_be_const_but_does_not_trigger<T>(t: T)
where
T: const ConstTrait,
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
index 439da46..d495759 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
@@ -25,7 +25,7 @@ fn can_be_const() {
0u64.method();
}
-// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
+// False negative, see FIXME comment in `clippy_utils::qualify_min_const_fn`
fn could_be_const_but_does_not_trigger<T>(t: T)
where
T: const ConstTrait,
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
index 65eb2d5..95bf63e 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -221,3 +221,60 @@
//~^ missing_const_for_fn
*x += 1;
}
+
+mod issue_15079 {
+ pub trait Trait {}
+
+ pub struct Struct<T: Trait> {
+ _t: Option<T>,
+ }
+
+ impl<T: Trait> Struct<T> {
+ #[clippy::msrv = "1.60"]
+ pub fn new_1_60() -> Self {
+ Self { _t: None }
+ }
+
+ #[clippy::msrv = "1.61"]
+ pub const fn new_1_61() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+ }
+
+ pub struct S2<T> {
+ _t: Option<T>,
+ }
+
+ impl<T> S2<T> {
+ #[clippy::msrv = "1.60"]
+ pub const fn new_1_60() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+
+ #[clippy::msrv = "1.61"]
+ pub const fn new_1_61() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+ }
+
+ pub struct S3<T: ?Sized + 'static> {
+ _t: Option<&'static T>,
+ }
+
+ impl<T: ?Sized + 'static> S3<T> {
+ #[clippy::msrv = "1.60"]
+ pub const fn new_1_60() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+
+ #[clippy::msrv = "1.61"]
+ pub const fn new_1_61() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 3690d2f..8290be6 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -221,3 +221,60 @@ fn mut_add(x: &mut i32) {
//~^ missing_const_for_fn
*x += 1;
}
+
+mod issue_15079 {
+ pub trait Trait {}
+
+ pub struct Struct<T: Trait> {
+ _t: Option<T>,
+ }
+
+ impl<T: Trait> Struct<T> {
+ #[clippy::msrv = "1.60"]
+ pub fn new_1_60() -> Self {
+ Self { _t: None }
+ }
+
+ #[clippy::msrv = "1.61"]
+ pub fn new_1_61() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+ }
+
+ pub struct S2<T> {
+ _t: Option<T>,
+ }
+
+ impl<T> S2<T> {
+ #[clippy::msrv = "1.60"]
+ pub fn new_1_60() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+
+ #[clippy::msrv = "1.61"]
+ pub fn new_1_61() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+ }
+
+ pub struct S3<T: ?Sized + 'static> {
+ _t: Option<&'static T>,
+ }
+
+ impl<T: ?Sized + 'static> S3<T> {
+ #[clippy::msrv = "1.60"]
+ pub fn new_1_60() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+
+ #[clippy::msrv = "1.61"]
+ pub fn new_1_61() -> Self {
+ //~^ missing_const_for_fn
+ Self { _t: None }
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 10e07d1..17cbc43 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -332,5 +332,75 @@
LL | const fn mut_add(x: &mut i32) {
| +++++
-error: aborting due to 25 previous errors
+error: this could be a `const fn`
+ --> tests/ui/missing_const_for_fn/could_be_const.rs:239:9
+ |
+LL | / pub fn new_1_61() -> Self {
+LL | |
+LL | | Self { _t: None }
+LL | | }
+ | |_________^
+ |
+help: make the function `const`
+ |
+LL | pub const fn new_1_61() -> Self {
+ | +++++
+
+error: this could be a `const fn`
+ --> tests/ui/missing_const_for_fn/could_be_const.rs:251:9
+ |
+LL | / pub fn new_1_60() -> Self {
+LL | |
+LL | | Self { _t: None }
+LL | | }
+ | |_________^
+ |
+help: make the function `const`
+ |
+LL | pub const fn new_1_60() -> Self {
+ | +++++
+
+error: this could be a `const fn`
+ --> tests/ui/missing_const_for_fn/could_be_const.rs:257:9
+ |
+LL | / pub fn new_1_61() -> Self {
+LL | |
+LL | | Self { _t: None }
+LL | | }
+ | |_________^
+ |
+help: make the function `const`
+ |
+LL | pub const fn new_1_61() -> Self {
+ | +++++
+
+error: this could be a `const fn`
+ --> tests/ui/missing_const_for_fn/could_be_const.rs:269:9
+ |
+LL | / pub fn new_1_60() -> Self {
+LL | |
+LL | | Self { _t: None }
+LL | | }
+ | |_________^
+ |
+help: make the function `const`
+ |
+LL | pub const fn new_1_60() -> Self {
+ | +++++
+
+error: this could be a `const fn`
+ --> tests/ui/missing_const_for_fn/could_be_const.rs:275:9
+ |
+LL | / pub fn new_1_61() -> Self {
+LL | |
+LL | | Self { _t: None }
+LL | | }
+ | |_________^
+ |
+help: make the function `const`
+ |
+LL | pub const fn new_1_61() -> Self {
+ | +++++
+
+error: aborting due to 30 previous errors
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
index 0e3e4cf..ecb82a2 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -179,7 +179,7 @@
--> tests/ui/nonminimal_bool.rs:186:8
|
LL | if !b != true {}
- | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)`
+ | ^^^^^^^^^^ help: try simplifying it as shown: `!!b`
error: this boolean expression can be simplified
--> tests/ui/nonminimal_bool.rs:189:8
@@ -209,7 +209,7 @@
--> tests/ui/nonminimal_bool.rs:193:8
|
LL | if true != !b {}
- | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)`
+ | ^^^^^^^^^^ help: try simplifying it as shown: `!!b`
error: this boolean expression can be simplified
--> tests/ui/nonminimal_bool.rs:196:8
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index a1119d7..34f3e04 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -5,6 +5,7 @@
clippy::uninlined_format_args,
clippy::unnecessary_wraps,
clippy::unnecessary_literal_unwrap,
+ clippy::unnecessary_result_map_or_else,
clippy::useless_vec
)]
@@ -409,4 +410,33 @@
//~^ or_fun_call
}
+mod result_map_or {
+ fn g() -> i32 {
+ 3
+ }
+
+ fn f(n: i32) -> i32 {
+ n
+ }
+
+ fn test_map_or() {
+ let x: Result<i32, ()> = Ok(4);
+ let _ = x.map_or_else(|_| g(), |v| v);
+ //~^ or_fun_call
+ let _ = x.map_or_else(|_| g(), f);
+ //~^ or_fun_call
+ let _ = x.map_or(0, f);
+ }
+}
+
+fn test_option_get_or_insert() {
+ // assume that this is slow call
+ fn g() -> u8 {
+ 99
+ }
+ let mut x = Some(42_u8);
+ let _ = x.get_or_insert_with(g);
+ //~^ or_fun_call
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index a7cd632..dc57bd6 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -5,6 +5,7 @@
clippy::uninlined_format_args,
clippy::unnecessary_wraps,
clippy::unnecessary_literal_unwrap,
+ clippy::unnecessary_result_map_or_else,
clippy::useless_vec
)]
@@ -409,4 +410,33 @@ fn f() -> i32 {
//~^ or_fun_call
}
+mod result_map_or {
+ fn g() -> i32 {
+ 3
+ }
+
+ fn f(n: i32) -> i32 {
+ n
+ }
+
+ fn test_map_or() {
+ let x: Result<i32, ()> = Ok(4);
+ let _ = x.map_or(g(), |v| v);
+ //~^ or_fun_call
+ let _ = x.map_or(g(), f);
+ //~^ or_fun_call
+ let _ = x.map_or(0, f);
+ }
+}
+
+fn test_option_get_or_insert() {
+ // assume that this is slow call
+ fn g() -> u8 {
+ 99
+ }
+ let mut x = Some(42_u8);
+ let _ = x.get_or_insert(g());
+ //~^ or_fun_call
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 35bda7e..0f159fe 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -1,5 +1,5 @@
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:52:22
+ --> tests/ui/or_fun_call.rs:53:22
|
LL | with_constructor.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)`
@@ -8,7 +8,7 @@
= help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:56:14
+ --> tests/ui/or_fun_call.rs:57:14
|
LL | with_new.unwrap_or(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
@@ -17,199 +17,199 @@
= help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:60:21
+ --> tests/ui/or_fun_call.rs:61:21
|
LL | with_const_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:64:14
+ --> tests/ui/or_fun_call.rs:65:14
|
LL | with_err.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:68:19
+ --> tests/ui/or_fun_call.rs:69:19
|
LL | with_err_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:72:24
+ --> tests/ui/or_fun_call.rs:73:24
|
LL | with_default_trait.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:76:23
+ --> tests/ui/or_fun_call.rs:77:23
|
LL | with_default_type.unwrap_or(u64::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:80:18
+ --> tests/ui/or_fun_call.rs:81:18
|
LL | self_default.unwrap_or(<FakeDefault>::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:84:18
+ --> tests/ui/or_fun_call.rs:85:18
|
LL | real_default.unwrap_or(<FakeDefault as Default>::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:88:14
+ --> tests/ui/or_fun_call.rs:89:14
|
LL | with_vec.unwrap_or(vec![]);
| ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:92:21
+ --> tests/ui/or_fun_call.rs:93:21
|
LL | without_default.unwrap_or(Foo::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
error: use of `or_insert` to construct default value
- --> tests/ui/or_fun_call.rs:96:19
+ --> tests/ui/or_fun_call.rs:97:19
|
LL | map.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert` to construct default value
- --> tests/ui/or_fun_call.rs:100:23
+ --> tests/ui/or_fun_call.rs:101:23
|
LL | map_vec.entry(42).or_insert(vec![]);
| ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert` to construct default value
- --> tests/ui/or_fun_call.rs:104:21
+ --> tests/ui/or_fun_call.rs:105:21
|
LL | btree.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert` to construct default value
- --> tests/ui/or_fun_call.rs:108:25
+ --> tests/ui/or_fun_call.rs:109:25
|
LL | btree_vec.entry(42).or_insert(vec![]);
| ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:112:21
+ --> tests/ui/or_fun_call.rs:113:21
|
LL | let _ = stringy.unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `ok_or`
- --> tests/ui/or_fun_call.rs:117:17
+ --> tests/ui/or_fun_call.rs:118:17
|
LL | let _ = opt.ok_or(format!("{} world.", hello));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:122:21
+ --> tests/ui/or_fun_call.rs:123:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:125:21
+ --> tests/ui/or_fun_call.rs:126:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
error: function call inside of `or`
- --> tests/ui/or_fun_call.rs:150:35
+ --> tests/ui/or_fun_call.rs:151:35
|
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:193:18
+ --> tests/ui/or_fun_call.rs:194:18
|
LL | None.unwrap_or(ptr_to_ref(s));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:201:14
+ --> tests/ui/or_fun_call.rs:202:14
|
LL | None.unwrap_or(unsafe { ptr_to_ref(s) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:204:14
+ --> tests/ui/or_fun_call.rs:205:14
|
LL | None.unwrap_or( unsafe { ptr_to_ref(s) } );
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:280:25
+ --> tests/ui/or_fun_call.rs:281:25
|
LL | let _ = Some(4).map_or(g(), |v| v);
| ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)`
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:282:25
+ --> tests/ui/or_fun_call.rs:283:25
|
LL | let _ = Some(4).map_or(g(), f);
| ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:314:18
+ --> tests/ui/or_fun_call.rs:315:18
|
LL | with_new.unwrap_or_else(Vec::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:318:28
+ --> tests/ui/or_fun_call.rs:319:28
|
LL | with_default_trait.unwrap_or_else(Default::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:322:27
+ --> tests/ui/or_fun_call.rs:323:27
|
LL | with_default_type.unwrap_or_else(u64::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:326:22
+ --> tests/ui/or_fun_call.rs:327:22
|
LL | real_default.unwrap_or_else(<FakeDefault as Default>::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `or_insert_with` to construct default value
- --> tests/ui/or_fun_call.rs:330:23
+ --> tests/ui/or_fun_call.rs:331:23
|
LL | map.entry(42).or_insert_with(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert_with` to construct default value
- --> tests/ui/or_fun_call.rs:334:25
+ --> tests/ui/or_fun_call.rs:335:25
|
LL | btree.entry(42).or_insert_with(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:338:25
+ --> tests/ui/or_fun_call.rs:339:25
|
LL | let _ = stringy.unwrap_or_else(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:380:17
+ --> tests/ui/or_fun_call.rs:381:17
|
LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)`
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:385:17
+ --> tests/ui/or_fun_call.rs:386:17
|
LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)`
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:390:17
+ --> tests/ui/or_fun_call.rs:391:17
|
LL | let _ = opt.unwrap_or({
| _________________^
@@ -229,22 +229,40 @@
|
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:396:17
+ --> tests/ui/or_fun_call.rs:397:17
|
LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)`
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:401:17
+ --> tests/ui/or_fun_call.rs:402:17
|
LL | let _ = opt.unwrap_or({ i32::default() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:408:21
+ --> tests/ui/or_fun_call.rs:409:21
|
LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
-error: aborting due to 38 previous errors
+error: function call inside of `map_or`
+ --> tests/ui/or_fun_call.rs:424:19
+ |
+LL | let _ = x.map_or(g(), |v| v);
+ | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)`
+
+error: function call inside of `map_or`
+ --> tests/ui/or_fun_call.rs:426:19
+ |
+LL | let _ = x.map_or(g(), f);
+ | ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
+
+error: function call inside of `get_or_insert`
+ --> tests/ui/or_fun_call.rs:438:15
+ |
+LL | let _ = x.get_or_insert(g());
+ | ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
+
+error: aborting due to 41 previous errors
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 60dc1c1..8d6f5fb 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -453,3 +453,15 @@
None
}
+
+fn issue_13642(x: Option<i32>) -> Option<()> {
+ let Some(x) = x else {
+ #[cfg(false)]
+ panic!();
+
+ #[cfg(true)]
+ return None;
+ };
+
+ None
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index 99d0122..f13eee2 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -549,3 +549,15 @@ fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> {
None
}
+
+fn issue_13642(x: Option<i32>) -> Option<()> {
+ let Some(x) = x else {
+ #[cfg(false)]
+ panic!();
+
+ #[cfg(true)]
+ return None;
+ };
+
+ None
+}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
index 666ff78..cf52ecf 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
@@ -169,9 +169,9 @@
// #13476
#[const_trait]
trait ConstTrait {}
-const fn const_trait_bounds_good<T: ConstTrait + ~const ConstTrait>() {}
+const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
-const fn const_trait_bounds_bad<T: ~const ConstTrait>() {}
+const fn const_trait_bounds_bad<T: [const] ConstTrait>() {}
//~^ trait_duplication_in_bounds
fn projections<T, U, V>()
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
index a1a86fe..955562f 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
@@ -169,9 +169,9 @@ fn assoc_tys_generics<'a, 'b, T, U>()
// #13476
#[const_trait]
trait ConstTrait {}
-const fn const_trait_bounds_good<T: ConstTrait + ~const ConstTrait>() {}
+const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
-const fn const_trait_bounds_bad<T: ~const ConstTrait + ~const ConstTrait>() {}
+const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
//~^ trait_duplication_in_bounds
fn projections<T, U, V>()
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
index d76b4e4..ab31721 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
@@ -61,8 +61,8 @@
error: these bounds contain repeated elements
--> tests/ui/trait_duplication_in_bounds.rs:174:36
|
-LL | const fn const_trait_bounds_bad<T: ~const ConstTrait + ~const ConstTrait>() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `~const ConstTrait`
+LL | const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[const] ConstTrait`
error: these where clauses contain repeated elements
--> tests/ui/trait_duplication_in_bounds.rs:181:8
diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
index 6652efd..66590be 100644
--- a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
@@ -21,3 +21,16 @@ fn main() {
let _: String = format!("{:?}", os_str); //~ unnecessary_debug_formatting
let _: String = format!("{:?}", os_string); //~ unnecessary_debug_formatting
}
+
+#[clippy::msrv = "1.86"]
+fn msrv_1_86() {
+ let os_str = OsStr::new("test");
+ println!("{:?}", os_str);
+}
+
+#[clippy::msrv = "1.87"]
+fn msrv_1_87() {
+ let os_str = OsStr::new("test");
+ println!("{:?}", os_str);
+ //~^ unnecessary_debug_formatting
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
index 382e59b..f04d2d5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
@@ -54,5 +54,14 @@
= help: use `Display` formatting and change this to `os_string.display()`
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
-error: aborting due to 6 previous errors
+error: unnecessary `Debug` formatting in `println!` args
+ --> tests/ui/unnecessary_os_str_debug_formatting.rs:34:22
+ |
+LL | println!("{:?}", os_str);
+ | ^^^^^^
+ |
+ = help: use `Display` formatting and change this to `os_str.display()`
+ = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
+
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
index 141ff6e..5f738a2 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -91,6 +91,21 @@
}
{
+ pub enum Enum {
+ A,
+ B,
+ C(u8),
+ D(u8, u8),
+ E { e: u8 },
+ };
+ match Enum::A {
+ Enum::A => (),
+ Enum::B | Enum::C(_) | Enum::D(..) | Enum::E { .. } => (),
+ //~^ wildcard_enum_match_arm
+ }
+ }
+
+ {
#![allow(clippy::manual_non_exhaustive)]
pub enum Enum {
A,
@@ -105,3 +120,17 @@
}
}
}
+
+fn issue15091() {
+ enum Foo {
+ A,
+ B,
+ C,
+ }
+
+ match Foo::A {
+ Foo::A => {},
+ r#type @ Foo::B | r#type @ Foo::C => {},
+ //~^ wildcard_enum_match_arm
+ }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
index a13684e..4bc4bfd 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
@@ -91,6 +91,21 @@ fn main() {
}
{
+ pub enum Enum {
+ A,
+ B,
+ C(u8),
+ D(u8, u8),
+ E { e: u8 },
+ };
+ match Enum::A {
+ Enum::A => (),
+ _ => (),
+ //~^ wildcard_enum_match_arm
+ }
+ }
+
+ {
#![allow(clippy::manual_non_exhaustive)]
pub enum Enum {
A,
@@ -105,3 +120,17 @@ pub enum Enum {
}
}
}
+
+fn issue15091() {
+ enum Foo {
+ A,
+ B,
+ C,
+ }
+
+ match Foo::A {
+ Foo::A => {},
+ r#type => {},
+ //~^ wildcard_enum_match_arm
+ }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index 088c6b7..d092998 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -38,7 +38,19 @@
--> tests/ui/wildcard_enum_match_arm.rs:103:13
|
LL | _ => (),
+ | ^ help: try: `Enum::B | Enum::C(_) | Enum::D(..) | Enum::E { .. }`
+
+error: wildcard match will also match any future added variants
+ --> tests/ui/wildcard_enum_match_arm.rs:118:13
+ |
+LL | _ => (),
| ^ help: try: `Enum::B | Enum::__Private`
-error: aborting due to 6 previous errors
+error: wildcard match will also match any future added variants
+ --> tests/ui/wildcard_enum_match_arm.rs:133:9
+ |
+LL | r#type => {},
+ | ^^^^^^ help: try: `r#type @ Foo::B | r#type @ Foo::C`
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index f6fc235..b017938 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -27,6 +27,7 @@ fn read_version(path: &str) -> String {
"clippy_config/Cargo.toml",
"clippy_lints/Cargo.toml",
"clippy_utils/Cargo.toml",
+ "declare_clippy_lint/Cargo.toml",
];
for path in paths {
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 16557a4..4f37075 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -17,6 +17,9 @@
[issue-links]
+[mentions."clippy_lints/src/doc"]
+cc = ["@notriddle"]
+
# Prevents mentions in commits to avoid users being spammed
[no-mentions]
diff --git a/src/tools/clippy/util/versions.py b/src/tools/clippy/util/versions.py
index fee0d29..6e06d77 100755
--- a/src/tools/clippy/util/versions.py
+++ b/src/tools/clippy/util/versions.py
@@ -6,11 +6,11 @@
import sys
def key(v):
- if v == "master":
- return sys.maxsize
if v == "stable":
- return sys.maxsize - 1
+ return sys.maxsize
if v == "beta":
+ return sys.maxsize - 1
+ if v == "master":
return sys.maxsize - 2
if v == "pre-1.29.0":
return -1
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 192d4f4..d3123ca 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -81,6 +81,15 @@
]
[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -113,6 +122,26 @@
]
[[package]]
+name = "capstone"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
+dependencies = [
+ "capstone-sys",
+ "libc",
+]
+
+[[package]]
+name = "capstone-sys"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
name = "cargo-platform"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -151,6 +180,12 @@
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
name = "chrono"
version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -224,7 +259,7 @@
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -243,7 +278,7 @@
"libc",
"once_cell",
"unicode-width 0.2.0",
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -298,7 +333,7 @@
"libc",
"option-ext",
"redox_users",
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -314,7 +349,7 @@
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
dependencies = [
"libc",
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -334,6 +369,12 @@
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -401,6 +442,25 @@
]
[[package]]
+name = "ipc-channel"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fb8251fb7bcd9ccd3725ed8deae9fe7db8e586495c9eb5b0c52e6233e5e75ea"
+dependencies = [
+ "bincode",
+ "crossbeam-channel",
+ "fnv",
+ "lazy_static",
+ "libc",
+ "mio",
+ "rand 0.8.5",
+ "serde",
+ "tempfile",
+ "uuid",
+ "windows",
+]
+
+[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -534,23 +594,39 @@
]
[[package]]
+name = "mio"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+dependencies = [
+ "libc",
+ "log",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "miri"
version = "0.1.0"
dependencies = [
"aes",
"bitflags",
+ "capstone",
"chrono",
"chrono-tz",
"colored",
"directories",
"getrandom 0.3.2",
+ "ipc-channel",
"libc",
"libffi",
"libloading",
"measureme",
+ "nix",
"rand 0.9.0",
"regex",
"rustc_version",
+ "serde",
"smallvec",
"tempfile",
"tikv-jemalloc-sys",
@@ -558,6 +634,18 @@
]
[[package]]
+name = "nix"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -748,6 +836,8 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
"rand_core 0.6.4",
]
@@ -757,13 +847,23 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
- "rand_chacha",
+ "rand_chacha 0.9.0",
"rand_core 0.9.3",
"zerocopy",
]
[[package]]
name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
@@ -777,6 +877,9 @@
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.15",
+]
[[package]]
name = "rand_core"
@@ -879,7 +982,7 @@
"errno",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -993,7 +1096,7 @@
"getrandom 0.3.2",
"once_cell",
"rustix",
- "windows-sys",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -1148,6 +1251,15 @@
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
+name = "uuid"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+dependencies = [
+ "getrandom 0.3.2",
+]
+
+[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1242,6 +1354,79 @@
]
[[package]]
+name = "windows"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
+dependencies = [
+ "windows-core",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-result",
+ "windows-strings",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index a314488..0b4b8e2 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -40,6 +40,12 @@
libffi = "4.0.0"
libloading = "0.8"
+[target.'cfg(target_os = "linux")'.dependencies]
+nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"] }
+ipc-channel = "0.19.0"
+serde = { version = "1.0.219", features = ["derive"] }
+capstone = "0.13"
+
[dev-dependencies]
ui_test = "0.29.1"
colored = "2"
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 5554c79..e609fb9 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -419,6 +419,9 @@
Finally, the flag is **unsound** in the sense that Miri stops tracking details such as
initialization and provenance on memory shared with native code, so it is easily possible to write
code that has UB which is missed by Miri.
+* `-Zmiri-native-lib-enable-tracing` enables the WIP detailed tracing mode for invoking native code.
+ Note that this flag is only meaningful on Linux systems; other Unixes (currently) do not support
+ tracing mode.
* `-Zmiri-measureme=<name>` enables `measureme` profiling for the interpreted program.
This can be used to find which parts of your program are executing slowly under Miri.
The profile is written out to a file inside a directory called `<name>`, and can be processed
@@ -592,7 +595,7 @@
* [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084))
* [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281)
* [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo)
-* [Mockall reading unintialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
+* [Mockall reading uninitialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
* [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248)
Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index b9b58c0..e399f66 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -83,7 +83,7 @@ pub fn setup(
SysrootConfig::NoStd
} else {
SysrootConfig::WithStd {
- std_features: ["panic_unwind", "backtrace"].into_iter().map(Into::into).collect(),
+ std_features: ["panic-unwind", "backtrace"].into_iter().map(Into::into).collect(),
}
};
let cargo_cmd = {
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 8636214..d18e9c7 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -32,6 +32,7 @@ fn build_miri_sysroot(
&mut self,
quiet: bool,
target: Option<impl AsRef<OsStr>>,
+ features: &[String],
) -> Result<PathBuf> {
if let Some(miri_sysroot) = self.sh.var_os("MIRI_SYSROOT") {
// Sysroot already set, use that.
@@ -39,8 +40,8 @@ fn build_miri_sysroot(
}
// Make sure everything is built. Also Miri itself.
- self.build(".", &[], quiet)?;
- self.build("cargo-miri", &[], quiet)?;
+ self.build(".", features, &[], quiet)?;
+ self.build("cargo-miri", &[], &[], quiet)?;
let target_flag = if let Some(target) = &target {
vec![OsStr::new("--target"), target.as_ref()]
@@ -58,7 +59,7 @@ fn build_miri_sysroot(
}
let mut cmd = self
- .cargo_cmd("cargo-miri", "run")
+ .cargo_cmd("cargo-miri", "run", &[])
.arg("--quiet")
.arg("--")
.args(&["miri", "setup", "--print-sysroot"])
@@ -90,7 +91,9 @@ fn auto_actions() -> Result<()> {
Self::fmt(vec![])?;
}
if auto_clippy {
- Self::clippy(vec![])?;
+ // no features for auto actions, see
+ // https://github.com/rust-lang/miri/pull/4396#discussion_r2149654845
+ Self::clippy(vec![], vec![])?;
}
Ok(())
@@ -175,16 +178,16 @@ pub fn exec(self) -> Result<()> {
}
// Then run the actual command.
match self {
- Command::Install { flags } => Self::install(flags),
- Command::Build { flags } => Self::build(flags),
- Command::Check { flags } => Self::check(flags),
- Command::Test { bless, flags, target, coverage } =>
- Self::test(bless, flags, target, coverage),
- Command::Run { dep, verbose, target, edition, flags } =>
- Self::run(dep, verbose, target, edition, flags),
- Command::Doc { flags } => Self::doc(flags),
+ Command::Install { features, flags } => Self::install(features, flags),
+ Command::Build { features, flags } => Self::build(features, flags),
+ Command::Check { features, flags } => Self::check(features, flags),
+ Command::Test { bless, target, coverage, features, flags } =>
+ Self::test(bless, target, coverage, features, flags),
+ Command::Run { dep, verbose, target, edition, features, flags } =>
+ Self::run(dep, verbose, target, edition, features, flags),
+ Command::Doc { features, flags } => Self::doc(features, flags),
Command::Fmt { flags } => Self::fmt(flags),
- Command::Clippy { flags } => Self::clippy(flags),
+ Command::Clippy { features, flags } => Self::clippy(features, flags),
Command::Bench { target, no_install, save_baseline, load_baseline, benches } =>
Self::bench(target, no_install, save_baseline, load_baseline, benches),
Command::Toolchain { flags } => Self::toolchain(flags),
@@ -494,7 +497,7 @@ fn bench(
if !no_install {
// Make sure we have an up-to-date Miri installed and selected the right toolchain.
- Self::install(vec![])?;
+ Self::install(vec![], vec![])?;
}
let results_json_dir = if save_baseline.is_some() || load_baseline.is_some() {
Some(TempDir::new()?)
@@ -601,47 +604,48 @@ struct BenchResult {
Ok(())
}
- fn install(flags: Vec<String>) -> Result<()> {
+ fn install(features: Vec<String>, flags: Vec<String>) -> Result<()> {
let e = MiriEnv::new()?;
- e.install_to_sysroot(e.miri_dir.clone(), &flags)?;
- e.install_to_sysroot(path!(e.miri_dir / "cargo-miri"), &flags)?;
+ e.install_to_sysroot(".", &features, &flags)?;
+ e.install_to_sysroot("cargo-miri", &[], &flags)?;
Ok(())
}
- fn build(flags: Vec<String>) -> Result<()> {
+ fn build(features: Vec<String>, flags: Vec<String>) -> Result<()> {
let e = MiriEnv::new()?;
- e.build(".", &flags, /* quiet */ false)?;
- e.build("cargo-miri", &flags, /* quiet */ false)?;
+ e.build(".", &features, &flags, /* quiet */ false)?;
+ e.build("cargo-miri", &[], &flags, /* quiet */ false)?;
Ok(())
}
- fn check(flags: Vec<String>) -> Result<()> {
+ fn check(features: Vec<String>, flags: Vec<String>) -> Result<()> {
let e = MiriEnv::new()?;
- e.check(".", &flags)?;
- e.check("cargo-miri", &flags)?;
+ e.check(".", &features, &flags)?;
+ e.check("cargo-miri", &[], &flags)?;
Ok(())
}
- fn doc(flags: Vec<String>) -> Result<()> {
+ fn doc(features: Vec<String>, flags: Vec<String>) -> Result<()> {
let e = MiriEnv::new()?;
- e.doc(".", &flags)?;
- e.doc("cargo-miri", &flags)?;
+ e.doc(".", &features, &flags)?;
+ e.doc("cargo-miri", &[], &flags)?;
Ok(())
}
- fn clippy(flags: Vec<String>) -> Result<()> {
+ fn clippy(features: Vec<String>, flags: Vec<String>) -> Result<()> {
let e = MiriEnv::new()?;
- e.clippy(".", &flags)?;
- e.clippy("cargo-miri", &flags)?;
- e.clippy("miri-script", &flags)?;
+ e.clippy(".", &features, &flags)?;
+ e.clippy("cargo-miri", &[], &flags)?;
+ e.clippy("miri-script", &[], &flags)?;
Ok(())
}
fn test(
bless: bool,
- mut flags: Vec<String>,
target: Option<String>,
coverage: bool,
+ features: Vec<String>,
+ mut flags: Vec<String>,
) -> Result<()> {
let mut e = MiriEnv::new()?;
@@ -652,7 +656,7 @@ fn test(
}
// Prepare a sysroot. (Also builds cargo-miri, which we need.)
- e.build_miri_sysroot(/* quiet */ false, target.as_deref())?;
+ e.build_miri_sysroot(/* quiet */ false, target.as_deref(), &features)?;
// Forward information to test harness.
if bless {
@@ -672,10 +676,10 @@ fn test(
// Then test, and let caller control flags.
// Only in root project as `cargo-miri` has no tests.
- e.test(".", &flags)?;
+ e.test(".", &features, &flags)?;
if let Some(coverage) = &coverage {
- coverage.show_coverage_report(&e)?;
+ coverage.show_coverage_report(&e, &features)?;
}
Ok(())
@@ -686,14 +690,17 @@ fn run(
verbose: bool,
target: Option<String>,
edition: Option<String>,
+ features: Vec<String>,
flags: Vec<String>,
) -> Result<()> {
let mut e = MiriEnv::new()?;
// Preparation: get a sysroot, and get the miri binary.
- let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?;
- let miri_bin =
- e.build_get_binary(".").context("failed to get filename of miri executable")?;
+ let miri_sysroot =
+ e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref(), &features)?;
+ let miri_bin = e
+ .build_get_binary(".", &features)
+ .context("failed to get filename of miri executable")?;
// More flags that we will pass before `flags`
// (because `flags` may contain `--`).
@@ -718,7 +725,7 @@ fn run(
// The basic command that executes the Miri driver.
let mut cmd = if dep {
// We invoke the test suite as that has all the logic for running with dependencies.
- e.cargo_cmd(".", "test")
+ e.cargo_cmd(".", "test", &features)
.args(&["--test", "ui"])
.args(quiet_flag)
.arg("--")
diff --git a/src/tools/miri/miri-script/src/coverage.rs b/src/tools/miri/miri-script/src/coverage.rs
index 8cafcea..cdf2bbb 100644
--- a/src/tools/miri/miri-script/src/coverage.rs
+++ b/src/tools/miri/miri-script/src/coverage.rs
@@ -49,7 +49,7 @@ pub fn add_env_vars(&self, e: &mut MiriEnv) -> Result<()> {
/// show_coverage_report will print coverage information using the artifact
/// files in `self.path`.
- pub fn show_coverage_report(&self, e: &MiriEnv) -> Result<()> {
+ pub fn show_coverage_report(&self, e: &MiriEnv, features: &[String]) -> Result<()> {
let profraw_files = self.profraw_files()?;
let profdata_bin = path!(e.libdir / ".." / "bin" / "llvm-profdata");
@@ -63,8 +63,9 @@ pub fn show_coverage_report(&self, e: &MiriEnv) -> Result<()> {
// Create the coverage report.
let cov_bin = path!(e.libdir / ".." / "bin" / "llvm-cov");
- let miri_bin =
- e.build_get_binary(".").context("failed to get filename of miri executable")?;
+ let miri_bin = e
+ .build_get_binary(".", features)
+ .context("failed to get filename of miri executable")?;
cmd!(
e.sh,
"{cov_bin} report --instr-profile={merged_file} --object {miri_bin} --sources src/"
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index 6aab2f7..673d658 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -14,24 +14,40 @@ pub enum Command {
/// Sets up the rpath such that the installed binary should work in any
/// working directory.
Install {
+ /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+ /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+ #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+ features: Vec<String>,
/// Flags that are passed through to `cargo install`.
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
flags: Vec<String>,
},
/// Build Miri.
Build {
+ /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+ /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+ #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+ features: Vec<String>,
/// Flags that are passed through to `cargo build`.
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
flags: Vec<String>,
},
/// Check Miri.
Check {
+ /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+ /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+ #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+ features: Vec<String>,
/// Flags that are passed through to `cargo check`.
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
flags: Vec<String>,
},
/// Check Miri with Clippy.
Clippy {
+ /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+ /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+ #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+ features: Vec<String>,
/// Flags that are passed through to `cargo clippy`.
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
flags: Vec<String>,
@@ -47,6 +63,10 @@ pub enum Command {
/// Produce coverage report.
#[arg(long)]
coverage: bool,
+ /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+ /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+ #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+ features: Vec<String>,
/// Flags that are passed through to the test harness.
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
flags: Vec<String>,
@@ -67,6 +87,10 @@ pub enum Command {
/// The Rust edition.
#[arg(long)]
edition: Option<String>,
+ /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+ /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+ #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+ features: Vec<String>,
/// Flags that are passed through to `miri`.
///
/// The flags set in `MIRIFLAGS` are added in front of these flags.
@@ -75,6 +99,10 @@ pub enum Command {
},
/// Build documentation.
Doc {
+ /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+ /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+ #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+ features: Vec<String>,
/// Flags that are passed through to `cargo doc`.
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
flags: Vec<String>,
@@ -144,13 +172,13 @@ fn add_remainder(&mut self, remainder: Vec<String>) -> Result<()> {
}
match self {
- Self::Install { flags }
- | Self::Build { flags }
- | Self::Check { flags }
- | Self::Doc { flags }
+ Self::Install { flags, .. }
+ | Self::Build { flags, .. }
+ | Self::Check { flags, .. }
+ | Self::Doc { flags, .. }
| Self::Fmt { flags }
| Self::Toolchain { flags }
- | Self::Clippy { flags }
+ | Self::Clippy { flags, .. }
| Self::Run { flags, .. }
| Self::Test { flags, .. } => {
flags.extend(remainder);
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index 5c2a055..c100cf1 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -26,6 +26,12 @@ pub fn flagsplit(flags: &str) -> Vec<String> {
flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect()
}
+/// Turns a list of features into a list of arguments to pass to cargo invocations.
+/// Each feature will go in its own argument, e.g. "--features feat1 --features feat2".
+fn features_to_args(features: &[String]) -> impl IntoIterator<Item = &str> {
+ features.iter().flat_map(|feat| ["--features", feat])
+}
+
/// Some extra state we track for building Miri, such as the right RUSTFLAGS.
pub struct MiriEnv {
/// miri_dir is the root of the miri repository checkout we are working in.
@@ -116,44 +122,70 @@ pub fn new() -> Result<Self> {
Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags, libdir })
}
- pub fn cargo_cmd(&self, crate_dir: impl AsRef<OsStr>, cmd: &str) -> Cmd<'_> {
+ /// Make sure the `features` you pass here exist for the specified `crate_dir`. For example, the
+ /// "--features" parameter of [crate::Command]s is intended only for the "miri" root crate.
+ pub fn cargo_cmd(
+ &self,
+ crate_dir: impl AsRef<OsStr>,
+ cmd: &str,
+ features: &[String],
+ ) -> Cmd<'_> {
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
let manifest_path = path!(self.miri_dir / crate_dir.as_ref() / "Cargo.toml");
+ let features = features_to_args(features);
cmd!(
self.sh,
- "cargo +{toolchain} {cmd} {cargo_extra_flags...} --manifest-path {manifest_path}"
+ "cargo +{toolchain} {cmd} {cargo_extra_flags...} --manifest-path {manifest_path} {features...}"
)
}
+ /// Make sure the `features` you pass here exist for the specified `crate_dir`. For example, the
+ /// "--features" parameter of [crate::Command]s is intended only for the "miri" root crate.
pub fn install_to_sysroot(
&self,
- path: impl AsRef<OsStr>,
+ crate_dir: impl AsRef<OsStr>,
+ features: &[String],
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
) -> Result<()> {
let MiriEnv { sysroot, toolchain, cargo_extra_flags, .. } = self;
- let path = path!(self.miri_dir / path.as_ref());
+ let path = path!(self.miri_dir / crate_dir.as_ref());
+ let features = features_to_args(features);
// Install binaries to the miri toolchain's `sysroot` so they do not interact with other toolchains.
// (Not using `cargo_cmd` as `install` is special and doesn't use `--manifest-path`.)
- cmd!(self.sh, "cargo +{toolchain} install {cargo_extra_flags...} --path {path} --force --root {sysroot} {args...}").run()?;
+ cmd!(self.sh, "cargo +{toolchain} install {cargo_extra_flags...} --path {path} --force --root {sysroot} {features...} {args...}").run()?;
Ok(())
}
- pub fn build(&self, crate_dir: impl AsRef<OsStr>, args: &[String], quiet: bool) -> Result<()> {
+ pub fn build(
+ &self,
+ crate_dir: impl AsRef<OsStr>,
+ features: &[String],
+ args: &[String],
+ quiet: bool,
+ ) -> Result<()> {
let quiet_flag = if quiet { Some("--quiet") } else { None };
// We build all targets, since building *just* the bin target doesnot include
// `dev-dependencies` and that changes feature resolution. This also gets us more
// parallelism in `./miri test` as we build Miri and its tests together.
- let mut cmd =
- self.cargo_cmd(crate_dir, "build").args(&["--all-targets"]).args(quiet_flag).args(args);
+ let mut cmd = self
+ .cargo_cmd(crate_dir, "build", features)
+ .args(&["--all-targets"])
+ .args(quiet_flag)
+ .args(args);
cmd.set_quiet(quiet);
cmd.run()?;
Ok(())
}
/// Returns the path to the main crate binary. Assumes that `build` has been called before.
- pub fn build_get_binary(&self, crate_dir: impl AsRef<OsStr>) -> Result<PathBuf> {
- let cmd =
- self.cargo_cmd(crate_dir, "build").args(&["--all-targets", "--message-format=json"]);
+ pub fn build_get_binary(
+ &self,
+ crate_dir: impl AsRef<OsStr>,
+ features: &[String],
+ ) -> Result<PathBuf> {
+ let cmd = self
+ .cargo_cmd(crate_dir, "build", features)
+ .args(&["--all-targets", "--message-format=json"]);
let output = cmd.output()?;
let mut bin = None;
for line in output.stdout.lines() {
@@ -174,23 +206,43 @@ pub fn build_get_binary(&self, crate_dir: impl AsRef<OsStr>) -> Result<PathBuf>
bin.ok_or_else(|| anyhow!("found no binary in cargo output"))
}
- pub fn check(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
- self.cargo_cmd(crate_dir, "check").arg("--all-targets").args(args).run()?;
+ pub fn check(
+ &self,
+ crate_dir: impl AsRef<OsStr>,
+ features: &[String],
+ args: &[String],
+ ) -> Result<()> {
+ self.cargo_cmd(crate_dir, "check", features).arg("--all-targets").args(args).run()?;
Ok(())
}
- pub fn doc(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
- self.cargo_cmd(crate_dir, "doc").args(args).run()?;
+ pub fn doc(
+ &self,
+ crate_dir: impl AsRef<OsStr>,
+ features: &[String],
+ args: &[String],
+ ) -> Result<()> {
+ self.cargo_cmd(crate_dir, "doc", features).args(args).run()?;
Ok(())
}
- pub fn clippy(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
- self.cargo_cmd(crate_dir, "clippy").arg("--all-targets").args(args).run()?;
+ pub fn clippy(
+ &self,
+ crate_dir: impl AsRef<OsStr>,
+ features: &[String],
+ args: &[String],
+ ) -> Result<()> {
+ self.cargo_cmd(crate_dir, "clippy", features).arg("--all-targets").args(args).run()?;
Ok(())
}
- pub fn test(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
- self.cargo_cmd(crate_dir, "test").args(args).run()?;
+ pub fn test(
+ &self,
+ crate_dir: impl AsRef<OsStr>,
+ features: &[String],
+ args: &[String],
+ ) -> Result<()> {
+ self.cargo_cmd(crate_dir, "test", features).args(args).run()?;
Ok(())
}
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 90c6e31..b2ab17f 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-0cbc0764380630780a275c437260e4d4d5f28c92
+d41e12f1f4e4884c356f319b881921aa37040de5
diff --git a/src/tools/miri/src/alloc/isolated_alloc.rs b/src/tools/miri/src/alloc/isolated_alloc.rs
index 3a7879f..a7bb9b4 100644
--- a/src/tools/miri/src/alloc/isolated_alloc.rs
+++ b/src/tools/miri/src/alloc/isolated_alloc.rs
@@ -1,5 +1,7 @@
-use std::alloc::{self, Layout};
+use std::alloc::Layout;
+use std::ptr::NonNull;
+use nix::sys::mman;
use rustc_index::bit_set::DenseBitSet;
/// How many bytes of memory each bit in the bitset represents.
@@ -11,8 +13,8 @@
pub struct IsolatedAlloc {
/// Pointers to page-aligned memory that has been claimed by the allocator.
/// Every pointer here must point to a page-sized allocation claimed via
- /// the global allocator. These pointers are used for "small" allocations.
- page_ptrs: Vec<*mut u8>,
+ /// mmap. These pointers are used for "small" allocations.
+ page_ptrs: Vec<NonNull<u8>>,
/// Metadata about which bytes have been allocated on each page. The length
/// of this vector must be the same as that of `page_ptrs`, and the domain
/// size of the bitset must be exactly `page_size / COMPRESSION_FACTOR`.
@@ -24,7 +26,7 @@ pub struct IsolatedAlloc {
page_infos: Vec<DenseBitSet<usize>>,
/// Pointers to multiple-page-sized allocations. These must also be page-aligned,
/// with their size stored as the second element of the vector.
- huge_ptrs: Vec<(*mut u8, usize)>,
+ huge_ptrs: Vec<(NonNull<u8>, usize)>,
/// The host (not emulated) page size.
page_size: usize,
}
@@ -52,20 +54,26 @@ fn normalized_layout(layout: Layout) -> Layout {
Layout::from_size_align(size, align).unwrap()
}
- /// Returns the layout used to allocate the pages that hold small allocations.
+ /// For greater-than-page-sized allocations, returns the allocation size we need to request
+ /// including the slack we need to satisfy the alignment request.
#[inline]
- fn page_layout(&self) -> Layout {
- Layout::from_size_align(self.page_size, self.page_size).unwrap()
- }
-
- /// If the allocation is greater than a page, then round to the nearest page #.
- #[inline]
- fn huge_normalized_layout(layout: Layout, page_size: usize) -> Layout {
+ fn huge_normalized_layout(&self, layout: Layout) -> usize {
// Allocate in page-sized chunks
- let size = layout.size().next_multiple_of(page_size);
+ let size = layout.size().next_multiple_of(self.page_size);
// And make sure the align is at least one page
- let align = std::cmp::max(layout.align(), page_size);
- Layout::from_size_align(size, align).unwrap()
+ let align = std::cmp::max(layout.align(), self.page_size);
+ // pg_count gives us the # of pages needed to satisfy the size. For
+ // align > page_size where align = n * page_size, a sufficently-aligned
+ // address must exist somewhere in the range of
+ // some_page_aligned_address..some_page_aligned_address + (n-1) * page_size
+ // (since if some_page_aligned_address + n * page_size is sufficently aligned,
+ // then so is some_page_aligned_address itself per the definition of n, so we
+ // can avoid using that 1 extra page).
+ // Thus we allocate n-1 extra pages
+ let pg_count = size.div_ceil(self.page_size);
+ let extra_pages = align.strict_div(self.page_size).saturating_sub(1);
+
+ pg_count.strict_add(extra_pages).strict_mul(self.page_size)
}
/// Determined whether a given normalized (size, align) should be sent to
@@ -78,7 +86,7 @@ fn is_huge_alloc(&self, layout: &Layout) -> bool {
/// Allocates memory as described in `Layout`. This memory should be deallocated
/// by calling `dealloc` on this same allocator.
///
- /// SAFETY: See `alloc::alloc()`
+ /// SAFETY: See `alloc::alloc()`.
pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
// SAFETY: Upheld by caller
unsafe { self.allocate(layout, false) }
@@ -86,7 +94,7 @@ pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
/// Same as `alloc`, but zeroes out the memory.
///
- /// SAFETY: See `alloc::alloc_zeroed()`
+ /// SAFETY: See `alloc::alloc_zeroed()`.
pub unsafe fn alloc_zeroed(&mut self, layout: Layout) -> *mut u8 {
// SAFETY: Upheld by caller
unsafe { self.allocate(layout, true) }
@@ -95,14 +103,13 @@ pub unsafe fn alloc_zeroed(&mut self, layout: Layout) -> *mut u8 {
/// Abstracts over the logic of `alloc_zeroed` vs `alloc`, as determined by
/// the `zeroed` argument.
///
- /// SAFETY: See `alloc::alloc()`, with the added restriction that `page_size`
- /// corresponds to the host pagesize.
+ /// SAFETY: See `alloc::alloc()`.
unsafe fn allocate(&mut self, layout: Layout, zeroed: bool) -> *mut u8 {
let layout = IsolatedAlloc::normalized_layout(layout);
if self.is_huge_alloc(&layout) {
// SAFETY: Validity of `layout` upheld by caller; we checked that
// the size and alignment are appropriate for being a huge alloc
- unsafe { self.alloc_huge(layout, zeroed) }
+ unsafe { self.alloc_huge(layout) }
} else {
for (&mut page, pinfo) in std::iter::zip(&mut self.page_ptrs, &mut self.page_infos) {
// SAFETY: The value in `self.page_size` is used to allocate
@@ -132,7 +139,7 @@ unsafe fn allocate(&mut self, layout: Layout, zeroed: bool) -> *mut u8 {
unsafe fn alloc_small(
page_size: usize,
layout: Layout,
- page: *mut u8,
+ page: NonNull<u8>,
pinfo: &mut DenseBitSet<usize>,
zeroed: bool,
) -> Option<*mut u8> {
@@ -159,7 +166,7 @@ unsafe fn alloc_small(
// zero out, even if we allocated more
ptr.write_bytes(0, layout.size());
}
- return Some(ptr);
+ return Some(ptr.as_ptr());
}
}
}
@@ -167,26 +174,50 @@ unsafe fn alloc_small(
}
/// Expands the available memory pool by adding one page.
- fn add_page(&mut self) -> (*mut u8, &mut DenseBitSet<usize>) {
- // SAFETY: The system page size, which is the layout size, cannot be 0
- let page_ptr = unsafe { alloc::alloc(self.page_layout()) };
+ fn add_page(&mut self) -> (NonNull<u8>, &mut DenseBitSet<usize>) {
+ // SAFETY: mmap is always safe to call when requesting anonymous memory
+ let page_ptr = unsafe {
+ libc::mmap(
+ std::ptr::null_mut(),
+ self.page_size,
+ libc::PROT_READ | libc::PROT_WRITE,
+ libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+ -1,
+ 0,
+ )
+ .cast::<u8>()
+ };
+ assert_ne!(page_ptr.addr(), usize::MAX, "mmap failed");
// `page_infos` has to have one bit for each `COMPRESSION_FACTOR`-sized chunk of bytes in the page.
- assert!(self.page_size % COMPRESSION_FACTOR == 0);
+ assert!(self.page_size.is_multiple_of(COMPRESSION_FACTOR));
self.page_infos.push(DenseBitSet::new_empty(self.page_size / COMPRESSION_FACTOR));
- self.page_ptrs.push(page_ptr);
- (page_ptr, self.page_infos.last_mut().unwrap())
+ self.page_ptrs.push(NonNull::new(page_ptr).unwrap());
+ (NonNull::new(page_ptr).unwrap(), self.page_infos.last_mut().unwrap())
}
/// Allocates in multiples of one page on the host system.
+ /// Will always be zeroed.
///
/// SAFETY: Same as `alloc()`.
- unsafe fn alloc_huge(&mut self, layout: Layout, zeroed: bool) -> *mut u8 {
- let layout = IsolatedAlloc::huge_normalized_layout(layout, self.page_size);
- // SAFETY: Upheld by caller
- let ret =
- unsafe { if zeroed { alloc::alloc_zeroed(layout) } else { alloc::alloc(layout) } };
- self.huge_ptrs.push((ret, layout.size()));
- ret
+ unsafe fn alloc_huge(&mut self, layout: Layout) -> *mut u8 {
+ let size = self.huge_normalized_layout(layout);
+ // SAFETY: mmap is always safe to call when requesting anonymous memory
+ let ret = unsafe {
+ libc::mmap(
+ std::ptr::null_mut(),
+ size,
+ libc::PROT_READ | libc::PROT_WRITE,
+ libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+ -1,
+ 0,
+ )
+ .cast::<u8>()
+ };
+ assert_ne!(ret.addr(), usize::MAX, "mmap failed");
+ self.huge_ptrs.push((NonNull::new(ret).unwrap(), size));
+ // huge_normalized_layout ensures that we've overallocated enough space
+ // for this to be valid.
+ ret.map_addr(|a| a.next_multiple_of(layout.align()))
}
/// Deallocates a pointer from this allocator.
@@ -215,15 +246,15 @@ pub unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
let page_ptr = self.page_ptrs.remove(idx);
// SAFETY: We checked that there are no outstanding allocations
// from us pointing to this page, and we know it was allocated
- // with this layout
+ // in add_page as exactly a single page.
unsafe {
- alloc::dealloc(page_ptr, self.page_layout());
+ assert_eq!(libc::munmap(page_ptr.as_ptr().cast(), self.page_size), 0);
}
}
}
}
- /// Returns the index of the page that this was deallocated from
+ /// Returns the index of the page that this was deallocated from.
///
/// SAFETY: the pointer must have been allocated with `alloc_small`.
unsafe fn dealloc_small(&mut self, ptr: *mut u8, layout: Layout) -> usize {
@@ -236,7 +267,7 @@ unsafe fn dealloc_small(&mut self, ptr: *mut u8, layout: Layout) -> usize {
// This could be made faster if the list was sorted -- the allocator isn't fully optimized at the moment.
let pinfo = std::iter::zip(&mut self.page_ptrs, &mut self.page_infos)
.enumerate()
- .find(|(_, (page, _))| page.addr() == page_addr);
+ .find(|(_, (page, _))| page.addr().get() == page_addr);
let Some((idx_of_pinfo, (_, pinfo))) = pinfo else {
panic!("Freeing in an unallocated page: {ptr:?}\nHolding pages {:?}", self.page_ptrs)
};
@@ -252,20 +283,73 @@ unsafe fn dealloc_small(&mut self, ptr: *mut u8, layout: Layout) -> usize {
/// SAFETY: Same as `dealloc()` with the added requirement that `layout`
/// must ask for a size larger than the host pagesize.
unsafe fn dealloc_huge(&mut self, ptr: *mut u8, layout: Layout) {
- let layout = IsolatedAlloc::huge_normalized_layout(layout, self.page_size);
- // Find the pointer matching in address with the one we got
+ let size = self.huge_normalized_layout(layout);
+ // Find the huge allocation containing `ptr`.
let idx = self
.huge_ptrs
.iter()
- .position(|pg| ptr.addr() == pg.0.addr())
+ .position(|&(pg, size)| {
+ pg.addr().get() <= ptr.addr() && ptr.addr() < pg.addr().get().strict_add(size)
+ })
.expect("Freeing unallocated pages");
// And kick it from the list
- self.huge_ptrs.remove(idx);
- // SAFETY: Caller ensures validity of the layout
+ let (un_offset_ptr, size2) = self.huge_ptrs.remove(idx);
+ assert_eq!(size, size2, "got wrong layout in dealloc");
+ // SAFETY: huge_ptrs contains allocations made with mmap with the size recorded there.
unsafe {
- alloc::dealloc(ptr, layout);
+ let ret = libc::munmap(un_offset_ptr.as_ptr().cast(), size);
+ assert_eq!(ret, 0);
}
}
+
+ /// Returns a vector of page addresses managed by the allocator.
+ pub fn pages(&self) -> Vec<usize> {
+ let mut pages: Vec<usize> =
+ self.page_ptrs.iter().map(|p| p.expose_provenance().get()).collect();
+ for (ptr, size) in self.huge_ptrs.iter() {
+ for i in 0..size / self.page_size {
+ pages.push(ptr.expose_provenance().get().strict_add(i * self.page_size));
+ }
+ }
+ pages
+ }
+
+ /// Protects all owned memory as `PROT_NONE`, preventing accesses.
+ ///
+ /// SAFETY: Accessing memory after this point will result in a segfault
+ /// unless it is first unprotected.
+ pub unsafe fn prepare_ffi(&mut self) -> Result<(), nix::errno::Errno> {
+ let prot = mman::ProtFlags::PROT_NONE;
+ unsafe { self.mprotect(prot) }
+ }
+
+ /// Deprotects all owned memory by setting it to RW. Erroring here is very
+ /// likely unrecoverable, so it may panic if applying those permissions
+ /// fails.
+ pub fn unprep_ffi(&mut self) {
+ let prot = mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE;
+ unsafe {
+ self.mprotect(prot).unwrap();
+ }
+ }
+
+ /// Applies `prot` to every page managed by the allocator.
+ ///
+ /// SAFETY: Accessing memory in violation of the protection flags will
+ /// trigger a segfault.
+ unsafe fn mprotect(&mut self, prot: mman::ProtFlags) -> Result<(), nix::errno::Errno> {
+ for &pg in &self.page_ptrs {
+ unsafe {
+ mman::mprotect(pg.cast(), self.page_size, prot)?;
+ }
+ }
+ for &(hpg, size) in &self.huge_ptrs {
+ unsafe {
+ mman::mprotect(hpg.cast(), size.next_multiple_of(self.page_size), prot)?;
+ }
+ }
+ Ok(())
+ }
}
#[cfg(test)]
@@ -347,12 +431,15 @@ fn check_leaks_and_overlaps() {
sizes.append(&mut vec![256; 12]);
// Give it some multi-page ones too
sizes.append(&mut vec![32 * 1024; 4]);
+ sizes.push(4 * 1024);
// Matching aligns for the sizes
let mut aligns = vec![16; 12];
aligns.append(&mut vec![256; 2]);
aligns.append(&mut vec![64; 12]);
aligns.append(&mut vec![4096; 4]);
+ // And one that requests align > page_size
+ aligns.push(64 * 1024);
// Make sure we didn't mess up in the test itself!
assert_eq!(sizes.len(), aligns.len());
diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
index ab6aaed..b6cc017 100644
--- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs
+++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
@@ -129,7 +129,7 @@ pub fn take_addr(
let idx = rng.random_range(begin..end);
// Remove it from the pool and return.
let (chosen_addr, chosen_size, chosen_thread, clock) = subpool.remove(idx);
- debug_assert!(chosen_size >= size && chosen_addr % align.bytes() == 0);
+ debug_assert!(chosen_size >= size && chosen_addr.is_multiple_of(align.bytes()));
debug_assert!(cross_thread_reuse || chosen_thread == thread);
// No synchronization needed if we reused from the current thread.
Some((chosen_addr, if chosen_thread == thread { None } else { Some(clock) }))
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index d4ba7fb..92d2173 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -227,10 +227,11 @@ fn after_analysis<'tcx>(
} else {
let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None)
.unwrap_or_else(|| {
+ //#[cfg(target_os = "linux")]
+ //miri::native_lib::register_retcode_sv(rustc_driver::EXIT_FAILURE);
tcx.dcx().abort_if_errors();
rustc_driver::EXIT_FAILURE
});
-
std::process::exit(return_code);
}
@@ -295,6 +296,7 @@ fn config(&mut self, config: &mut Config) {
level: SymbolExportLevel::C,
kind: SymbolExportKind::Text,
used: false,
+ rustc_std_internal_symbol: false,
},
))
} else {
@@ -722,6 +724,8 @@ fn main() {
} else {
show_error!("-Zmiri-native-lib `{}` does not exist", filename);
}
+ } else if arg == "-Zmiri-native-lib-enable-tracing" {
+ miri_config.native_lib_enable_tracing = true;
} else if let Some(param) = arg.strip_prefix("-Zmiri-num-cpus=") {
let num_cpus = param
.parse::<u32>()
@@ -792,6 +796,16 @@ fn main() {
debug!("rustc arguments: {:?}", rustc_args);
debug!("crate arguments: {:?}", miri_config.args);
+ #[cfg(target_os = "linux")]
+ if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing {
+ // FIXME: This should display a diagnostic / warning on error
+ // SAFETY: If any other threads exist at this point (namely for the ctrlc
+ // handler), they will not interact with anything on the main rustc/Miri
+ // thread in an async-signal-unsafe way such as by accessing shared
+ // semaphores, etc.; the handler only calls `sleep()` and `exit()`, which
+ // are async-signal-safe, as is accessing atomics
+ //let _ = unsafe { miri::native_lib::init_sv() };
+ }
run_compiler_and_exit(
&rustc_args,
&mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config),
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index bc57ba6..b8bcacf 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -814,7 +814,7 @@ fn sb_retag_place(
info: RetagInfo, // diagnostics info about this retag
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
let this = self.eval_context_mut();
- let size = this.size_and_align_of_mplace(place)?.map(|(size, _)| size);
+ let size = this.size_and_align_of_val(place)?.map(|(size, _)| size);
// FIXME: If we cannot determine the size (because the unsized tail is an `extern type`),
// bail out -- we cannot reasonably figure out which memory range to reborrow.
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/276.
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index ce8fe03..a0761cb 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -468,10 +468,8 @@ fn tb_retag_place(
// - when `extern type` is involved we use the size of the known prefix,
// - if the pointer is not reborrowed (raw pointer) then we override the size
// to do a zero-length reborrow.
- let reborrow_size = this
- .size_and_align_of_mplace(place)?
- .map(|(size, _)| size)
- .unwrap_or(place.layout.size);
+ let reborrow_size =
+ this.size_and_align_of_val(place)?.map(|(size, _)| size).unwrap_or(place.layout.size);
trace!("Creating new permission: {:?} with size {:?}", new_perm, reborrow_size);
// This new tag is not guaranteed to actually be used.
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
index dcd5a6c..ad0a565 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -327,7 +327,7 @@ fn consistency_large() {
for i in 0..1000 {
i.hash(&mut hasher);
let rng = hasher.finish();
- let op = rng % 3 == 0;
+ let op = rng.is_multiple_of(3);
let key = (rng / 2) % 50;
let val = (rng / 100) % 1000;
if op {
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 38b5d4c..c8a408f 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -582,88 +582,6 @@ fn detach_thread(&mut self, id: ThreadId, allow_terminated_joined: bool) -> Inte
interp_ok(())
}
- /// Mark that the active thread tries to join the thread with `joined_thread_id`.
- fn join_thread(
- &mut self,
- joined_thread_id: ThreadId,
- data_race_handler: &mut GlobalDataRaceHandler,
- ) -> InterpResult<'tcx> {
- if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached {
- // On Windows this corresponds to joining on a closed handle.
- throw_ub_format!("trying to join a detached thread");
- }
-
- fn after_join<'tcx>(
- threads: &mut ThreadManager<'_>,
- joined_thread_id: ThreadId,
- data_race_handler: &mut GlobalDataRaceHandler,
- ) -> InterpResult<'tcx> {
- match data_race_handler {
- GlobalDataRaceHandler::None => {}
- GlobalDataRaceHandler::Vclocks(data_race) =>
- data_race.thread_joined(threads, joined_thread_id),
- GlobalDataRaceHandler::Genmc(genmc_ctx) =>
- genmc_ctx.handle_thread_join(threads.active_thread, joined_thread_id)?,
- }
- interp_ok(())
- }
-
- // Mark the joined thread as being joined so that we detect if other
- // threads try to join it.
- self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined;
- if !self.threads[joined_thread_id].state.is_terminated() {
- trace!(
- "{:?} blocked on {:?} when trying to join",
- self.active_thread, joined_thread_id
- );
- // The joined thread is still running, we need to wait for it.
- // Unce we get unblocked, perform the appropriate synchronization.
- self.block_thread(
- BlockReason::Join(joined_thread_id),
- None,
- callback!(
- @capture<'tcx> {
- joined_thread_id: ThreadId,
- }
- |this, unblock: UnblockKind| {
- assert_eq!(unblock, UnblockKind::Ready);
- after_join(&mut this.machine.threads, joined_thread_id, &mut this.machine.data_race)
- }
- ),
- );
- } else {
- // The thread has already terminated - establish happens-before
- after_join(self, joined_thread_id, data_race_handler)?;
- }
- interp_ok(())
- }
-
- /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`.
- /// If the thread is already joined by another thread, it will throw UB
- fn join_thread_exclusive(
- &mut self,
- joined_thread_id: ThreadId,
- data_race_handler: &mut GlobalDataRaceHandler,
- ) -> InterpResult<'tcx> {
- if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Joined {
- throw_ub_format!("trying to join an already joined thread");
- }
-
- if joined_thread_id == self.active_thread {
- throw_ub_format!("trying to join itself");
- }
-
- // Sanity check `join_status`.
- assert!(
- self.threads
- .iter()
- .all(|thread| { !thread.state.is_blocked_on(BlockReason::Join(joined_thread_id)) }),
- "this thread already has threads waiting for its termination"
- );
-
- self.join_thread(joined_thread_id, data_race_handler)
- }
-
/// Set the name of the given thread.
pub fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec<u8>) {
self.threads[thread].thread_name = Some(new_thread_name);
@@ -1114,20 +1032,102 @@ fn detach_thread(
this.machine.threads.detach_thread(thread_id, allow_terminated_joined)
}
- #[inline]
- fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
+ /// Mark that the active thread tries to join the thread with `joined_thread_id`.
+ ///
+ /// When the join is successful (immediately, or as soon as the joined thread finishes), `success_retval` will be written to `return_dest`.
+ fn join_thread(
+ &mut self,
+ joined_thread_id: ThreadId,
+ success_retval: Scalar,
+ return_dest: &MPlaceTy<'tcx>,
+ ) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
- this.machine.threads.join_thread(joined_thread_id, &mut this.machine.data_race)?;
+ let thread_mgr = &mut this.machine.threads;
+ if thread_mgr.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached {
+ // On Windows this corresponds to joining on a closed handle.
+ throw_ub_format!("trying to join a detached thread");
+ }
+
+ fn after_join<'tcx>(
+ this: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
+ joined_thread_id: ThreadId,
+ success_retval: Scalar,
+ return_dest: &MPlaceTy<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let threads = &this.machine.threads;
+ match &mut this.machine.data_race {
+ GlobalDataRaceHandler::None => {}
+ GlobalDataRaceHandler::Vclocks(data_race) =>
+ data_race.thread_joined(threads, joined_thread_id),
+ GlobalDataRaceHandler::Genmc(genmc_ctx) =>
+ genmc_ctx.handle_thread_join(threads.active_thread, joined_thread_id)?,
+ }
+ this.write_scalar(success_retval, return_dest)?;
+ interp_ok(())
+ }
+
+ // Mark the joined thread as being joined so that we detect if other
+ // threads try to join it.
+ thread_mgr.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined;
+ if !thread_mgr.threads[joined_thread_id].state.is_terminated() {
+ trace!(
+ "{:?} blocked on {:?} when trying to join",
+ thread_mgr.active_thread, joined_thread_id
+ );
+ // The joined thread is still running, we need to wait for it.
+ // Once we get unblocked, perform the appropriate synchronization and write the return value.
+ let dest = return_dest.clone();
+ thread_mgr.block_thread(
+ BlockReason::Join(joined_thread_id),
+ None,
+ callback!(
+ @capture<'tcx> {
+ joined_thread_id: ThreadId,
+ dest: MPlaceTy<'tcx>,
+ success_retval: Scalar,
+ }
+ |this, unblock: UnblockKind| {
+ assert_eq!(unblock, UnblockKind::Ready);
+ after_join(this, joined_thread_id, success_retval, &dest)
+ }
+ ),
+ );
+ } else {
+ // The thread has already terminated - establish happens-before and write the return value.
+ after_join(this, joined_thread_id, success_retval, return_dest)?;
+ }
interp_ok(())
}
- #[inline]
- fn join_thread_exclusive(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
+ /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`.
+ /// If the thread is already joined by another thread, it will throw UB.
+ ///
+ /// When the join is successful (immediately, or as soon as the joined thread finishes), `success_retval` will be written to `return_dest`.
+ fn join_thread_exclusive(
+ &mut self,
+ joined_thread_id: ThreadId,
+ success_retval: Scalar,
+ return_dest: &MPlaceTy<'tcx>,
+ ) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
- this.machine
- .threads
- .join_thread_exclusive(joined_thread_id, &mut this.machine.data_race)?;
- interp_ok(())
+ let threads = &this.machine.threads.threads;
+ if threads[joined_thread_id].join_status == ThreadJoinStatus::Joined {
+ throw_ub_format!("trying to join an already joined thread");
+ }
+
+ if joined_thread_id == this.machine.threads.active_thread {
+ throw_ub_format!("trying to join itself");
+ }
+
+ // Sanity check `join_status`.
+ assert!(
+ threads
+ .iter()
+ .all(|thread| { !thread.state.is_blocked_on(BlockReason::Join(joined_thread_id)) }),
+ "this thread already has threads waiting for its termination"
+ );
+
+ this.join_thread(joined_thread_id, success_retval, return_dest)
}
#[inline]
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 54a7c14..9ecbd31 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -132,7 +132,9 @@ pub enum NonHaltingDiagnostic {
Int2Ptr {
details: bool,
},
- NativeCallSharedMem,
+ NativeCallSharedMem {
+ tracing: bool,
+ },
WeakMemoryOutdatedLoad {
ptr: Pointer,
},
@@ -627,7 +629,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
RejectedIsolatedOp(_) =>
("operation rejected by isolation".to_string(), DiagLevel::Warning),
Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning),
- NativeCallSharedMem =>
+ NativeCallSharedMem { .. } =>
("sharing memory with a native function".to_string(), DiagLevel::Warning),
ExternTypeReborrow =>
("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning),
@@ -663,7 +665,8 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
ProgressReport { .. } =>
format!("progress report: current operation being executed is here"),
Int2Ptr { .. } => format!("integer-to-pointer cast"),
- NativeCallSharedMem => format!("sharing memory with a native function called via FFI"),
+ NativeCallSharedMem { .. } =>
+ format!("sharing memory with a native function called via FFI"),
WeakMemoryOutdatedLoad { ptr } =>
format!("weak memory emulation: outdated value returned from load at {ptr}"),
ExternTypeReborrow =>
@@ -709,22 +712,41 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
}
v
}
- NativeCallSharedMem => {
- vec![
- note!(
- "when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory"
- ),
- note!(
- "in particular, Miri assumes that the native call initializes all memory it has access to"
- ),
- note!(
- "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory"
- ),
- note!(
- "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free"
- ),
- ]
- }
+ NativeCallSharedMem { tracing } =>
+ if *tracing {
+ vec![
+ note!(
+ "when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis"
+ ),
+ note!(
+ "in particular, Miri assumes that the native call initializes all memory it has written to"
+ ),
+ note!(
+ "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory"
+ ),
+ note!(
+ "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free"
+ ),
+ note!(
+ "tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here"
+ ),
+ ]
+ } else {
+ vec![
+ note!(
+ "when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory"
+ ),
+ note!(
+ "in particular, Miri assumes that the native call initializes all memory it has access to"
+ ),
+ note!(
+ "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory"
+ ),
+ note!(
+ "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free"
+ ),
+ ]
+ },
ExternTypeReborrow => {
assert!(self.borrow_tracker.as_ref().is_some_and(|b| {
matches!(
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 7a5f96e..44612da 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -11,7 +11,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::{LayoutCx, LayoutOf};
+use rustc_middle::ty::layout::LayoutCx;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::EntryFnType;
@@ -150,6 +150,8 @@ pub struct MiriConfig {
pub retag_fields: RetagFields,
/// The location of the shared object files to load when calling external functions
pub native_lib: Vec<PathBuf>,
+ /// Whether to enable the new native lib tracing system.
+ pub native_lib_enable_tracing: bool,
/// Run a garbage collector for BorTags every N basic blocks.
pub gc_interval: u32,
/// The number of CPUs to be reported by miri.
@@ -199,6 +201,7 @@ fn default() -> MiriConfig {
report_progress: None,
retag_fields: RetagFields::Yes,
native_lib: vec![],
+ native_lib_enable_tracing: false,
gc_interval: 10_000,
num_cpus: 1,
page_size: None,
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 4edecc8..fb34600 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -489,7 +489,7 @@ fn visit_freeze_sensitive(
trace!("visit_frozen(place={:?}, size={:?})", *place, size);
debug_assert_eq!(
size,
- this.size_and_align_of_mplace(place)?
+ this.size_and_align_of_val(place)?
.map(|(size, _)| size)
.unwrap_or_else(|| place.layout.size)
);
@@ -530,7 +530,7 @@ fn visit_freeze_sensitive(
trace!("unsafe_cell_action on {:?}", place.ptr());
// We need a size to go on.
let unsafe_cell_size = this
- .size_and_align_of_mplace(place)?
+ .size_and_align_of_val(place)?
.map(|(size, _)| size)
// for extern types, just cover what we can
.unwrap_or_else(|| place.layout.size);
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index ec77a16..ed1851a 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -191,7 +191,7 @@ fn emulate_intrinsic_by_name(
let [f] = check_intrinsic_arg_count(args)?;
let f = this.read_scalar(f)?.to_f32()?;
- let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{
+ let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
// Using host floats (but it's fine, these operations do not have
// guaranteed precision).
let host = f.to_host();
@@ -235,7 +235,7 @@ fn emulate_intrinsic_by_name(
let [f] = check_intrinsic_arg_count(args)?;
let f = this.read_scalar(f)?.to_f64()?;
- let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{
+ let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
// Using host floats (but it's fine, these operations do not have
// guaranteed precision).
let host = f.to_host();
@@ -312,7 +312,7 @@ fn emulate_intrinsic_by_name(
let f1 = this.read_scalar(f1)?.to_f32()?;
let f2 = this.read_scalar(f2)?.to_f32()?;
- let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+ let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f1.to_host().powf(f2.to_host()).to_soft();
@@ -330,7 +330,7 @@ fn emulate_intrinsic_by_name(
let f1 = this.read_scalar(f1)?.to_f64()?;
let f2 = this.read_scalar(f2)?.to_f64()?;
- let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+ let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f1.to_host().powf(f2.to_host()).to_soft();
@@ -349,7 +349,7 @@ fn emulate_intrinsic_by_name(
let f = this.read_scalar(f)?.to_f32()?;
let i = this.read_scalar(i)?.to_i32()?;
- let res = fixed_powi_float_value(f, i).unwrap_or_else(|| {
+ let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f.to_host().powi(i).to_soft();
@@ -367,7 +367,7 @@ fn emulate_intrinsic_by_name(
let f = this.read_scalar(f)?.to_f64()?;
let i = this.read_scalar(i)?.to_i32()?;
- let res = fixed_powi_float_value(f, i).unwrap_or_else(|| {
+ let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f.to_host().powi(i).to_soft();
@@ -496,52 +496,88 @@ fn apply_random_float_error_to_imm<'tcx>(
/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
/// - powf32, powf64
///
+/// # Return
+///
/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
/// (specifically, C23 annex F.10) when given `args` as arguments. Outputs that are unaffected by a relative error
/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
/// implementation. Returns `None` if no specific value is guaranteed.
+///
+/// # Note
+///
+/// For `powf*` operations of the form:
+///
+/// - `(SNaN)^(±0)`
+/// - `1^(SNaN)`
+///
+/// The result is implementation-defined:
+/// - musl returns for both `1.0`
+/// - glibc returns for both `NaN`
+///
+/// This discrepancy exists because SNaN handling is not consistently defined across platforms,
+/// and the C standard leaves behavior for SNaNs unspecified.
+///
+/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
fn fixed_float_value<S: Semantics>(
+ ecx: &mut MiriInterpCx<'_>,
intrinsic_name: &str,
args: &[IeeeFloat<S>],
) -> Option<IeeeFloat<S>> {
let one = IeeeFloat::<S>::one();
- match (intrinsic_name, args) {
+ Some(match (intrinsic_name, args) {
// cos(+- 0) = 1
- ("cosf32" | "cosf64", [input]) if input.is_zero() => Some(one),
+ ("cosf32" | "cosf64", [input]) if input.is_zero() => one,
// e^0 = 1
- ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => Some(one),
-
- // 1^y = 1 for any y, even a NaN.
- ("powf32" | "powf64", [base, _]) if *base == one => Some(one),
+ ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
// (-1)^(±INF) = 1
- ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => Some(one),
+ ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
- // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
- // the NaN. We should return either 1 or the NaN non-deterministically here.
- // But for now, just handle them all the same.
+ // 1^y = 1 for any y, even a NaN
+ ("powf32" | "powf64", [base, exp]) if *base == one => {
+ let rng = ecx.machine.rng.get_mut();
+ // SNaN exponents get special treatment: they might return 1, or a NaN.
+ let return_nan = exp.is_signaling() && ecx.machine.float_nondet && rng.random();
+ // Handle both the musl and glibc cases non-deterministically.
+ if return_nan { ecx.generate_nan(args) } else { one }
+ }
+
// x^(±0) = 1 for any x, even a NaN
- ("powf32" | "powf64", [_, exp]) if exp.is_zero() => Some(one),
+ ("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
+ let rng = ecx.machine.rng.get_mut();
+ // SNaN bases get special treatment: they might return 1, or a NaN.
+ let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random();
+ // Handle both the musl and glibc cases non-deterministically.
+ if return_nan { ecx.generate_nan(args) } else { one }
+ }
- // There are a lot of cases for fixed outputs according to the C Standard, but these are mainly INF or zero
- // which are not affected by the applied error.
- _ => None,
- }
+ // There are a lot of cases for fixed outputs according to the C Standard, but these are
+ // mainly INF or zero which are not affected by the applied error.
+ _ => return None,
+ })
}
-/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
-/// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
-fn fixed_powi_float_value<S: Semantics>(base: IeeeFloat<S>, exp: i32) -> Option<IeeeFloat<S>> {
- match (base.category(), exp) {
- // x^0 = 1, if x is not a Signaling NaN
- // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
- // the NaN. We should return either 1 or the NaN non-deterministically here.
- // But for now, just handle them all the same.
- (_, 0) => Some(IeeeFloat::<S>::one()),
+/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
+/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
+fn fixed_powi_float_value<S: Semantics>(
+ ecx: &mut MiriInterpCx<'_>,
+ base: IeeeFloat<S>,
+ exp: i32,
+) -> Option<IeeeFloat<S>> {
+ Some(match exp {
+ 0 => {
+ let one = IeeeFloat::<S>::one();
+ let rng = ecx.machine.rng.get_mut();
+ let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
+ // For SNaN treatment, we are consistent with `powf`above.
+ // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
+ // but for now we are maximally conservative.)
+ if return_nan { ecx.generate_nan(&[base]) } else { one }
+ }
- _ => None,
- }
+ _ => return None,
+ })
}
/// Given an floating-point operation and a floating-point value, clamps the result to the output
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index dbe193b..e63992a 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -3,7 +3,6 @@
use rustc_abi::{Endian, HasDataLayout};
use rustc_apfloat::{Float, Round};
use rustc_middle::ty::FloatTy;
-use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::{mir, ty};
use rustc_span::{Symbol, sym};
@@ -37,6 +36,7 @@ fn emulate_simd_intrinsic(
| "ceil"
| "floor"
| "round"
+ | "round_ties_even"
| "trunc"
| "fsqrt"
| "fsin"
@@ -72,6 +72,7 @@ enum Op<'a> {
"ceil" => Op::Round(rustc_apfloat::Round::TowardPositive),
"floor" => Op::Round(rustc_apfloat::Round::TowardNegative),
"round" => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
+ "round_ties_even" => Op::Round(rustc_apfloat::Round::NearestTiesToEven),
"trunc" => Op::Round(rustc_apfloat::Round::TowardZero),
"ctlz" => Op::Numeric(sym::ctlz),
"ctpop" => Op::Numeric(sym::ctpop),
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index e96c81d..00f26a3 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -10,6 +10,7 @@
#![feature(variant_count)]
#![feature(yeet_expr)]
#![feature(nonzero_ops)]
+#![cfg_attr(bootstrap, feature(nonnull_provenance))]
#![feature(strict_overflow_ops)]
#![feature(pointer_is_aligned_to)]
#![feature(ptr_metadata)]
@@ -99,6 +100,11 @@
use rustc_middle::{bug, span_bug};
use tracing::{info, trace};
+//#[cfg(target_os = "linux")]
+//pub mod native_lib {
+// pub use crate::shims::{init_sv, register_retcode_sv};
+//}
+
// Type aliases that set the provenance parameter.
pub type Pointer = interpret::Pointer<Option<machine::Provenance>>;
pub type StrictPointer = interpret::Pointer<machine::Provenance>;
@@ -168,7 +174,7 @@
"-Zmir-emit-retag",
"-Zmir-preserve-ub",
"-Zmir-opt-level=0",
- "-Zmir-enable-passes=-CheckAlignment,-CheckNull",
+ "-Zmir-enable-passes=-CheckAlignment,-CheckNull,-CheckEnums",
// Deduplicating diagnostics means we miss events when tracking what happens during an
// execution. Let's not do that.
"-Zdeduplicate-diagnostics=no",
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index b4d7db3..3a748c4 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1056,7 +1056,7 @@ fn alignment_check(
// What's the offset between us and the promised alignment?
let distance = offset.bytes().wrapping_sub(promised_offset.bytes());
// That must also be aligned.
- if distance % align.bytes() == 0 {
+ if distance.is_multiple_of(align.bytes()) {
// All looking good!
None
} else {
@@ -1612,7 +1612,7 @@ fn before_terminator(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
ecx.machine.since_gc += 1;
// Possibly report our progress. This will point at the terminator we are about to execute.
if let Some(report_progress) = ecx.machine.report_progress {
- if ecx.machine.basic_block_count % u64::from(report_progress) == 0 {
+ if ecx.machine.basic_block_count.is_multiple_of(u64::from(report_progress)) {
ecx.emit_diagnostic(NonHaltingDiagnostic::ProgressReport {
block_count: ecx.machine.basic_block_count,
});
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index feb83ca..dd00b27 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,5 +1,4 @@
use rustc_abi::{CanonAbi, FieldIdx, Size};
-use rustc_middle::ty::layout::LayoutOf as _;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_span::{BytePos, Loc, Symbol, hygiene};
use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index b498551..f09fc54 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -21,6 +21,8 @@
pub mod tls;
pub use self::files::FdTable;
+//#[cfg(target_os = "linux")]
+//pub use self::native_lib::trace::{init_sv, register_retcode_sv};
pub use self::unix::{DirTable, EpollInterestTable};
/// What needs to be done after emulating an item (a shim or an intrinsic) is done.
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib/mod.rs
similarity index 66%
rename from src/tools/miri/src/shims/native_lib.rs
rename to src/tools/miri/src/shims/native_lib/mod.rs
index 030c2e3..9c659f6 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib/mod.rs
@@ -1,4 +1,9 @@
//! Implements calling functions from a native library.
+
+// FIXME: disabled since it fails to build on many targets.
+//#[cfg(target_os = "linux")]
+//pub mod trace;
+
use std::ops::Deref;
use libffi::high::call as ffi;
@@ -8,8 +13,15 @@
use rustc_middle::ty::{self as ty, IntTy, UintTy};
use rustc_span::Symbol;
+//#[cfg(target_os = "linux")]
+//use self::trace::Supervisor;
use crate::*;
+//#[cfg(target_os = "linux")]
+//type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option<self::trace::messages::MemEvents>)>;
+//#[cfg(not(target_os = "linux"))]
+type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option<!>)>;
+
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
/// Call native host function and return the output as an immediate.
@@ -19,71 +31,93 @@ fn call_native_with_args<'a>(
dest: &MPlaceTy<'tcx>,
ptr: CodePtr,
libffi_args: Vec<libffi::high::Arg<'a>>,
- ) -> InterpResult<'tcx, ImmTy<'tcx>> {
+ ) -> CallResult<'tcx> {
let this = self.eval_context_mut();
+ //#[cfg(target_os = "linux")]
+ //let alloc = this.machine.allocator.as_ref().unwrap();
+
+ // SAFETY: We don't touch the machine memory past this point.
+ //#[cfg(target_os = "linux")]
+ //let (guard, stack_ptr) = unsafe { Supervisor::start_ffi(alloc) };
// Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
// as the specified primitive integer type
- let scalar = match dest.layout.ty.kind() {
- // ints
- ty::Int(IntTy::I8) => {
- // Unsafe because of the call to native code.
- // Because this is calling a C function it is not necessarily sound,
- // but there is no way around this and we've checked as much as we can.
- let x = unsafe { ffi::call::<i8>(ptr, libffi_args.as_slice()) };
- Scalar::from_i8(x)
- }
- ty::Int(IntTy::I16) => {
- let x = unsafe { ffi::call::<i16>(ptr, libffi_args.as_slice()) };
- Scalar::from_i16(x)
- }
- ty::Int(IntTy::I32) => {
- let x = unsafe { ffi::call::<i32>(ptr, libffi_args.as_slice()) };
- Scalar::from_i32(x)
- }
- ty::Int(IntTy::I64) => {
- let x = unsafe { ffi::call::<i64>(ptr, libffi_args.as_slice()) };
- Scalar::from_i64(x)
- }
- ty::Int(IntTy::Isize) => {
- let x = unsafe { ffi::call::<isize>(ptr, libffi_args.as_slice()) };
- Scalar::from_target_isize(x.try_into().unwrap(), this)
- }
- // uints
- ty::Uint(UintTy::U8) => {
- let x = unsafe { ffi::call::<u8>(ptr, libffi_args.as_slice()) };
- Scalar::from_u8(x)
- }
- ty::Uint(UintTy::U16) => {
- let x = unsafe { ffi::call::<u16>(ptr, libffi_args.as_slice()) };
- Scalar::from_u16(x)
- }
- ty::Uint(UintTy::U32) => {
- let x = unsafe { ffi::call::<u32>(ptr, libffi_args.as_slice()) };
- Scalar::from_u32(x)
- }
- ty::Uint(UintTy::U64) => {
- let x = unsafe { ffi::call::<u64>(ptr, libffi_args.as_slice()) };
- Scalar::from_u64(x)
- }
- ty::Uint(UintTy::Usize) => {
- let x = unsafe { ffi::call::<usize>(ptr, libffi_args.as_slice()) };
- Scalar::from_target_usize(x.try_into().unwrap(), this)
- }
- // Functions with no declared return type (i.e., the default return)
- // have the output_type `Tuple([])`.
- ty::Tuple(t_list) if (*t_list).deref().is_empty() => {
- unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
- return interp_ok(ImmTy::uninit(dest.layout));
- }
- ty::RawPtr(..) => {
- let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) };
- let ptr = Pointer::new(Provenance::Wildcard, Size::from_bytes(x.addr()));
- Scalar::from_pointer(ptr, this)
- }
- _ => throw_unsup_format!("unsupported return type for native call: {:?}", link_name),
+ let res = 'res: {
+ let scalar = match dest.layout.ty.kind() {
+ // ints
+ ty::Int(IntTy::I8) => {
+ // Unsafe because of the call to native code.
+ // Because this is calling a C function it is not necessarily sound,
+ // but there is no way around this and we've checked as much as we can.
+ let x = unsafe { ffi::call::<i8>(ptr, libffi_args.as_slice()) };
+ Scalar::from_i8(x)
+ }
+ ty::Int(IntTy::I16) => {
+ let x = unsafe { ffi::call::<i16>(ptr, libffi_args.as_slice()) };
+ Scalar::from_i16(x)
+ }
+ ty::Int(IntTy::I32) => {
+ let x = unsafe { ffi::call::<i32>(ptr, libffi_args.as_slice()) };
+ Scalar::from_i32(x)
+ }
+ ty::Int(IntTy::I64) => {
+ let x = unsafe { ffi::call::<i64>(ptr, libffi_args.as_slice()) };
+ Scalar::from_i64(x)
+ }
+ ty::Int(IntTy::Isize) => {
+ let x = unsafe { ffi::call::<isize>(ptr, libffi_args.as_slice()) };
+ Scalar::from_target_isize(x.try_into().unwrap(), this)
+ }
+ // uints
+ ty::Uint(UintTy::U8) => {
+ let x = unsafe { ffi::call::<u8>(ptr, libffi_args.as_slice()) };
+ Scalar::from_u8(x)
+ }
+ ty::Uint(UintTy::U16) => {
+ let x = unsafe { ffi::call::<u16>(ptr, libffi_args.as_slice()) };
+ Scalar::from_u16(x)
+ }
+ ty::Uint(UintTy::U32) => {
+ let x = unsafe { ffi::call::<u32>(ptr, libffi_args.as_slice()) };
+ Scalar::from_u32(x)
+ }
+ ty::Uint(UintTy::U64) => {
+ let x = unsafe { ffi::call::<u64>(ptr, libffi_args.as_slice()) };
+ Scalar::from_u64(x)
+ }
+ ty::Uint(UintTy::Usize) => {
+ let x = unsafe { ffi::call::<usize>(ptr, libffi_args.as_slice()) };
+ Scalar::from_target_usize(x.try_into().unwrap(), this)
+ }
+ // Functions with no declared return type (i.e., the default return)
+ // have the output_type `Tuple([])`.
+ ty::Tuple(t_list) if (*t_list).deref().is_empty() => {
+ unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
+ break 'res interp_ok(ImmTy::uninit(dest.layout));
+ }
+ ty::RawPtr(..) => {
+ let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) };
+ let ptr = Pointer::new(Provenance::Wildcard, Size::from_bytes(x.addr()));
+ Scalar::from_pointer(ptr, this)
+ }
+ _ =>
+ break 'res Err(err_unsup_format!(
+ "unsupported return type for native call: {:?}",
+ link_name
+ ))
+ .into(),
+ };
+ interp_ok(ImmTy::from_scalar(scalar, dest.layout))
};
- interp_ok(ImmTy::from_scalar(scalar, dest.layout))
+
+ // SAFETY: We got the guard and stack pointer from start_ffi, and
+ // the allocator is the same
+ //#[cfg(target_os = "linux")]
+ //let events = unsafe { Supervisor::end_ffi(alloc, guard, stack_ptr) };
+ //#[cfg(not(target_os = "linux"))]
+ let events = None;
+
+ interp_ok((res?, events))
}
/// Get the pointer to the function of the specified name in the shared object file,
@@ -179,7 +213,12 @@ fn call_native_fn(
// The first time this happens, print a warning.
if !this.machine.native_call_mem_warned.replace(true) {
// Newly set, so first time we get here.
- this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem);
+ this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem {
+ //#[cfg(target_os = "linux")]
+ //tracing: self::trace::Supervisor::is_enabled(),
+ //#[cfg(not(target_os = "linux"))]
+ tracing: false,
+ });
}
this.expose_provenance(prov)?;
@@ -196,7 +235,15 @@ fn call_native_fn(
.collect::<Vec<libffi::high::Arg<'_>>>();
// Call the function and store output, depending on return type in the function signature.
- let ret = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
+ let (ret, maybe_memevents) =
+ this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
+
+ if cfg!(target_os = "linux")
+ && let Some(events) = maybe_memevents
+ {
+ trace!("Registered FFI events:\n{events:#0x?}");
+ }
+
this.write_immediate(*ret, dest)?;
interp_ok(true)
}
diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs
new file mode 100644
index 0000000..4961e87
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/child.rs
@@ -0,0 +1,251 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use ipc_channel::ipc;
+use nix::sys::{ptrace, signal};
+use nix::unistd;
+
+use super::CALLBACK_STACK_SIZE;
+use super::messages::{Confirmation, MemEvents, StartFfiInfo, TraceRequest};
+use super::parent::{ChildListener, sv_loop};
+use crate::alloc::isolated_alloc::IsolatedAlloc;
+
+static SUPERVISOR: std::sync::Mutex<Option<Supervisor>> = std::sync::Mutex::new(None);
+
+/// The main means of communication between the child and parent process,
+/// allowing the former to send requests and get info from the latter.
+pub struct Supervisor {
+ /// Sender for FFI-mode-related requests.
+ message_tx: ipc::IpcSender<TraceRequest>,
+ /// Used for synchronisation, allowing us to receive confirmation that the
+ /// parent process has handled the request from `message_tx`.
+ confirm_rx: ipc::IpcReceiver<Confirmation>,
+ /// Receiver for memory acceses that ocurred during the FFI call.
+ event_rx: ipc::IpcReceiver<MemEvents>,
+}
+
+/// Marker representing that an error occurred during creation of the supervisor.
+#[derive(Debug)]
+pub struct SvInitError;
+
+impl Supervisor {
+ /// Returns `true` if the supervisor process exists, and `false` otherwise.
+ pub fn is_enabled() -> bool {
+ SUPERVISOR.lock().unwrap().is_some()
+ }
+
+ /// Begins preparations for doing an FFI call. This should be called at
+ /// the last possible moment before entering said call. `alloc` points to
+ /// the allocator which handed out the memory used for this machine.
+ ///
+ /// As this locks the supervisor via a mutex, no other threads may enter FFI
+ /// until this one returns and its guard is dropped via `end_ffi`. The
+ /// pointer returned should be passed to `end_ffi` to avoid a memory leak.
+ ///
+ /// SAFETY: The resulting guard must be dropped *via `end_ffi`* immediately
+ /// after the desired call has concluded.
+ pub unsafe fn start_ffi(
+ alloc: &Rc<RefCell<IsolatedAlloc>>,
+ ) -> (std::sync::MutexGuard<'static, Option<Supervisor>>, Option<*mut [u8; CALLBACK_STACK_SIZE]>)
+ {
+ let mut sv_guard = SUPERVISOR.lock().unwrap();
+ // If the supervisor is not initialised for whatever reason, fast-fail.
+ // This might be desired behaviour, as even on platforms where ptracing
+ // is not implemented it enables us to enforce that only one FFI call
+ // happens at a time.
+ let Some(sv) = sv_guard.take() else {
+ return (sv_guard, None);
+ };
+
+ // Get pointers to all the pages the supervisor must allow accesses in
+ // and prepare the callback stack.
+ let page_ptrs = alloc.borrow().pages();
+ let raw_stack_ptr: *mut [u8; CALLBACK_STACK_SIZE] =
+ Box::leak(Box::new([0u8; CALLBACK_STACK_SIZE])).as_mut_ptr().cast();
+ let stack_ptr = raw_stack_ptr.expose_provenance();
+ let start_info = StartFfiInfo { page_ptrs, stack_ptr };
+
+ // SAFETY: We do not access machine memory past this point until the
+ // supervisor is ready to allow it.
+ unsafe {
+ if alloc.borrow_mut().prepare_ffi().is_err() {
+ // Don't mess up unwinding by maybe leaving the memory partly protected
+ alloc.borrow_mut().unprep_ffi();
+ panic!("Cannot protect memory for FFI call!");
+ }
+ }
+
+ // Send over the info.
+ // NB: if we do not wait to receive a blank confirmation response, it is
+ // possible that the supervisor is alerted of the SIGSTOP *before* it has
+ // actually received the start_info, thus deadlocking! This way, we can
+ // enforce an ordering for these events.
+ sv.message_tx.send(TraceRequest::StartFfi(start_info)).unwrap();
+ sv.confirm_rx.recv().unwrap();
+ *sv_guard = Some(sv);
+ // We need to be stopped for the supervisor to be able to make certain
+ // modifications to our memory - simply waiting on the recv() doesn't
+ // count.
+ signal::raise(signal::SIGSTOP).unwrap();
+ (sv_guard, Some(raw_stack_ptr))
+ }
+
+ /// Undoes FFI-related preparations, allowing Miri to continue as normal, then
+ /// gets the memory accesses and changes performed during the FFI call. Note
+ /// that this may include some spurious accesses done by `libffi` itself in
+ /// the process of executing the function call.
+ ///
+ /// SAFETY: The `sv_guard` and `raw_stack_ptr` passed must be the same ones
+ /// received by a prior call to `start_ffi`, and the allocator must be the
+ /// one passed to it also.
+ pub unsafe fn end_ffi(
+ alloc: &Rc<RefCell<IsolatedAlloc>>,
+ mut sv_guard: std::sync::MutexGuard<'static, Option<Supervisor>>,
+ raw_stack_ptr: Option<*mut [u8; CALLBACK_STACK_SIZE]>,
+ ) -> Option<MemEvents> {
+ // We can't use IPC channels here to signal that FFI mode has ended,
+ // since they might allocate memory which could get us stuck in a SIGTRAP
+ // with no easy way out! While this could be worked around, it is much
+ // simpler and more robust to simply use the signals which are left for
+ // arbitrary usage. Since this will block until we are continued by the
+ // supervisor, we can assume past this point that everything is back to
+ // normal.
+ signal::raise(signal::SIGUSR1).unwrap();
+
+ // This is safe! It just sets memory to normal expected permissions.
+ alloc.borrow_mut().unprep_ffi();
+
+ // If this is `None`, then `raw_stack_ptr` is None and does not need to
+ // be deallocated (and there's no need to worry about the guard, since
+ // it contains nothing).
+ let sv = sv_guard.take()?;
+ // SAFETY: Caller upholds that this pointer was allocated as a box with
+ // this type.
+ unsafe {
+ drop(Box::from_raw(raw_stack_ptr.unwrap()));
+ }
+ // On the off-chance something really weird happens, don't block forever.
+ let ret = sv
+ .event_rx
+ .try_recv_timeout(std::time::Duration::from_secs(5))
+ .map_err(|e| {
+ match e {
+ ipc::TryRecvError::IpcError(_) => (),
+ ipc::TryRecvError::Empty =>
+ eprintln!("Waiting for accesses from supervisor timed out!"),
+ }
+ })
+ .ok();
+ // Do *not* leave the supervisor empty, or else we might get another fork...
+ *sv_guard = Some(sv);
+ ret
+ }
+}
+
+/// Initialises the supervisor process. If this function errors, then the
+/// supervisor process could not be created successfully; else, the caller
+/// is now the child process and can communicate via `start_ffi`/`end_ffi`,
+/// receiving back events through `get_events`.
+///
+/// # Safety
+/// The invariants for `fork()` must be upheld by the caller.
+pub unsafe fn init_sv() -> Result<(), SvInitError> {
+ // FIXME: Much of this could be reimplemented via the mitosis crate if we upstream the
+ // relevant missing bits.
+
+ // On Linux, this will check whether ptrace is fully disabled by the Yama module.
+ // If Yama isn't running or we're not on Linux, we'll still error later, but
+ // this saves a very expensive fork call.
+ let ptrace_status = std::fs::read_to_string("/proc/sys/kernel/yama/ptrace_scope");
+ if let Ok(stat) = ptrace_status {
+ if let Some(stat) = stat.chars().next() {
+ // Fast-error if ptrace is fully disabled on the system.
+ if stat == '3' {
+ return Err(SvInitError);
+ }
+ }
+ }
+
+ // Initialise the supervisor if it isn't already, placing it into SUPERVISOR.
+ let mut lock = SUPERVISOR.lock().unwrap();
+ if lock.is_some() {
+ return Ok(());
+ }
+
+ // Prepare the IPC channels we need.
+ let (message_tx, message_rx) = ipc::channel().unwrap();
+ let (confirm_tx, confirm_rx) = ipc::channel().unwrap();
+ let (event_tx, event_rx) = ipc::channel().unwrap();
+ // SAFETY: Calling sysconf(_SC_PAGESIZE) is always safe and cannot error.
+ let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }.try_into().unwrap();
+ super::parent::PAGE_SIZE.store(page_size, std::sync::atomic::Ordering::Relaxed);
+
+ unsafe {
+ // TODO: Maybe use clone3() instead for better signalling of when the child exits?
+ // SAFETY: Caller upholds that only one thread exists.
+ match unistd::fork().unwrap() {
+ unistd::ForkResult::Parent { child } => {
+ // If somehow another thread does exist, prevent it from accessing the lock
+ // and thus breaking our safety invariants.
+ std::mem::forget(lock);
+ // The child process is free to unwind, so we won't to avoid doubly freeing
+ // system resources.
+ let init = std::panic::catch_unwind(|| {
+ let listener =
+ ChildListener { message_rx, attached: false, override_retcode: None };
+ // Trace as many things as possible, to be able to handle them as needed.
+ let options = ptrace::Options::PTRACE_O_TRACESYSGOOD
+ | ptrace::Options::PTRACE_O_TRACECLONE
+ | ptrace::Options::PTRACE_O_TRACEFORK;
+ // Attach to the child process without stopping it.
+ match ptrace::seize(child, options) {
+ // Ptrace works :D
+ Ok(_) => {
+ let code = sv_loop(listener, child, event_tx, confirm_tx).unwrap_err();
+ // If a return code of 0 is not explicitly given, assume something went
+ // wrong and return 1.
+ std::process::exit(code.0.unwrap_or(1))
+ }
+ // Ptrace does not work and we failed to catch that.
+ Err(_) => {
+ // If we can't ptrace, Miri continues being the parent.
+ signal::kill(child, signal::SIGKILL).unwrap();
+ SvInitError
+ }
+ }
+ });
+ match init {
+ // The "Ok" case means that we couldn't ptrace.
+ Ok(e) => return Err(e),
+ Err(p) => {
+ eprintln!("Supervisor process panicked!\n{p:?}");
+ std::process::exit(1);
+ }
+ }
+ }
+ unistd::ForkResult::Child => {
+ // Make sure we never get orphaned and stuck in SIGSTOP or similar
+ // SAFETY: prctl PR_SET_PDEATHSIG is always safe to call.
+ let ret = libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGTERM);
+ assert_eq!(ret, 0);
+ // First make sure the parent succeeded with ptracing us!
+ signal::raise(signal::SIGSTOP).unwrap();
+ // If we're the child process, save the supervisor info.
+ *lock = Some(Supervisor { message_tx, confirm_rx, event_rx });
+ }
+ }
+ }
+ Ok(())
+}
+
+/// Instruct the supervisor process to return a particular code. Useful if for
+/// whatever reason this code fails to be intercepted normally. In the case of
+/// `abort_if_errors()` used in `bin/miri.rs`, the return code is erroneously
+/// given as a 0 if this is not used.
+pub fn register_retcode_sv(code: i32) {
+ let mut sv_guard = SUPERVISOR.lock().unwrap();
+ if let Some(sv) = sv_guard.take() {
+ sv.message_tx.send(TraceRequest::OverrideRetcode(code)).unwrap();
+ *sv_guard = Some(sv);
+ }
+}
diff --git a/src/tools/miri/src/shims/native_lib/trace/messages.rs b/src/tools/miri/src/shims/native_lib/trace/messages.rs
new file mode 100644
index 0000000..8a83dab
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/messages.rs
@@ -0,0 +1,80 @@
+//! Houses the types that are directly sent across the IPC channels.
+//!
+//! The overall structure of a traced FFI call, from the child process's POV, is
+//! as follows:
+//! ```
+//! message_tx.send(TraceRequest::StartFfi);
+//! confirm_rx.recv();
+//! raise(SIGSTOP);
+//! /* do ffi call */
+//! raise(SIGUSR1); // morally equivalent to some kind of "TraceRequest::EndFfi"
+//! let events = event_rx.recv();
+//! ```
+//! `TraceRequest::OverrideRetcode` can be sent at any point in the above, including
+//! before or after all of them.
+//!
+//! NB: sending these events out of order, skipping steps, etc. will result in
+//! unspecified behaviour from the supervisor process, so use the abstractions
+//! in `super::child` (namely `start_ffi()` and `end_ffi()`) to handle this. It is
+//! trivially easy to cause a deadlock or crash by messing this up!
+
+use std::ops::Range;
+
+/// An IPC request sent by the child process to the parent.
+///
+/// The sender for this channel should live on the child process.
+#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
+pub enum TraceRequest {
+ /// Requests that tracing begins. Following this being sent, the child must
+ /// wait to receive a `Confirmation` on the respective channel and then
+ /// `raise(SIGSTOP)`.
+ ///
+ /// To avoid possible issues while allocating memory for IPC channels, ending
+ /// the tracing is instead done via `raise(SIGUSR1)`.
+ StartFfi(StartFfiInfo),
+ /// Manually overrides the code that the supervisor will return upon exiting.
+ /// Once set, it is permanent. This can be called again to change the value.
+ OverrideRetcode(i32),
+}
+
+/// Information needed to begin tracing.
+#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
+pub struct StartFfiInfo {
+ /// A vector of page addresses. These should have been automatically obtained
+ /// with `IsolatedAlloc::pages` and prepared with `IsolatedAlloc::prepare_ffi`.
+ pub page_ptrs: Vec<usize>,
+ /// The address of an allocation that can serve as a temporary stack.
+ /// This should be a leaked `Box<[u8; CALLBACK_STACK_SIZE]>` cast to an int.
+ pub stack_ptr: usize,
+}
+
+/// A marker type confirming that the supervisor has received the request to begin
+/// tracing and is now waiting for a `SIGSTOP`.
+///
+/// The sender for this channel should live on the parent process.
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+pub struct Confirmation;
+
+/// The final results of an FFI trace, containing every relevant event detected
+/// by the tracer. Sent by the supervisor after receiving a `SIGUSR1` signal.
+///
+/// The sender for this channel should live on the parent process.
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+pub struct MemEvents {
+ /// An ordered list of memory accesses that occurred. These should be assumed
+ /// to be overcautious; that is, if the size of an access is uncertain it is
+ /// pessimistically rounded up, and if the type (read/write/both) is uncertain
+ /// it is reported as whatever would be safest to assume; i.e. a read + maybe-write
+ /// becomes a read + write, etc.
+ pub acc_events: Vec<AccessEvent>,
+}
+
+/// A single memory access, conservatively overestimated
+/// in case of ambiguity.
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+pub enum AccessEvent {
+ /// A read may have occurred on no more than the specified address range.
+ Read(Range<usize>),
+ /// A write may have occurred on no more than the specified address range.
+ Write(Range<usize>),
+}
diff --git a/src/tools/miri/src/shims/native_lib/trace/mod.rs b/src/tools/miri/src/shims/native_lib/trace/mod.rs
new file mode 100644
index 0000000..174b06b
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/mod.rs
@@ -0,0 +1,8 @@
+mod child;
+pub mod messages;
+mod parent;
+
+pub use self::child::{Supervisor, init_sv, register_retcode_sv};
+
+/// The size of the temporary stack we use for callbacks that the server executes in the client.
+const CALLBACK_STACK_SIZE: usize = 1024;
diff --git a/src/tools/miri/src/shims/native_lib/trace/parent.rs b/src/tools/miri/src/shims/native_lib/trace/parent.rs
new file mode 100644
index 0000000..dfb0b35
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/parent.rs
@@ -0,0 +1,660 @@
+use std::sync::atomic::{AtomicPtr, AtomicUsize};
+
+use ipc_channel::ipc;
+use nix::sys::{ptrace, signal, wait};
+use nix::unistd;
+
+use super::CALLBACK_STACK_SIZE;
+use super::messages::{AccessEvent, Confirmation, MemEvents, StartFfiInfo, TraceRequest};
+
+/// The flags to use when calling `waitid()`.
+/// Since bitwise or on the nix version of these flags is implemented as a trait,
+/// this cannot be const directly so we do it this way.
+const WAIT_FLAGS: wait::WaitPidFlag =
+ wait::WaitPidFlag::from_bits_truncate(libc::WUNTRACED | libc::WEXITED);
+
+/// Arch-specific maximum size a single access might perform. x86 value is set
+/// assuming nothing bigger than AVX-512 is available.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+const ARCH_MAX_ACCESS_SIZE: usize = 64;
+/// The largest arm64 simd instruction operates on 16 bytes.
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+const ARCH_MAX_ACCESS_SIZE: usize = 16;
+
+/// The default word size on a given platform, in bytes.
+#[cfg(any(target_arch = "x86", target_arch = "arm"))]
+const ARCH_WORD_SIZE: usize = 4;
+#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
+const ARCH_WORD_SIZE: usize = 8;
+
+/// The address of the page set to be edited, initialised to a sentinel null
+/// pointer.
+static PAGE_ADDR: AtomicPtr<u8> = AtomicPtr::new(std::ptr::null_mut());
+/// The host pagesize, initialised to a sentinel zero value.
+pub static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
+/// How many consecutive pages to unprotect. 1 by default, unlikely to be set
+/// higher than 2.
+static PAGE_COUNT: AtomicUsize = AtomicUsize::new(1);
+
+/// Allows us to get common arguments from the `user_regs_t` across architectures.
+/// Normally this would land us ABI hell, but thankfully all of our usecases
+/// consist of functions with a small number of register-sized integer arguments.
+/// See <https://man7.org/linux/man-pages/man2/syscall.2.html> for sources.
+trait ArchIndependentRegs {
+ /// Gets the address of the instruction pointer.
+ fn ip(&self) -> usize;
+ /// Set the instruction pointer; remember to also set the stack pointer, or
+ /// else the stack might get messed up!
+ fn set_ip(&mut self, ip: usize);
+ /// Set the stack pointer, ideally to a zeroed-out area.
+ fn set_sp(&mut self, sp: usize);
+}
+
+// It's fine / desirable behaviour for values to wrap here, we care about just
+// preserving the bit pattern.
+#[cfg(target_arch = "x86_64")]
+#[expect(clippy::as_conversions)]
+#[rustfmt::skip]
+impl ArchIndependentRegs for libc::user_regs_struct {
+ #[inline]
+ fn ip(&self) -> usize { self.rip as _ }
+ #[inline]
+ fn set_ip(&mut self, ip: usize) { self.rip = ip as _ }
+ #[inline]
+ fn set_sp(&mut self, sp: usize) { self.rsp = sp as _ }
+}
+
+#[cfg(target_arch = "x86")]
+#[expect(clippy::as_conversions)]
+#[rustfmt::skip]
+impl ArchIndependentRegs for libc::user_regs_struct {
+ #[inline]
+ fn ip(&self) -> usize { self.eip as _ }
+ #[inline]
+ fn set_ip(&mut self, ip: usize) { self.eip = ip as _ }
+ #[inline]
+ fn set_sp(&mut self, sp: usize) { self.esp = sp as _ }
+}
+
+#[cfg(target_arch = "aarch64")]
+#[expect(clippy::as_conversions)]
+#[rustfmt::skip]
+impl ArchIndependentRegs for libc::user_regs_struct {
+ #[inline]
+ fn ip(&self) -> usize { self.pc as _ }
+ #[inline]
+ fn set_ip(&mut self, ip: usize) { self.pc = ip as _ }
+ #[inline]
+ fn set_sp(&mut self, sp: usize) { self.sp = sp as _ }
+}
+
+/// A unified event representing something happening on the child process. Wraps
+/// `nix`'s `WaitStatus` and our custom signals so it can all be done with one
+/// `match` statement.
+pub enum ExecEvent {
+ /// Child process requests that we begin monitoring it.
+ Start(StartFfiInfo),
+ /// Child requests that we stop monitoring and pass over the events we
+ /// detected.
+ End,
+ /// The child process with the specified pid was stopped by the given signal.
+ Status(unistd::Pid, signal::Signal),
+ /// The child process with the specified pid entered or existed a syscall.
+ Syscall(unistd::Pid),
+ /// A child process exited or was killed; if we have a return code, it is
+ /// specified.
+ Died(Option<i32>),
+}
+
+/// A listener for the FFI start info channel along with relevant state.
+pub struct ChildListener {
+ /// The matching channel for the child's `Supervisor` struct.
+ pub message_rx: ipc::IpcReceiver<TraceRequest>,
+ /// Whether an FFI call is currently ongoing.
+ pub attached: bool,
+ /// If `Some`, overrides the return code with the given value.
+ pub override_retcode: Option<i32>,
+}
+
+impl Iterator for ChildListener {
+ type Item = ExecEvent;
+
+ // Allows us to monitor the child process by just iterating over the listener.
+ // NB: This should never return None!
+ fn next(&mut self) -> Option<Self::Item> {
+ // Do not block if the child has nothing to report for `waitid`.
+ let opts = WAIT_FLAGS | wait::WaitPidFlag::WNOHANG;
+ loop {
+ // Listen to any child, not just the main one. Important if we want
+ // to allow the C code to fork further, along with being a bit of
+ // defensive programming since Linux sometimes assigns threads of
+ // the same process different PIDs with unpredictable rules...
+ match wait::waitid(wait::Id::All, opts) {
+ Ok(stat) =>
+ match stat {
+ // Child exited normally with a specific code set.
+ wait::WaitStatus::Exited(_, code) => {
+ let code = self.override_retcode.unwrap_or(code);
+ return Some(ExecEvent::Died(Some(code)));
+ }
+ // Child was killed by a signal, without giving a code.
+ wait::WaitStatus::Signaled(_, _, _) =>
+ return Some(ExecEvent::Died(self.override_retcode)),
+ // Child entered a syscall. Since we're always technically
+ // tracing, only pass this along if we're actively
+ // monitoring the child.
+ wait::WaitStatus::PtraceSyscall(pid) =>
+ if self.attached {
+ return Some(ExecEvent::Syscall(pid));
+ },
+ // Child with the given pid was stopped by the given signal.
+ // It's somewhat dubious when this is returned instead of
+ // WaitStatus::Stopped, but for our purposes they are the
+ // same thing.
+ wait::WaitStatus::PtraceEvent(pid, signal, _) =>
+ if self.attached {
+ // This is our end-of-FFI signal!
+ if signal == signal::SIGUSR1 {
+ self.attached = false;
+ return Some(ExecEvent::End);
+ } else {
+ return Some(ExecEvent::Status(pid, signal));
+ }
+ } else {
+ // Just pass along the signal.
+ ptrace::cont(pid, signal).unwrap();
+ },
+ // Child was stopped at the given signal. Same logic as for
+ // WaitStatus::PtraceEvent.
+ wait::WaitStatus::Stopped(pid, signal) =>
+ if self.attached {
+ if signal == signal::SIGUSR1 {
+ self.attached = false;
+ return Some(ExecEvent::End);
+ } else {
+ return Some(ExecEvent::Status(pid, signal));
+ }
+ } else {
+ ptrace::cont(pid, signal).unwrap();
+ },
+ _ => (),
+ },
+ // This case should only trigger if all children died and we
+ // somehow missed that, but it's best we not allow any room
+ // for deadlocks.
+ Err(_) => return Some(ExecEvent::Died(None)),
+ }
+
+ // Similarly, do a non-blocking poll of the IPC channel.
+ if let Ok(req) = self.message_rx.try_recv() {
+ match req {
+ TraceRequest::StartFfi(info) =>
+ // Should never trigger - but better to panic explicitly than deadlock!
+ if self.attached {
+ panic!("Attempting to begin FFI multiple times!");
+ } else {
+ self.attached = true;
+ return Some(ExecEvent::Start(info));
+ },
+ TraceRequest::OverrideRetcode(code) => self.override_retcode = Some(code),
+ }
+ }
+
+ // Not ideal, but doing anything else might sacrifice performance.
+ std::thread::yield_now();
+ }
+ }
+}
+
+/// An error came up while waiting on the child process to do something.
+/// It likely died, with this return code if we have one.
+#[derive(Debug)]
+pub struct ExecEnd(pub Option<i32>);
+
+/// This is the main loop of the supervisor process. It runs in a separate
+/// process from the rest of Miri (but because we fork, addresses for anything
+/// created before the fork - like statics - are the same).
+pub fn sv_loop(
+ listener: ChildListener,
+ init_pid: unistd::Pid,
+ event_tx: ipc::IpcSender<MemEvents>,
+ confirm_tx: ipc::IpcSender<Confirmation>,
+) -> Result<!, ExecEnd> {
+ // Get the pagesize set and make sure it isn't still on the zero sentinel value!
+ let page_size = PAGE_SIZE.load(std::sync::atomic::Ordering::Relaxed);
+ assert_ne!(page_size, 0);
+
+ // Things that we return to the child process.
+ let mut acc_events = Vec::new();
+
+ // Memory allocated for the MiriMachine.
+ let mut ch_pages = Vec::new();
+ let mut ch_stack = None;
+
+ // An instance of the Capstone disassembler, so we don't spawn one on every access.
+ let cs = get_disasm();
+
+ // The pid of the last process we interacted with, used by default if we don't have a
+ // reason to use a different one.
+ let mut curr_pid = init_pid;
+
+ // There's an initial sigstop we need to deal with.
+ wait_for_signal(Some(curr_pid), signal::SIGSTOP, false)?;
+ ptrace::cont(curr_pid, None).unwrap();
+
+ for evt in listener {
+ match evt {
+ // start_ffi was called by the child, so prep memory.
+ ExecEvent::Start(ch_info) => {
+ // All the pages that the child process is "allowed to" access.
+ ch_pages = ch_info.page_ptrs;
+ // And the temporary callback stack it allocated for us to use later.
+ ch_stack = Some(ch_info.stack_ptr);
+
+ // We received the signal and are no longer in the main listener loop,
+ // so we can let the child move on to the end of start_ffi where it will
+ // raise a SIGSTOP. We need it to be signal-stopped *and waited for* in
+ // order to do most ptrace operations!
+ confirm_tx.send(Confirmation).unwrap();
+ // We can't trust simply calling `Pid::this()` in the child process to give the right
+ // PID for us, so we get it this way.
+ curr_pid = wait_for_signal(None, signal::SIGSTOP, false).unwrap();
+
+ ptrace::syscall(curr_pid, None).unwrap();
+ }
+ // end_ffi was called by the child.
+ ExecEvent::End => {
+ // Hand over the access info we traced.
+ event_tx.send(MemEvents { acc_events }).unwrap();
+ // And reset our values.
+ acc_events = Vec::new();
+ ch_stack = None;
+
+ // No need to monitor syscalls anymore, they'd just be ignored.
+ ptrace::cont(curr_pid, None).unwrap();
+ }
+ // Child process was stopped by a signal
+ ExecEvent::Status(pid, signal) =>
+ match signal {
+ // If it was a segfault, check if it was an artificial one
+ // caused by it trying to access the MiriMachine memory.
+ signal::SIGSEGV =>
+ handle_segfault(
+ pid,
+ &ch_pages,
+ ch_stack.unwrap(),
+ page_size,
+ &cs,
+ &mut acc_events,
+ )?,
+ // Something weird happened.
+ _ => {
+ eprintln!("Process unexpectedly got {signal}; continuing...");
+ // In case we're not tracing
+ if ptrace::syscall(pid, None).is_err() {
+ // If *this* fails too, something really weird happened
+ // and it's probably best to just panic.
+ signal::kill(pid, signal::SIGCONT).unwrap();
+ }
+ }
+ },
+ // Child entered a syscall; we wait for exits inside of this, so it
+ // should never trigger on return from a syscall we care about.
+ ExecEvent::Syscall(pid) => {
+ ptrace::syscall(pid, None).unwrap();
+ }
+ ExecEvent::Died(code) => {
+ return Err(ExecEnd(code));
+ }
+ }
+ }
+
+ unreachable!()
+}
+
+/// Spawns a Capstone disassembler for the host architecture.
+#[rustfmt::skip]
+fn get_disasm() -> capstone::Capstone {
+ use capstone::prelude::*;
+ let cs_pre = Capstone::new();
+ {
+ #[cfg(target_arch = "x86_64")]
+ {cs_pre.x86().mode(arch::x86::ArchMode::Mode64)}
+ #[cfg(target_arch = "x86")]
+ {cs_pre.x86().mode(arch::x86::ArchMode::Mode32)}
+ #[cfg(target_arch = "aarch64")]
+ {cs_pre.arm64().mode(arch::arm64::ArchMode::Arm)}
+ #[cfg(target_arch = "arm")]
+ {cs_pre.arm().mode(arch::arm::ArchMode::Arm)}
+ }
+ .detail(true)
+ .build()
+ .unwrap()
+}
+
+/// Waits for `wait_signal`. If `init_cont`, it will first do a `ptrace::cont`.
+/// We want to avoid that in some cases, like at the beginning of FFI.
+///
+/// If `pid` is `None`, only one wait will be done and `init_cont` should be false.
+fn wait_for_signal(
+ pid: Option<unistd::Pid>,
+ wait_signal: signal::Signal,
+ init_cont: bool,
+) -> Result<unistd::Pid, ExecEnd> {
+ if init_cont {
+ ptrace::cont(pid.unwrap(), None).unwrap();
+ }
+ // Repeatedly call `waitid` until we get the signal we want, or the process dies.
+ loop {
+ let wait_id = match pid {
+ Some(pid) => wait::Id::Pid(pid),
+ None => wait::Id::All,
+ };
+ let stat = wait::waitid(wait_id, WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+ let (signal, pid) = match stat {
+ // Report the cause of death, if we know it.
+ wait::WaitStatus::Exited(_, code) => {
+ return Err(ExecEnd(Some(code)));
+ }
+ wait::WaitStatus::Signaled(_, _, _) => return Err(ExecEnd(None)),
+ wait::WaitStatus::Stopped(pid, signal) => (signal, pid),
+ wait::WaitStatus::PtraceEvent(pid, signal, _) => (signal, pid),
+ // This covers PtraceSyscall and variants that are impossible with
+ // the flags set (e.g. WaitStatus::StillAlive).
+ _ => {
+ ptrace::cont(pid.unwrap(), None).unwrap();
+ continue;
+ }
+ };
+ if signal == wait_signal {
+ return Ok(pid);
+ } else {
+ ptrace::cont(pid, signal).map_err(|_| ExecEnd(None))?;
+ }
+ }
+}
+
+/// Grabs the access that caused a segfault and logs it down if it's to our memory,
+/// or kills the child and returns the appropriate error otherwise.
+fn handle_segfault(
+ pid: unistd::Pid,
+ ch_pages: &[usize],
+ ch_stack: usize,
+ page_size: usize,
+ cs: &capstone::Capstone,
+ acc_events: &mut Vec<AccessEvent>,
+) -> Result<(), ExecEnd> {
+ /// This is just here to not pollute the main namespace with `capstone::prelude::*`.
+ #[inline]
+ fn capstone_disassemble(
+ instr: &[u8],
+ addr: usize,
+ cs: &capstone::Capstone,
+ acc_events: &mut Vec<AccessEvent>,
+ ) -> capstone::CsResult<()> {
+ use capstone::prelude::*;
+
+ // The arch_detail is what we care about, but it relies on these temporaries
+ // that we can't drop. 0x1000 is the default base address for Captsone, and
+ // we're expecting 1 instruction.
+ let insns = cs.disasm_count(instr, 0x1000, 1)?;
+ let ins_detail = cs.insn_detail(&insns[0])?;
+ let arch_detail = ins_detail.arch_detail();
+
+ for op in arch_detail.operands() {
+ match op {
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ arch::ArchOperand::X86Operand(x86_operand) => {
+ match x86_operand.op_type {
+ // We only care about memory accesses
+ arch::x86::X86OperandType::Mem(_) => {
+ let push = addr..addr.strict_add(usize::from(x86_operand.size));
+ // It's called a "RegAccessType" but it also applies to memory
+ let acc_ty = x86_operand.access.unwrap();
+ if acc_ty.is_readable() {
+ acc_events.push(AccessEvent::Read(push.clone()));
+ }
+ if acc_ty.is_writable() {
+ acc_events.push(AccessEvent::Write(push));
+ }
+ }
+ _ => (),
+ }
+ }
+ #[cfg(target_arch = "aarch64")]
+ arch::ArchOperand::Arm64Operand(arm64_operand) => {
+ // Annoyingly, we don't always get the size here, so just be pessimistic for now.
+ match arm64_operand.op_type {
+ arch::arm64::Arm64OperandType::Mem(_) => {
+ // B = 1 byte, H = 2 bytes, S = 4 bytes, D = 8 bytes, Q = 16 bytes.
+ let size = match arm64_operand.vas {
+ // Not an fp/simd instruction.
+ arch::arm64::Arm64Vas::ARM64_VAS_INVALID => ARCH_WORD_SIZE,
+ // 1 byte.
+ arch::arm64::Arm64Vas::ARM64_VAS_1B => 1,
+ // 2 bytes.
+ arch::arm64::Arm64Vas::ARM64_VAS_1H => 2,
+ // 4 bytes.
+ arch::arm64::Arm64Vas::ARM64_VAS_4B
+ | arch::arm64::Arm64Vas::ARM64_VAS_2H
+ | arch::arm64::Arm64Vas::ARM64_VAS_1S => 4,
+ // 8 bytes.
+ arch::arm64::Arm64Vas::ARM64_VAS_8B
+ | arch::arm64::Arm64Vas::ARM64_VAS_4H
+ | arch::arm64::Arm64Vas::ARM64_VAS_2S
+ | arch::arm64::Arm64Vas::ARM64_VAS_1D => 8,
+ // 16 bytes.
+ arch::arm64::Arm64Vas::ARM64_VAS_16B
+ | arch::arm64::Arm64Vas::ARM64_VAS_8H
+ | arch::arm64::Arm64Vas::ARM64_VAS_4S
+ | arch::arm64::Arm64Vas::ARM64_VAS_2D
+ | arch::arm64::Arm64Vas::ARM64_VAS_1Q => 16,
+ };
+ let push = addr..addr.strict_add(size);
+ // FIXME: This now has access type info in the latest
+ // git version of capstone because this pissed me off
+ // and I added it. Change this when it updates.
+ acc_events.push(AccessEvent::Read(push.clone()));
+ acc_events.push(AccessEvent::Write(push));
+ }
+ _ => (),
+ }
+ }
+ #[cfg(target_arch = "arm")]
+ arch::ArchOperand::ArmOperand(arm_operand) =>
+ match arm_operand.op_type {
+ arch::arm::ArmOperandType::Mem(_) => {
+ // We don't get info on the size of the access, but
+ // we're at least told if it's a vector instruction.
+ let size = if arm_operand.vector_index.is_some() {
+ ARCH_MAX_ACCESS_SIZE
+ } else {
+ ARCH_WORD_SIZE
+ };
+ let push = addr..addr.strict_add(size);
+ let acc_ty = arm_operand.access.unwrap();
+ if acc_ty.is_readable() {
+ acc_events.push(AccessEvent::Read(push.clone()));
+ }
+ if acc_ty.is_writable() {
+ acc_events.push(AccessEvent::Write(push));
+ }
+ }
+ _ => (),
+ },
+ _ => unimplemented!(),
+ }
+ }
+
+ Ok(())
+ }
+
+ // Get information on what caused the segfault. This contains the address
+ // that triggered it.
+ let siginfo = ptrace::getsiginfo(pid).unwrap();
+ // All x86, ARM, etc. instructions only have at most one memory operand
+ // (thankfully!)
+ // SAFETY: si_addr is safe to call.
+ let addr = unsafe { siginfo.si_addr().addr() };
+ let page_addr = addr.strict_sub(addr.strict_rem(page_size));
+
+ if !ch_pages.iter().any(|pg| (*pg..pg.strict_add(page_size)).contains(&addr)) {
+ // This was a real segfault (not one of the Miri memory pages), so print some debug info and
+ // quit.
+ let regs = ptrace::getregs(pid).unwrap();
+ eprintln!("Segfault occurred during FFI at {addr:#018x}");
+ eprintln!("Expected access on pages: {ch_pages:#018x?}");
+ eprintln!("Register dump: {regs:#x?}");
+ ptrace::kill(pid).unwrap();
+ return Err(ExecEnd(None));
+ }
+
+ // Overall structure:
+ // - Get the address that caused the segfault
+ // - Unprotect the memory: we force the child to execute `mempr_off`, passing parameters via
+ // global atomic variables. This is what we use the temporary callback stack for.
+ // - Step 1 instruction
+ // - Parse executed code to estimate size & type of access
+ // - Reprotect the memory by executing `mempr_on` in the child.
+ // - Continue
+
+ // Ensure the stack is properly zeroed out!
+ for a in (ch_stack..ch_stack.strict_add(CALLBACK_STACK_SIZE)).step_by(ARCH_WORD_SIZE) {
+ ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap();
+ }
+
+ // Guard against both architectures with upwards and downwards-growing stacks.
+ let stack_ptr = ch_stack.strict_add(CALLBACK_STACK_SIZE / 2);
+ let regs_bak = ptrace::getregs(pid).unwrap();
+ let mut new_regs = regs_bak;
+ let ip_prestep = regs_bak.ip();
+
+ // Move the instr ptr into the deprotection code.
+ #[expect(clippy::as_conversions)]
+ new_regs.set_ip(mempr_off as usize);
+ // Don't mess up the stack by accident!
+ new_regs.set_sp(stack_ptr);
+
+ // Modify the PAGE_ADDR global on the child process to point to the page
+ // that we want unprotected.
+ ptrace::write(
+ pid,
+ (&raw const PAGE_ADDR).cast_mut().cast(),
+ libc::c_long::try_from(page_addr).unwrap(),
+ )
+ .unwrap();
+
+ // Check if we also own the next page, and if so unprotect it in case
+ // the access spans the page boundary.
+ let flag = if ch_pages.contains(&page_addr.strict_add(page_size)) { 2 } else { 1 };
+ ptrace::write(pid, (&raw const PAGE_COUNT).cast_mut().cast(), flag).unwrap();
+
+ ptrace::setregs(pid, new_regs).unwrap();
+
+ // Our mempr_* functions end with a raise(SIGSTOP).
+ wait_for_signal(Some(pid), signal::SIGSTOP, true)?;
+
+ // Step 1 instruction.
+ ptrace::setregs(pid, regs_bak).unwrap();
+ ptrace::step(pid, None).unwrap();
+ // Don't use wait_for_signal here since 1 instruction doesn't give room
+ // for any uncertainty + we don't want it `cont()`ing randomly by accident
+ // Also, don't let it continue with unprotected memory if something errors!
+ let _ = wait::waitid(wait::Id::Pid(pid), WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+
+ // Zero out again to be safe
+ for a in (ch_stack..ch_stack.strict_add(CALLBACK_STACK_SIZE)).step_by(ARCH_WORD_SIZE) {
+ ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap();
+ }
+
+ // Save registers and grab the bytes that were executed. This would
+ // be really nasty if it was a jump or similar but those thankfully
+ // won't do memory accesses and so can't trigger this!
+ let regs_bak = ptrace::getregs(pid).unwrap();
+ new_regs = regs_bak;
+ let ip_poststep = regs_bak.ip();
+ // We need to do reads/writes in word-sized chunks.
+ let diff = (ip_poststep.strict_sub(ip_prestep)).div_ceil(ARCH_WORD_SIZE);
+ let instr = (ip_prestep..ip_prestep.strict_add(diff)).fold(vec![], |mut ret, ip| {
+ // This only needs to be a valid pointer in the child process, not ours.
+ ret.append(
+ &mut ptrace::read(pid, std::ptr::without_provenance_mut(ip))
+ .unwrap()
+ .to_ne_bytes()
+ .to_vec(),
+ );
+ ret
+ });
+
+ // Now figure out the size + type of access and log it down.
+ // This will mark down e.g. the same area being read multiple times,
+ // since it's more efficient to compress the accesses at the end.
+ if capstone_disassemble(&instr, addr, cs, acc_events).is_err() {
+ // Read goes first because we need to be pessimistic.
+ acc_events.push(AccessEvent::Read(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE)));
+ acc_events.push(AccessEvent::Write(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE)));
+ }
+
+ // Reprotect everything and continue.
+ #[expect(clippy::as_conversions)]
+ new_regs.set_ip(mempr_on as usize);
+ new_regs.set_sp(stack_ptr);
+ ptrace::setregs(pid, new_regs).unwrap();
+ wait_for_signal(Some(pid), signal::SIGSTOP, true)?;
+
+ ptrace::setregs(pid, regs_bak).unwrap();
+ ptrace::syscall(pid, None).unwrap();
+ Ok(())
+}
+
+// We only get dropped into these functions via offsetting the instr pointer
+// manually, so we *must not ever* unwind from them.
+
+/// Disables protections on the page whose address is currently in `PAGE_ADDR`.
+///
+/// SAFETY: `PAGE_ADDR` should be set to a page-aligned pointer to an owned page,
+/// `PAGE_SIZE` should be the host pagesize, and the range from `PAGE_ADDR` to
+/// `PAGE_SIZE` * `PAGE_COUNT` must be owned and allocated memory. No other threads
+/// should be running.
+pub unsafe extern "C" fn mempr_off() {
+ use std::sync::atomic::Ordering;
+
+ // Again, cannot allow unwinds to happen here.
+ let len = PAGE_SIZE.load(Ordering::Relaxed).saturating_mul(PAGE_COUNT.load(Ordering::Relaxed));
+ // SAFETY: Upheld by "caller".
+ unsafe {
+ // It's up to the caller to make sure this doesn't actually overflow, but
+ // we mustn't unwind from here, so...
+ if libc::mprotect(
+ PAGE_ADDR.load(Ordering::Relaxed).cast(),
+ len,
+ libc::PROT_READ | libc::PROT_WRITE,
+ ) != 0
+ {
+ // Can't return or unwind, but we can do this.
+ std::process::exit(-1);
+ }
+ }
+ // If this fails somehow we're doomed.
+ if signal::raise(signal::SIGSTOP).is_err() {
+ std::process::exit(-1);
+ }
+}
+
+/// Reenables protection on the page set by `PAGE_ADDR`.
+///
+/// SAFETY: See `mempr_off()`.
+pub unsafe extern "C" fn mempr_on() {
+ use std::sync::atomic::Ordering;
+
+ let len = PAGE_SIZE.load(Ordering::Relaxed).wrapping_mul(PAGE_COUNT.load(Ordering::Relaxed));
+ // SAFETY: Upheld by "caller".
+ unsafe {
+ if libc::mprotect(PAGE_ADDR.load(Ordering::Relaxed).cast(), len, libc::PROT_NONE) != 0 {
+ std::process::exit(-1);
+ }
+ }
+ if signal::raise(signal::SIGSTOP).is_err() {
+ std::process::exit(-1);
+ }
+}
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index 7080edb..b9391a0f 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -7,7 +7,6 @@
use std::path::{Path, PathBuf};
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf;
use crate::*;
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 62ac7ee..604fb09 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -6,7 +6,6 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_index::IndexVec;
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf;
use crate::*;
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 9106ef9..b3c5839 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -3,7 +3,6 @@
use rustc_abi::{CanonAbi, ExternAbi, Size};
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf;
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
@@ -946,8 +945,7 @@ fn emulate_foreign_item_inner(
}
"pthread_join" => {
let [thread, retval] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
- let res = this.pthread_join(thread, retval)?;
- this.write_scalar(res, dest)?;
+ this.pthread_join(thread, retval, dest)?;
}
"pthread_detach" => {
let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 8e5a3021..47732f8 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -22,8 +22,7 @@ fn mremap(
let flags = this.read_scalar(flags)?.to_i32()?;
// old_address must be a multiple of the page size
- #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
- if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 {
+ if !old_address.addr().bytes().is_multiple_of(this.machine.page_size) || new_size == 0 {
this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
}
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index aefeee6..4bbbbc6 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -130,8 +130,7 @@ fn munmap(&mut self, addr: &OpTy<'tcx>, length: &OpTy<'tcx>) -> InterpResult<'tc
// addr must be a multiple of the page size, but apart from that munmap is just implemented
// as a dealloc.
- #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
- if addr.addr().bytes() % this.machine.page_size != 0 {
+ if !addr.addr().bytes().is_multiple_of(this.machine.page_size) {
return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index eee2bbc..50eb4d9 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -17,7 +17,7 @@ fn bytewise_equal_atomic_relaxed<'tcx>(
// We do this in chunks of 4, so that we are okay to race with (sufficiently aligned)
// 4-byte atomic accesses.
- assert!(size.bytes() % 4 == 0);
+ assert!(size.bytes().is_multiple_of(4));
for i in 0..(size.bytes() / 4) {
let offset = Size::from_bytes(i.strict_mul(4));
let load = |place: &MPlaceTy<'tcx>| {
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 4b6615b..a438e71 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -41,7 +41,8 @@ fn pthread_join(
&mut self,
thread: &OpTy<'tcx>,
retval: &OpTy<'tcx>,
- ) -> InterpResult<'tcx, Scalar> {
+ return_dest: &MPlaceTy<'tcx>,
+ ) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
if !this.ptr_is_null(this.read_pointer(retval)?)? {
@@ -51,12 +52,15 @@ fn pthread_join(
let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
let Ok(thread) = this.thread_id_try_from(thread) else {
- return interp_ok(this.eval_libc("ESRCH"));
+ this.write_scalar(this.eval_libc("ESRCH"), return_dest)?;
+ return interp_ok(());
};
- this.join_thread_exclusive(thread)?;
-
- interp_ok(Scalar::from_u32(0))
+ this.join_thread_exclusive(
+ thread,
+ /* success_retval */ Scalar::from_u32(0),
+ return_dest,
+ )
}
fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 10f6df6..de10357 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -573,8 +573,7 @@ fn emulate_foreign_item_inner(
"WaitForSingleObject" => {
let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
- let ret = this.WaitForSingleObject(handle, timeout)?;
- this.write_scalar(ret, dest)?;
+ this.WaitForSingleObject(handle, timeout, dest)?;
}
"GetCurrentProcess" => {
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index d5f9ed4..a155ec6 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -1,5 +1,4 @@
use rustc_abi::ExternAbi;
-use rustc_middle::ty::layout::LayoutOf;
use self::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
use crate::*;
@@ -59,13 +58,14 @@ fn WaitForSingleObject(
&mut self,
handle_op: &OpTy<'tcx>,
timeout_op: &OpTy<'tcx>,
- ) -> InterpResult<'tcx, Scalar> {
+ return_dest: &MPlaceTy<'tcx>,
+ ) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let handle = this.read_handle(handle_op, "WaitForSingleObject")?;
let timeout = this.read_scalar(timeout_op)?.to_u32()?;
- let thread = match handle {
+ let joined_thread_id = match handle {
Handle::Thread(thread) => thread,
// Unlike on posix, the outcome of joining the current thread is not documented.
// On current Windows, it just deadlocks.
@@ -77,8 +77,12 @@ fn WaitForSingleObject(
throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout");
}
- this.join_thread(thread)?;
+ this.join_thread(
+ joined_thread_id,
+ /* success_retval */ this.eval_windows("c", "WAIT_OBJECT_0"),
+ return_dest,
+ )?;
- interp_ok(this.eval_windows("c", "WAIT_OBJECT_0"))
+ interp_ok(())
}
}
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index 7191284..058ca24 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -1,6 +1,5 @@
use rustc_abi::CanonAbi;
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 37539fe..83d23d6 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -2,7 +2,6 @@
use rustc_apfloat::ieee::{Double, Single};
use rustc_middle::mir;
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index 5dfe5cc..49d5977 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -1,7 +1,6 @@
use rustc_abi::CanonAbi;
use rustc_middle::mir;
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 1e82f52..fbfe459 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -2,7 +2,6 @@
use rustc_apfloat::Float;
use rustc_apfloat::ieee::Single;
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
use rustc_middle::{mir, ty};
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index 830513f..7e1e148 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -1,7 +1,6 @@
use rustc_abi::{CanonAbi, Size};
use rustc_middle::mir;
use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
index c63e926..9646cdb 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
@@ -6,7 +6,7 @@ fn direct_raw(x: *const (i32, i32)) -> *const i32 {
// Ensure that if a raw pointer is created via an intermediate
// reference, we catch that. (Just in case someone decides to
-// desugar this differenly or so.)
+// desugar this differently or so.)
fn via_ref(x: *const (i32, i32)) -> *const i32 {
unsafe { &(*x).0 as *const i32 } //~ERROR: dangling pointer
}
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 3835791..f21c608 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -1066,17 +1066,6 @@ fn ldexp(a: f64, b: i32) -> f64 {
assert_eq!((-1f32).powf(f32::NEG_INFINITY), 1.0);
assert_eq!((-1f64).powf(f64::NEG_INFINITY), 1.0);
- // For pow (powf in rust) the C standard says:
- // x^0 = 1 for all x even a sNaN
- // FIXME(#4286): this does not match the behavior of all implementations.
- assert_eq!(SNAN_F32.powf(0.0), 1.0);
- assert_eq!(SNAN_F64.powf(0.0), 1.0);
-
- // For pown (powi in rust) the C standard says:
- // x^0 = 1 for all x even a sNaN
- // FIXME(#4286): this does not match the behavior of all implementations.
- assert_eq!(SNAN_F32.powi(0), 1.0);
- assert_eq!(SNAN_F64.powi(0), 1.0);
assert_eq!(0f32.powi(10), 0.0);
assert_eq!(0f64.powi(100), 0.0);
@@ -1500,4 +1489,18 @@ pub fn test_operations_f128(a: f128, b: f128) {
test_operations_f32(12., 5.);
test_operations_f64(19., 11.);
test_operations_f128(25., 18.);
+
+
+ // SNaN^0 = (1 | NaN)
+ ensure_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan());
+ ensure_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan());
+
+ // 1^SNaN = (1 | NaN)
+ ensure_nondet(|| f32::powf(1.0, SNAN_F32).is_nan());
+ ensure_nondet(|| f64::powf(1.0, SNAN_F64).is_nan());
+
+ // same as powf (keep it consistent):
+ // x^SNaN = (1 | NaN)
+ ensure_nondet(|| f32::powi(SNAN_F32, 0).is_nan());
+ ensure_nondet(|| f64::powi(SNAN_F64, 0).is_nan());
}
diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs
index cadbbd5..3ffdb68 100644
--- a/src/tools/miri/tests/pass/float_nan.rs
+++ b/src/tools/miri/tests/pass/float_nan.rs
@@ -260,6 +260,7 @@ fn test_f32() {
// Intrinsics
let nan = F32::nan(Neg, Quiet, 0).as_f32();
+ let snan = F32::nan(Neg, Signaling, 1).as_f32();
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(f32::min(nan, nan)),
@@ -313,6 +314,18 @@ fn test_f32() {
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.ln_gamma().0),
);
+ check_all_outcomes(
+ HashSet::from_iter([
+ F32::from(1.0),
+ F32::nan(Pos, Quiet, 0),
+ F32::nan(Neg, Quiet, 0),
+ F32::nan(Pos, Quiet, 1),
+ F32::nan(Neg, Quiet, 1),
+ F32::nan(Pos, Signaling, 1),
+ F32::nan(Neg, Signaling, 1),
+ ]),
+ || F32::from(snan.powf(0.0)),
+ );
}
fn test_f64() {
@@ -376,6 +389,7 @@ fn test_f64() {
// Intrinsics
let nan = F64::nan(Neg, Quiet, 0).as_f64();
+ let snan = F64::nan(Neg, Signaling, 1).as_f64();
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(f64::min(nan, nan)),
@@ -433,6 +447,18 @@ fn test_f64() {
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.ln_gamma().0),
);
+ check_all_outcomes(
+ HashSet::from_iter([
+ F64::from(1.0),
+ F64::nan(Pos, Quiet, 0),
+ F64::nan(Neg, Quiet, 0),
+ F64::nan(Pos, Quiet, 1),
+ F64::nan(Neg, Quiet, 1),
+ F64::nan(Pos, Signaling, 1),
+ F64::nan(Neg, Signaling, 1),
+ ]),
+ || F64::from(snan.powf(0.0)),
+ );
}
fn test_casts() {
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index e14ce51..726d4c0 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -570,6 +570,10 @@ fn simd_round() {
f32x4::from_array([1.0, 1.0, 2.0, -5.0])
);
assert_eq!(
+ unsafe { intrinsics::simd_round_ties_even(f32x4::from_array([0.9, 1.001, 2.0, -4.5])) },
+ f32x4::from_array([1.0, 1.0, 2.0, -4.0])
+ );
+ assert_eq!(
f32x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(),
f32x4::from_array([0.0, 1.0, 2.0, -4.0])
);
@@ -587,6 +591,10 @@ fn simd_round() {
f64x4::from_array([1.0, 1.0, 2.0, -5.0])
);
assert_eq!(
+ unsafe { intrinsics::simd_round_ties_even(f64x4::from_array([0.9, 1.001, 2.0, -4.5])) },
+ f64x4::from_array([1.0, 1.0, 2.0, -4.0])
+ );
+ assert_eq!(
f64x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(),
f64x4::from_array([0.0, 1.0, 2.0, -4.0])
);
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index 64ce5cc..0dc6e56 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -122,7 +122,12 @@ pub fn dist(env: &Environment, dist_args: &[String]) -> Self {
let metrics_path = env.build_root().join("build").join("metrics.json");
let args = dist_args.iter().map(|arg| arg.as_str()).collect::<Vec<_>>();
let cmd = cmd(&args).env("RUST_BACKTRACE", "full");
- let cmd = add_shared_x_flags(env, cmd);
+ let mut cmd = add_shared_x_flags(env, cmd);
+ if env.is_fast_try_build() {
+ // We set build.extended=false for fast try builds, but we still need Cargo
+ cmd = cmd.arg("cargo");
+ }
+
Self { cmd, metrics_path }
}
@@ -189,5 +194,18 @@ pub fn run(self, timer: &mut TimerSection) -> anyhow::Result<()> {
}
fn add_shared_x_flags(env: &Environment, cmd: CmdBuilder) -> CmdBuilder {
- if env.is_fast_try_build() { cmd.arg("--set").arg("rust.deny-warnings=false") } else { cmd }
+ if env.is_fast_try_build() {
+ // Skip things that cannot be skipped through `x ... --skip`
+ cmd.arg("--set")
+ .arg("rust.llvm-bitcode-linker=false")
+ // Skip wasm-component-ld. This also skips cargo, which we need to re-enable for dist
+ .arg("--set")
+ .arg("build.extended=false")
+ .arg("--set")
+ .arg("rust.codegen-backends=['llvm']")
+ .arg("--set")
+ .arg("rust.deny-warnings=false")
+ } else {
+ cmd
+ }
}
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index d2827ec..9c8a663 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -407,13 +407,18 @@ fn main() -> anyhow::Result<()> {
for target in [
"rust-docs",
"rustc-docs",
+ "rustc-dev",
+ "rust-dev",
"rust-docs-json",
"rust-analyzer",
"rustc-src",
+ "extended",
"clippy",
"miri",
"rustfmt",
"gcc",
+ "generate-copyright",
+ "bootstrap",
] {
build_args.extend(["--skip".to_string(), target.to_string()]);
}
diff --git a/src/tools/rustfmt/tests/source/type.rs b/src/tools/rustfmt/tests/source/type.rs
index 7a232f8..213fad7 100644
--- a/src/tools/rustfmt/tests/source/type.rs
+++ b/src/tools/rustfmt/tests/source/type.rs
@@ -142,18 +142,18 @@ fn foo(a: SomeLongComplexType, b: SomeOtherLongComplexType) -> Box<Future<Item =
// Const bound
-trait T: ~ const Super {}
+trait T: [ const ] Super {}
-const fn not_quite_const<S: ~ const T>() -> i32 { <S as T>::CONST }
+const fn not_quite_const<S: [ const ] T>() -> i32 { <S as T>::CONST }
-impl ~ const T {}
+impl const T for U {}
-fn apit(_: impl ~ const T) {}
+fn apit(_: impl [ const ] T) {}
-fn rpit() -> impl ~ const T { S }
+fn rpit() -> impl [ const] T { S }
pub struct Foo<T: Trait>(T);
-impl<T: ~ const Trait> Foo<T> {
+impl<T: [ const] Trait> Foo<T> {
fn new(t: T) -> Self {
Self(t)
}
diff --git a/src/tools/rustfmt/tests/target/type.rs b/src/tools/rustfmt/tests/target/type.rs
index 325adb5..93479f8 100644
--- a/src/tools/rustfmt/tests/target/type.rs
+++ b/src/tools/rustfmt/tests/target/type.rs
@@ -147,22 +147,22 @@ fn foo(
// Const bound
-trait T: ~const Super {}
+trait T: [const] Super {}
-const fn not_quite_const<S: ~const T>() -> i32 {
+const fn not_quite_const<S: [const] T>() -> i32 {
<S as T>::CONST
}
-impl ~const T {}
+impl const T for U {}
-fn apit(_: impl ~const T) {}
+fn apit(_: impl [const] T) {}
-fn rpit() -> impl ~const T {
+fn rpit() -> impl [const] T {
S
}
pub struct Foo<T: Trait>(T);
-impl<T: ~const Trait> Foo<T> {
+impl<T: [const] Trait> Foo<T> {
fn new(t: T) -> Self {
Self(t)
}
diff --git a/src/tools/test-float-parse/src/ui.rs b/src/tools/test-float-parse/src/ui.rs
index 73473eef..1a9ba0d 100644
--- a/src/tools/test-float-parse/src/ui.rs
+++ b/src/tools/test-float-parse/src/ui.rs
@@ -118,7 +118,7 @@ pub fn finish_all(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) ->
match result {
Ok(FinishedAll) => (),
Err(EarlyExit::Timeout) => {
- println!(" exited early; exceded {:?} timeout", cfg.timeout)
+ println!(" exited early; exceeded {:?} timeout", cfg.timeout)
}
Err(EarlyExit::MaxFailures) => {
println!(" exited early; exceeded {:?} max failures", cfg.max_failures)
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 24356c3..4f9af6d 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1368,7 +1368,6 @@
ui/intrinsics/issue-28575.rs
ui/intrinsics/issue-84297-reifying-copy.rs
ui/invalid/issue-114435-layout-type-err.rs
-ui/issue-11881.rs
ui/issue-15924.rs
ui/issue-16822.rs
ui/issues-71798.rs
@@ -3919,7 +3918,6 @@
ui/traits/const-traits/issue-88155.rs
ui/traits/const-traits/issue-92111.rs
ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
-ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
ui/traits/issue-103563.rs
ui/traits/issue-104322.rs
diff --git a/tests/crashes/133808.rs b/tests/crashes/133808.rs
deleted file mode 100644
index 9c6a23d..0000000
--- a/tests/crashes/133808.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: #133808
-
-#![feature(generic_const_exprs, transmutability)]
-
-mod assert {
- use std::mem::TransmuteFrom;
-
- pub fn is_transmutable<Src, Dst>()
- where
- Dst: TransmuteFrom<Src>,
- {
- }
-}
-
-pub fn main() {}
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
index 82f5786..be3de58 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
@@ -1,10 +1,10 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> const-super-trait.rs:7:12
|
LL | trait Bar: ~const Foo {}
| ^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> const-super-trait.rs:7:1
|
LL | trait Bar: ~const Foo {}
@@ -30,7 +30,7 @@
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:7:12
|
LL | trait Bar: ~const Foo {}
@@ -41,7 +41,7 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:9:17
|
LL | const fn foo<T: ~const Bar>(x: &T) {
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
index 8f4c78c..ef764a6 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
@@ -1,16 +1,16 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> const-super-trait.rs:7:12
|
LL | trait Bar: ~const Foo {}
| ^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> const-super-trait.rs:7:1
|
LL | trait Bar: ~const Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:7:12
|
LL | trait Bar: ~const Foo {}
@@ -21,7 +21,7 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:9:17
|
LL | const fn foo<T: ~const Bar>(x: &T) {
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
index b7cd709..a237935 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
@@ -1,10 +1,10 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> const-super-trait.rs:7:12
|
7 | trait Bar: ~const Foo {}
| ^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> const-super-trait.rs:7:1
|
7 | trait Bar: ~const Foo {}
@@ -26,25 +26,25 @@
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:7:12
|
7 | trait Bar: ~const Foo {}
| ^^^^^^ can't be applied to `Foo`
|
-note: `Foo` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> const-super-trait.rs:3:1
|
3 | trait Foo {
| ^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:9:17
|
9 | const fn foo<T: ~const Bar>(x: &T) {
| ^^^^^^ can't be applied to `Bar`
|
-note: `Bar` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> const-super-trait.rs:7:1
|
7 | trait Bar: ~const Foo {}
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
index 4c59d87..2cdeb27 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
@@ -1,10 +1,10 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> const-super-trait.rs:7:12
|
7 | trait Bar: ~const Foo {}
| ^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> const-super-trait.rs:7:1
|
7 | trait Bar: ~const Foo {}
@@ -16,25 +16,25 @@
1 | #![cfg_attr(feature_enabled, feature(const_trait_impl))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:7:12
|
7 | trait Bar: ~const Foo {}
| ^^^^^^ can't be applied to `Foo`
|
-note: `Foo` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> const-super-trait.rs:3:1
|
3 | trait Foo {
| ^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> const-super-trait.rs:9:17
|
9 | const fn foo<T: ~const Bar>(x: &T) {
| ^^^^^^ can't be applied to `Bar`
|
-note: `Bar` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> const-super-trait.rs:7:1
|
7 | trait Bar: ~const Foo {}
diff --git a/tests/run-make/crate-circular-deps-link/a.rs b/tests/run-make/crate-circular-deps-link/a.rs
index 99b2b65..6deb449 100644
--- a/tests/run-make/crate-circular-deps-link/a.rs
+++ b/tests/run-make/crate-circular-deps-link/a.rs
@@ -1,6 +1,7 @@
#![crate_type = "rlib"]
#![feature(lang_items)]
#![feature(panic_unwind)]
+#![feature(rustc_attrs)]
#![no_std]
extern crate panic_unwind;
@@ -10,12 +11,12 @@ pub fn panic_handler(_: &core::panic::PanicInfo) -> ! {
loop {}
}
-#[no_mangle]
+#[rustc_std_internal_symbol]
extern "C" fn __rust_drop_panic() -> ! {
loop {}
}
-#[no_mangle]
+#[rustc_std_internal_symbol]
extern "C" fn __rust_foreign_exception() -> ! {
loop {}
}
diff --git a/tests/run-make/used-proc-macro/dep.rs b/tests/run-make/used-proc-macro/dep.rs
new file mode 100644
index 0000000..9f881d9
--- /dev/null
+++ b/tests/run-make/used-proc-macro/dep.rs
@@ -0,0 +1,4 @@
+#![crate_type = "lib"]
+
+#[used]
+static VERY_IMPORTANT_SYMBOL: u32 = 12345;
diff --git a/tests/run-make/used-proc-macro/proc_macro.rs b/tests/run-make/used-proc-macro/proc_macro.rs
new file mode 100644
index 0000000..af592ea
--- /dev/null
+++ b/tests/run-make/used-proc-macro/proc_macro.rs
@@ -0,0 +1,3 @@
+#![crate_type = "proc-macro"]
+
+extern crate dep as _;
diff --git a/tests/run-make/used-proc-macro/rmake.rs b/tests/run-make/used-proc-macro/rmake.rs
new file mode 100644
index 0000000..58b2760
--- /dev/null
+++ b/tests/run-make/used-proc-macro/rmake.rs
@@ -0,0 +1,18 @@
+// Test that #[used] statics are included in the final dylib for proc-macros too.
+
+//@ ignore-cross-compile
+//@ ignore-windows llvm-readobj --all doesn't show local symbols on Windows
+//@ needs-crate-type: proc-macro
+//@ ignore-musl (FIXME: can't find `-lunwind`)
+
+use run_make_support::{dynamic_lib_name, llvm_readobj, rustc};
+
+fn main() {
+ rustc().input("dep.rs").run();
+ rustc().input("proc_macro.rs").run();
+ llvm_readobj()
+ .input(dynamic_lib_name("proc_macro"))
+ .arg("--all")
+ .run()
+ .assert_stdout_contains("VERY_IMPORTANT_SYMBOL");
+}
diff --git a/tests/rustdoc/constant/const-effect-param.rs b/tests/rustdoc/constant/const-effect-param.rs
index cceb0ad..3dc63fb 100644
--- a/tests/rustdoc/constant/const-effect-param.rs
+++ b/tests/rustdoc/constant/const-effect-param.rs
@@ -11,4 +11,4 @@ pub trait Tr {
//@ has foo/fn.g.html
//@ has - '//pre[@class="rust item-decl"]' 'pub const fn g<T: Tr>()'
/// foo
-pub const fn g<T: ~const Tr>() {}
+pub const fn g<T: [const] Tr>() {}
diff --git a/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs b/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs
index 8a86e3e..e304eff 100644
--- a/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs
+++ b/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs
@@ -1,12 +1,12 @@
-// Test that we do not currently display `~const` in rustdoc
-// as that syntax is currently provisional; `~const Destruct` has
+// Test that we do not currently display `[const]` in rustdoc
+// as that syntax is currently provisional; `[const] Destruct` has
// no effect on stable code so it should be hidden as well.
//
// To future blessers: make sure that `const_trait_impl` is
// stabilized when changing `@!has` to `@has`, and please do
// not remove this test.
//
-// FIXME(const_trait_impl) add `const_trait` to `Fn` so we use `~const`
+// FIXME(const_trait_impl) add `const_trait` to `Fn` so we use `[const]`
// FIXME(const_trait_impl) restore `const_trait` to `Destruct`
#![feature(const_trait_impl)]
#![crate_name = "foo"]
@@ -15,58 +15,58 @@
pub struct S<T>(T);
-//@ !has foo/trait.Tr.html '//pre[@class="rust item-decl"]/code/a[@class="trait"]' '~const'
+//@ !has foo/trait.Tr.html '//pre[@class="rust item-decl"]/code/a[@class="trait"]' '[const]'
//@ has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Fn'
-//@ !has - '//pre[@class="rust item-decl"]/code/span[@class="where"]' '~const'
+//@ !has - '//pre[@class="rust item-decl"]/code/span[@class="where"]' '[const]'
//@ has - '//pre[@class="rust item-decl"]/code/span[@class="where"]' ': Fn'
#[const_trait]
pub trait Tr<T> {
- //@ !has - '//section[@id="method.a"]/h4[@class="code-header"]' '~const'
+ //@ !has - '//section[@id="method.a"]/h4[@class="code-header"]' '[const]'
//@ has - '//section[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn'
- //@ !has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ //@ !has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '[const]'
//@ has - '//section[@id="method.a"]/h4[@class="code-header"]/div[@class="where"]' ': Fn'
- fn a<A: /* ~const */ Fn() /* + ~const Destruct */>()
+ fn a<A: /* [const] */ Fn() /* + [const] Destruct */>()
where
- Option<A>: /* ~const */ Fn() /* + ~const Destruct */,
+ Option<A>: /* [const] */ Fn() /* + [const] Destruct */,
{
}
}
//@ has - '//section[@id="impl-Tr%3CT%3E-for-T"]' ''
-//@ !has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]' '~const'
+//@ !has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]' '[const]'
//@ has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/a[@class="trait"]' 'Fn'
-//@ !has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where"]' '~const'
+//@ !has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where"]' '[const]'
//@ has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/div[@class="where"]' ': Fn'
-impl<T: /* ~const */ Fn() /* + ~const Destruct */> const Tr<T> for T
+impl<T: /* [const] */ Fn() /* + [const] Destruct */> const Tr<T> for T
where
- Option<T>: /* ~const */ Fn() /* + ~const Destruct */,
+ Option<T>: /* [const] */ Fn() /* + [const] Destruct */,
{
- fn a<A: /* ~const */ Fn() /* + ~const Destruct */>()
+ fn a<A: /* [const] */ Fn() /* + [const] Destruct */>()
where
- Option<A>: /* ~const */ Fn() /* + ~const Destruct */,
+ Option<A>: /* [const] */ Fn() /* + [const] Destruct */,
{
}
}
-//@ !has foo/fn.foo.html '//pre[@class="rust item-decl"]/code/a[@class="trait"]' '~const'
+//@ !has foo/fn.foo.html '//pre[@class="rust item-decl"]/code/a[@class="trait"]' '[const]'
//@ has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Fn'
-//@ !has - '//pre[@class="rust item-decl"]/code/div[@class="where"]' '~const'
+//@ !has - '//pre[@class="rust item-decl"]/code/div[@class="where"]' '[const]'
//@ has - '//pre[@class="rust item-decl"]/code/div[@class="where"]' ': Fn'
-pub const fn foo<F: /* ~const */ Fn() /* + ~const Destruct */>()
+pub const fn foo<F: /* [const] */ Fn() /* + [const] Destruct */>()
where
- Option<F>: /* ~const */ Fn() /* + ~const Destruct */,
+ Option<F>: /* [const] */ Fn() /* + [const] Destruct */,
{
F::a()
}
impl<T> S<T> {
- //@ !has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '~const'
+ //@ !has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '[const]'
//@ has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn'
- //@ !has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ //@ !has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '[const]'
//@ has - '//section[@id="method.foo"]/h4[@class="code-header"]/div[@class="where"]' ': Fn'
- pub const fn foo<B, C: /* ~const */ Fn() /* + ~const Destruct */>()
+ pub const fn foo<B, C: /* [const] */ Fn() /* + [const] Destruct */>()
where
- B: /* ~const */ Fn() /* + ~const Destruct */,
+ B: /* [const] */ Fn() /* + [const] Destruct */,
{
B::a()
}
diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.rs b/tests/rustdoc/enum/enum-variant-non_exhaustive.rs
new file mode 100644
index 0000000..ea0234a
--- /dev/null
+++ b/tests/rustdoc/enum/enum-variant-non_exhaustive.rs
@@ -0,0 +1,17 @@
+// regression test for https://github.com/rust-lang/rust/issues/142599
+
+#![crate_name = "foo"]
+
+//@ snapshot type-code 'foo/enum.Type.html' '//pre[@class="rust item-decl"]/code'
+pub enum Type {
+ #[non_exhaustive]
+ // attribute that should not be shown
+ #[warn(unsafe_code)]
+ Variant,
+}
+
+// we would love to use the `following-sibling::` axis
+// (along with an `h2[@id="aliased-type"]` query),
+// but unfortunately python doesn't implement that.
+//@ snapshot type-alias-code 'foo/type.TypeAlias.html' '//pre[@class="rust item-decl"][2]/code'
+pub type TypeAlias = Type;
diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.type-alias-code.html b/tests/rustdoc/enum/enum-variant-non_exhaustive.type-alias-code.html
new file mode 100644
index 0000000..04eea70
--- /dev/null
+++ b/tests/rustdoc/enum/enum-variant-non_exhaustive.type-alias-code.html
@@ -0,0 +1,4 @@
+<code>pub enum TypeAlias {
+ #[non_exhaustive]
+ Variant,
+}</code>
\ No newline at end of file
diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.type-code.html b/tests/rustdoc/enum/enum-variant-non_exhaustive.type-code.html
new file mode 100644
index 0000000..6c8851e
--- /dev/null
+++ b/tests/rustdoc/enum/enum-variant-non_exhaustive.type-code.html
@@ -0,0 +1,4 @@
+<code>pub enum Type {
+ #[non_exhaustive]
+ Variant,
+}</code>
\ No newline at end of file
diff --git a/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs b/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs
index db198e0..d7d7b32 100644
--- a/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs
@@ -4,7 +4,7 @@
#[const_trait]
pub trait Resource {}
-pub const fn load<R: ~const Resource>() -> i32 {
+pub const fn load<R: [const] Resource>() -> i32 {
0
}
diff --git a/tests/rustdoc/intra-doc/deps.rs b/tests/rustdoc/intra-doc/deps.rs
new file mode 100644
index 0000000..fd40b83
--- /dev/null
+++ b/tests/rustdoc/intra-doc/deps.rs
@@ -0,0 +1,23 @@
+// Checks that links to crates are correctly generated and only existing crates
+// have a link generated.
+// Regression test for <https://github.com/rust-lang/rust/issues/137857>.
+
+//@ compile-flags: --document-private-items -Z unstable-options
+//@ compile-flags: --extern-html-root-url=empty=https://empty.example/
+// This one is to ensure that we don't link to any item we see which has
+// an external html root URL unless it actually exists.
+//@ compile-flags: --extern-html-root-url=non_existant=https://non-existant.example/
+//@ aux-build: empty.rs
+
+#![crate_name = "foo"]
+#![expect(rustdoc::broken_intra_doc_links)]
+
+//@ has 'foo/index.html'
+//@ has - '//a[@href="https://empty.example/empty/index.html"]' 'empty'
+// There should only be one intra doc links, we should not link `non_existant`.
+//@ count - '//*[@class="docblock"]//a' 1
+//! [`empty`]
+//!
+//! [`non_existant`]
+
+extern crate empty;
diff --git a/tests/ui/empty-allocation-non-null.rs b/tests/ui/allocator/empty-alloc-nonnull-guarantee.rs
similarity index 66%
rename from tests/ui/empty-allocation-non-null.rs
rename to tests/ui/allocator/empty-alloc-nonnull-guarantee.rs
index 45035a4..f408130 100644
--- a/tests/ui/empty-allocation-non-null.rs
+++ b/tests/ui/allocator/empty-alloc-nonnull-guarantee.rs
@@ -1,3 +1,7 @@
+//! Check that the default global Rust allocator produces non-null Box allocations for ZSTs.
+//!
+//! See https://github.com/rust-lang/rust/issues/11998
+
//@ run-pass
pub fn main() {
diff --git a/tests/ui/associated-types/unconstrained-lifetime-assoc-type.rs b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.rs
new file mode 100644
index 0000000..2c4af7d
--- /dev/null
+++ b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.rs
@@ -0,0 +1,21 @@
+//! Regression test for issue #22077
+//! lifetime parameters must be constrained in associated type definitions
+
+trait Fun {
+ type Output;
+ fn call<'x>(&'x self) -> Self::Output;
+}
+
+struct Holder {
+ x: String,
+}
+
+impl<'a> Fun for Holder {
+ //~^ ERROR E0207
+ type Output = &'a str;
+ fn call<'b>(&'b self) -> &'b str {
+ &self.x[..]
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-unused-rps-in-assoc-type.stderr b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr
similarity index 84%
rename from tests/ui/impl-unused-rps-in-assoc-type.stderr
rename to tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr
index ef61fa4..15d0820 100644
--- a/tests/ui/impl-unused-rps-in-assoc-type.stderr
+++ b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr
@@ -1,5 +1,5 @@
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-rps-in-assoc-type.rs:11:6
+ --> $DIR/unconstrained-lifetime-assoc-type.rs:13:6
|
LL | impl<'a> Fun for Holder {
| ^^ unconstrained lifetime parameter
diff --git a/tests/ui/async-await/issues/issue-95307.rs b/tests/ui/async-await/issues/issue-95307.rs
index 83df656..40905c2 100644
--- a/tests/ui/async-await/issues/issue-95307.rs
+++ b/tests/ui/async-await/issues/issue-95307.rs
@@ -5,7 +5,10 @@
pub trait C {
async fn new() -> [u8; _];
- //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions
+ //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for opaque types
+ //~| ERROR: the placeholder `_` is not allowed within types on item signatures for opaque types
+ //~| ERROR: the placeholder `_` is not allowed within types on item signatures for opaque types
+ //~| ERROR: the placeholder `_` is not allowed within types on item signatures for opaque types
}
fn main() {}
diff --git a/tests/ui/async-await/issues/issue-95307.stderr b/tests/ui/async-await/issues/issue-95307.stderr
index c670686..0aae7a2 100644
--- a/tests/ui/async-await/issues/issue-95307.stderr
+++ b/tests/ui/async-await/issues/issue-95307.stderr
@@ -1,9 +1,33 @@
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
--> $DIR/issue-95307.rs:7:28
|
LL | async fn new() -> [u8; _];
| ^ not allowed in type signatures
-error: aborting due to 1 previous error
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+ --> $DIR/issue-95307.rs:7:28
+ |
+LL | async fn new() -> [u8; _];
+ | ^ not allowed in type signatures
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+ --> $DIR/issue-95307.rs:7:28
+ |
+LL | async fn new() -> [u8; _];
+ | ^ not allowed in type signatures
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+ --> $DIR/issue-95307.rs:7:28
+ |
+LL | async fn new() -> [u8; _];
+ | ^ not allowed in type signatures
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/attributes/inline-attribute-enum-variant-error.rs b/tests/ui/attributes/inline-attribute-enum-variant-error.rs
new file mode 100644
index 0000000..305b285
--- /dev/null
+++ b/tests/ui/attributes/inline-attribute-enum-variant-error.rs
@@ -0,0 +1,9 @@
+//! Test that #[inline] attribute cannot be applied to enum variants
+
+enum Foo {
+ #[inline]
+ //~^ ERROR attribute should be applied
+ Variant,
+}
+
+fn main() {}
diff --git a/tests/ui/inline-disallow-on-variant.stderr b/tests/ui/attributes/inline-attribute-enum-variant-error.stderr
similarity index 83%
rename from tests/ui/inline-disallow-on-variant.stderr
rename to tests/ui/attributes/inline-attribute-enum-variant-error.stderr
index 255f6bc..a4564d8 100644
--- a/tests/ui/inline-disallow-on-variant.stderr
+++ b/tests/ui/attributes/inline-attribute-enum-variant-error.stderr
@@ -1,5 +1,5 @@
error[E0518]: attribute should be applied to function or closure
- --> $DIR/inline-disallow-on-variant.rs:2:5
+ --> $DIR/inline-attribute-enum-variant-error.rs:4:5
|
LL | #[inline]
| ^^^^^^^^^
diff --git a/tests/ui/attributes/inline-main.rs b/tests/ui/attributes/inline-main.rs
new file mode 100644
index 0000000..7181ee1
--- /dev/null
+++ b/tests/ui/attributes/inline-main.rs
@@ -0,0 +1,6 @@
+//! Test that #[inline(always)] can be applied to main function
+
+//@ run-pass
+
+#[inline(always)]
+fn main() {}
diff --git a/tests/ui/attributes/inner-attrs-impl-cfg.rs b/tests/ui/attributes/inner-attrs-impl-cfg.rs
new file mode 100644
index 0000000..e7a5cfa
--- /dev/null
+++ b/tests/ui/attributes/inner-attrs-impl-cfg.rs
@@ -0,0 +1,36 @@
+//! Test inner attributes (#![...]) behavior in impl blocks with cfg conditions.
+//!
+//! This test verifies that:
+//! - Inner attributes can conditionally exclude entire impl blocks
+//! - Regular attributes within impl blocks work independently
+//! - Attribute parsing doesn't consume too eagerly
+
+//@ run-pass
+
+struct Foo;
+
+impl Foo {
+ #![cfg(false)]
+
+ fn method(&self) -> bool {
+ false
+ }
+}
+
+impl Foo {
+ #![cfg(not(FALSE))]
+
+ // Check that we don't eat attributes too eagerly.
+ #[cfg(false)]
+ fn method(&self) -> bool {
+ false
+ }
+
+ fn method(&self) -> bool {
+ true
+ }
+}
+
+pub fn main() {
+ assert!(Foo.method());
+}
diff --git a/tests/ui/attributes/used_with_arg.rs b/tests/ui/attributes/used_with_arg.rs
index ad80ff5..bc7a6f0 100644
--- a/tests/ui/attributes/used_with_arg.rs
+++ b/tests/ui/attributes/used_with_arg.rs
@@ -1,3 +1,4 @@
+#![deny(unused_attributes)]
#![feature(used_with_arg)]
#[used(linker)]
@@ -6,14 +7,22 @@
#[used(compiler)]
static mut USED_COMPILER: [usize; 1] = [0];
-#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
+#[used(compiler)]
#[used(linker)]
static mut USED_COMPILER_LINKER2: [usize; 1] = [0];
-#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
-#[used(linker)]
#[used(compiler)]
#[used(linker)]
+#[used(compiler)] //~ ERROR unused attribute
+#[used(linker)] //~ ERROR unused attribute
static mut USED_COMPILER_LINKER3: [usize; 1] = [0];
+#[used(compiler)]
+#[used]
+static mut USED_WITHOUT_ATTR1: [usize; 1] = [0];
+
+#[used(linker)]
+#[used] //~ ERROR unused attribute
+static mut USED_WITHOUT_ATTR2: [usize; 1] = [0];
+
fn main() {}
diff --git a/tests/ui/attributes/used_with_arg.stderr b/tests/ui/attributes/used_with_arg.stderr
index 440e5c4..9ff91a4 100644
--- a/tests/ui/attributes/used_with_arg.stderr
+++ b/tests/ui/attributes/used_with_arg.stderr
@@ -1,18 +1,43 @@
-error: `used(compiler)` and `used(linker)` can't be used together
- --> $DIR/used_with_arg.rs:9:1
+error: unused attribute
+ --> $DIR/used_with_arg.rs:16:1
+ |
+LL | #[used(compiler)]
+ | ^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/used_with_arg.rs:14:1
|
LL | #[used(compiler)]
| ^^^^^^^^^^^^^^^^^
-LL | #[used(linker)]
- | ^^^^^^^^^^^^^^^
-
-error: `used(compiler)` and `used(linker)` can't be used together
- --> $DIR/used_with_arg.rs:13:1
+note: the lint level is defined here
+ --> $DIR/used_with_arg.rs:1:9
|
-LL | #[used(compiler)]
- | ^^^^^^^^^^^^^^^^^
+LL | #![deny(unused_attributes)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: unused attribute
+ --> $DIR/used_with_arg.rs:17:1
+ |
+LL | #[used(linker)]
+ | ^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/used_with_arg.rs:15:1
+ |
LL | #[used(linker)]
| ^^^^^^^^^^^^^^^
-error: aborting due to 2 previous errors
+error: unused attribute
+ --> $DIR/used_with_arg.rs:25:1
+ |
+LL | #[used]
+ | ^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/used_with_arg.rs:24:1
+ |
+LL | #[used(linker)]
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
diff --git a/tests/ui/attributes/used_with_multi_args.rs b/tests/ui/attributes/used_with_multi_args.rs
index d3109cc..1c054f7 100644
--- a/tests/ui/attributes/used_with_multi_args.rs
+++ b/tests/ui/attributes/used_with_multi_args.rs
@@ -1,6 +1,6 @@
#![feature(used_with_arg)]
-#[used(compiler, linker)] //~ ERROR expected `used`, `used(compiler)` or `used(linker)`
+#[used(compiler, linker)] //~ ERROR malformed `used` attribute input
static mut USED_COMPILER_LINKER: [usize; 1] = [0];
fn main() {}
diff --git a/tests/ui/attributes/used_with_multi_args.stderr b/tests/ui/attributes/used_with_multi_args.stderr
index d4417a2..e48209c 100644
--- a/tests/ui/attributes/used_with_multi_args.stderr
+++ b/tests/ui/attributes/used_with_multi_args.stderr
@@ -1,8 +1,20 @@
-error: expected `used`, `used(compiler)` or `used(linker)`
+error[E0805]: malformed `used` attribute input
--> $DIR/used_with_multi_args.rs:3:1
|
LL | #[used(compiler, linker)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^------------------^
+ | |
+ | expected a single argument here
+ |
+help: try changing it to one of the following valid forms of the attribute
+ |
+LL - #[used(compiler, linker)]
+LL + #[used(compiler|linker)]
+ |
+LL - #[used(compiler, linker)]
+LL + #[used]
+ |
error: aborting due to 1 previous error
+For more information about this error, try `rustc --explain E0805`.
diff --git a/tests/ui/const-generics/const_trait_fn-issue-88433.rs b/tests/ui/const-generics/const_trait_fn-issue-88433.rs
index bc91fc1..2f92a52 100644
--- a/tests/ui/const-generics/const_trait_fn-issue-88433.rs
+++ b/tests/ui/const-generics/const_trait_fn-issue-88433.rs
@@ -10,7 +10,6 @@ trait Func<T> {
fn call_once(self, arg: T) -> Self::Output;
}
-
struct Closure;
impl const Func<&usize> for Closure {
@@ -21,7 +20,7 @@ fn call_once(self, arg: &usize) -> Self::Output {
}
}
-enum Bug<T = [(); Closure.call_once(&0) ]> {
+enum Bug<T = [(); Closure.call_once(&0)]> {
V(T),
}
diff --git a/tests/ui/const-generics/generic_arg_infer/in-signature.rs b/tests/ui/const-generics/generic_arg_infer/in-signature.rs
index cd0235b..1be8b56 100644
--- a/tests/ui/const-generics/generic_arg_infer/in-signature.rs
+++ b/tests/ui/const-generics/generic_arg_infer/in-signature.rs
@@ -41,6 +41,7 @@ trait TyAssocConst {
trait TyAssocConstMixed {
const ARR: Bar<_, _>;
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated constants
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for associated constants
}
trait AssocTy {
@@ -57,4 +58,5 @@ impl AssocTy for i16 {
impl AssocTy for i32 {
type Assoc = Bar<_, _>;
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for associated types
}
diff --git a/tests/ui/const-generics/generic_arg_infer/in-signature.stderr b/tests/ui/const-generics/generic_arg_infer/in-signature.stderr
index f964fc8..b6f2662 100644
--- a/tests/ui/const-generics/generic_arg_infer/in-signature.stderr
+++ b/tests/ui/const-generics/generic_arg_infer/in-signature.stderr
@@ -103,24 +103,28 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
- --> $DIR/in-signature.rs:50:23
+ --> $DIR/in-signature.rs:51:23
|
LL | type Assoc = [u8; _];
| ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
- --> $DIR/in-signature.rs:54:27
+ --> $DIR/in-signature.rs:55:27
|
LL | type Assoc = Bar<i32, _>;
| ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
- --> $DIR/in-signature.rs:58:22
+ --> $DIR/in-signature.rs:59:22
|
LL | type Assoc = Bar<_, _>;
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+ --> $DIR/in-signature.rs:59:25
+ |
+LL | type Assoc = Bar<_, _>;
+ | ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
--> $DIR/in-signature.rs:34:21
@@ -138,10 +142,14 @@
--> $DIR/in-signature.rs:42:20
|
LL | const ARR: Bar<_, _>;
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
+ | ^ not allowed in type signatures
-error: aborting due to 15 previous errors
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
+ --> $DIR/in-signature.rs:42:23
+ |
+LL | const ARR: Bar<_, _>;
+ | ^ not allowed in type signatures
+
+error: aborting due to 17 previous errors
For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/const-generics/generic_const_exprs/non-local-const.rs b/tests/ui/const-generics/generic_const_exprs/non-local-const.rs
new file mode 100644
index 0000000..0a30cc3
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/non-local-const.rs
@@ -0,0 +1,10 @@
+// regression test for #133808.
+
+#![feature(generic_const_exprs)]
+#![feature(min_generic_const_args)]
+#![allow(incomplete_features)]
+#![crate_type = "lib"]
+
+pub trait Foo {}
+impl Foo for [u8; std::path::MAIN_SEPARATOR] {}
+//~^ ERROR the constant `MAIN_SEPARATOR` is not of type `usize`
diff --git a/tests/ui/const-generics/generic_const_exprs/non-local-const.stderr b/tests/ui/const-generics/generic_const_exprs/non-local-const.stderr
new file mode 100644
index 0000000..d8df326
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/non-local-const.stderr
@@ -0,0 +1,10 @@
+error: the constant `MAIN_SEPARATOR` is not of type `usize`
+ --> $DIR/non-local-const.rs:9:14
+ |
+LL | impl Foo for [u8; std::path::MAIN_SEPARATOR] {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `char`
+ |
+ = note: the length of array `[u8; MAIN_SEPARATOR]` must be type `usize`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr
index 94f06bb..0aabf48 100644
--- a/tests/ui/const-generics/issues/issue-88119.stderr
+++ b/tests/ui/const-generics/issues/issue-88119.stderr
@@ -6,7 +6,7 @@
|
= help: remove one of these features
-error[E0275]: overflow evaluating the requirement `&T: ~const ConstName`
+error[E0275]: overflow evaluating the requirement `&T: [const] ConstName`
--> $DIR/issue-88119.rs:19:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &T
@@ -42,7 +42,7 @@
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
-error[E0275]: overflow evaluating the requirement `&mut T: ~const ConstName`
+error[E0275]: overflow evaluating the requirement `&mut T: [const] ConstName`
--> $DIR/issue-88119.rs:26:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
diff --git a/tests/ui/consts/const-block-const-bound.rs b/tests/ui/consts/const-block-const-bound.rs
index b4b89a9..1847c88 100644
--- a/tests/ui/consts/const-block-const-bound.rs
+++ b/tests/ui/consts/const-block-const-bound.rs
@@ -3,7 +3,7 @@
use std::marker::Destruct;
-const fn f<T: ~const Destruct>(x: T) {}
+const fn f<T: [const] Destruct>(x: T) {}
struct UnconstDrop;
diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr
index 624772f..b6c8027 100644
--- a/tests/ui/consts/const-block-const-bound.stderr
+++ b/tests/ui/consts/const-block-const-bound.stderr
@@ -9,8 +9,8 @@
note: required by a bound in `f`
--> $DIR/const-block-const-bound.rs:6:15
|
-LL | const fn f<T: ~const Destruct>(x: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `f`
+LL | const fn f<T: [const] Destruct>(x: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `f`
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const-mut-refs/issue-76510.rs b/tests/ui/consts/const-mut-refs/issue-76510.rs
index 3b248d7..a6f7540 100644
--- a/tests/ui/consts/const-mut-refs/issue-76510.rs
+++ b/tests/ui/consts/const-mut-refs/issue-76510.rs
@@ -1,7 +1,7 @@
use std::mem::{transmute, ManuallyDrop};
const S: &'static mut str = &mut " hello ";
-//~^ ERROR: mutable borrows of lifetime-extended temporaries
+//~^ ERROR: mutable borrows of temporaries
const fn trigger() -> [(); unsafe {
let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr
index 6d5dac2..3a6c951 100644
--- a/tests/ui/consts/const-mut-refs/issue-76510.stderr
+++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr
@@ -1,8 +1,12 @@
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/issue-76510.rs:3:29
|
LL | const S: &'static mut str = &mut " hello ";
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs
index 2af92bd..9f9384a 100644
--- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs
+++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs
@@ -12,13 +12,13 @@
// It could be made sound to allow it to compile,
// but we do not want to allow this to compile,
// as that would be an enormous footgun in oli-obk's opinion.
-const B: *mut i32 = &mut 4; //~ ERROR mutable borrows of lifetime-extended temporaries
+const B: *mut i32 = &mut 4; //~ ERROR mutable borrows of temporaries
// Ok, no actual mutable allocation exists
const B2: Option<&mut i32> = None;
// Not ok, can't prove that no mutable allocation ends up in final value
-const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR mutable borrows of lifetime-extended temporaries
+const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR mutable borrows of temporaries
const fn helper(x: &mut i32) -> Option<&mut i32> { Some(x) }
const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed
@@ -69,13 +69,13 @@ unsafe impl<T> Sync for SyncPtr<T> {}
// (This relies on `SyncPtr` being a curly brace struct.)
// However, we intern the inner memory as read-only, so this must be rejected.
static RAW_MUT_CAST_S: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
-//~^ ERROR mutable borrows of lifetime-extended temporaries
+//~^ ERROR mutable borrows of temporaries
static RAW_MUT_COERCE_S: SyncPtr<i32> = SyncPtr { x: &mut 0 };
-//~^ ERROR mutable borrows of lifetime-extended temporaries
+//~^ ERROR mutable borrows of temporaries
const RAW_MUT_CAST_C: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
-//~^ ERROR mutable borrows of lifetime-extended temporaries
+//~^ ERROR mutable borrows of temporaries
const RAW_MUT_COERCE_C: SyncPtr<i32> = SyncPtr { x: &mut 0 };
-//~^ ERROR mutable borrows of lifetime-extended temporaries
+//~^ ERROR mutable borrows of temporaries
fn main() {
println!("{}", unsafe { *A });
diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr
index a55ccf7..16dee44 100644
--- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr
+++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr
@@ -1,14 +1,22 @@
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/mut_ref_in_final.rs:15:21
|
LL | const B: *mut i32 = &mut 4;
- | ^^^^^^
+ | ^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/mut_ref_in_final.rs:21:35
|
LL | const B3: Option<&mut i32> = Some(&mut 42);
- | ^^^^^^^
+ | ^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error[E0716]: temporary value dropped while borrowed
--> $DIR/mut_ref_in_final.rs:24:42
@@ -72,29 +80,45 @@
| | creates a temporary value which is freed while still in use
| using this value as a static requires that borrow lasts for `'static`
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/mut_ref_in_final.rs:71:53
|
LL | static RAW_MUT_CAST_S: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
- | ^^^^^^^
+ | ^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/mut_ref_in_final.rs:73:54
|
LL | static RAW_MUT_COERCE_S: SyncPtr<i32> = SyncPtr { x: &mut 0 };
- | ^^^^^^
+ | ^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/mut_ref_in_final.rs:75:52
|
LL | const RAW_MUT_CAST_C: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
- | ^^^^^^^
+ | ^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/mut_ref_in_final.rs:77:53
|
LL | const RAW_MUT_COERCE_C: SyncPtr<i32> = SyncPtr { x: &mut 0 };
- | ^^^^^^
+ | ^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 12 previous errors
diff --git a/tests/ui/consts/const-promoted-opaque.atomic.stderr b/tests/ui/consts/const-promoted-opaque.atomic.stderr
index 337bfa4..64cc7b3 100644
--- a/tests/ui/consts/const-promoted-opaque.atomic.stderr
+++ b/tests/ui/consts/const-promoted-opaque.atomic.stderr
@@ -7,11 +7,15 @@
LL | };
| - value is dropped here
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/const-promoted-opaque.rs:36:19
|
LL | const BAZ: &Foo = &FOO;
- | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error[E0716]: temporary value dropped while borrowed
--> $DIR/const-promoted-opaque.rs:40:26
diff --git a/tests/ui/consts/const-promoted-opaque.rs b/tests/ui/consts/const-promoted-opaque.rs
index 9ad2b10..270dddb 100644
--- a/tests/ui/consts/const-promoted-opaque.rs
+++ b/tests/ui/consts/const-promoted-opaque.rs
@@ -34,7 +34,7 @@ const fn foo() -> Foo {}
};
const BAZ: &Foo = &FOO;
-//[atomic]~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries
+//[atomic]~^ ERROR: interior mutable shared borrows of temporaries
fn main() {
let _: &'static _ = &FOO;
diff --git a/tests/ui/consts/constifconst-call-in-const-position.rs b/tests/ui/consts/constifconst-call-in-const-position.rs
index 80e47c2..da29030 100644
--- a/tests/ui/consts/constifconst-call-in-const-position.rs
+++ b/tests/ui/consts/constifconst-call-in-const-position.rs
@@ -14,7 +14,7 @@ fn a() -> usize {
}
}
-const fn foo<T: ~const Tr>() -> [u8; T::a()] {
+const fn foo<T: [const] Tr>() -> [u8; T::a()] {
[0; T::a()]
}
diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr
index c778299..e84e686 100644
--- a/tests/ui/consts/constifconst-call-in-const-position.stderr
+++ b/tests/ui/consts/constifconst-call-in-const-position.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: const Tr` is not satisfied
- --> $DIR/constifconst-call-in-const-position.rs:17:38
+ --> $DIR/constifconst-call-in-const-position.rs:17:39
|
-LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
- | ^
+LL | const fn foo<T: [const] Tr>() -> [u8; T::a()] {
+ | ^
error[E0277]: the trait bound `T: const Tr` is not satisfied
--> $DIR/constifconst-call-in-const-position.rs:18:9
diff --git a/tests/ui/consts/fn_trait_refs.rs b/tests/ui/consts/fn_trait_refs.rs
index af233ef..e475c0a 100644
--- a/tests/ui/consts/fn_trait_refs.rs
+++ b/tests/ui/consts/fn_trait_refs.rs
@@ -11,47 +11,47 @@
const fn tester_fn<T>(f: T) -> T::Output
where
- T: ~const Fn<()> + ~const Destruct,
+ T: [const] Fn<()> + [const] Destruct,
{
f()
}
const fn tester_fn_mut<T>(mut f: T) -> T::Output
where
- T: ~const FnMut<()> + ~const Destruct,
+ T: [const] FnMut<()> + [const] Destruct,
{
f()
}
const fn tester_fn_once<T>(f: T) -> T::Output
where
- T: ~const FnOnce<()>,
+ T: [const] FnOnce<()>,
{
f()
}
const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
where
- T: ~const Fn<()> + ~const Destruct,
+ T: [const] Fn<()> + [const] Destruct,
{
(
- // impl<A: Tuple, F: ~const Fn + ?Sized> const Fn<A> for &F
+ // impl<A: Tuple, F: [const] Fn + ?Sized> const Fn<A> for &F
tester_fn(&f),
- // impl<A: Tuple, F: ~const Fn + ?Sized> const FnMut<A> for &F
+ // impl<A: Tuple, F: [const] Fn + ?Sized> const FnMut<A> for &F
tester_fn_mut(&f),
- // impl<A: Tuple, F: ~const Fn + ?Sized> const FnOnce<A> for &F
+ // impl<A: Tuple, F: [const] Fn + ?Sized> const FnOnce<A> for &F
tester_fn_once(&f),
)
}
const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
where
- T: ~const FnMut<()> + ~const Destruct,
+ T: [const] FnMut<()> + [const] Destruct,
{
(
- // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnMut<A> for &mut F
+ // impl<A: Tuple, F: [const] FnMut + ?Sized> const FnMut<A> for &mut F
tester_fn_mut(&mut f),
- // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnOnce<A> for &mut F
+ // impl<A: Tuple, F: [const] FnMut + ?Sized> const FnOnce<A> for &mut F
tester_fn_once(&mut f),
)
}
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index 7dc0804..445dd75 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -4,148 +4,148 @@
LL | #![feature(const_fn_trait_ref_impls)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:14:8
|
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `Fn`
+LL | T: [const] Fn<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:14:8
|
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `Fn`
+LL | T: [const] Fn<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:14:8
|
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `Fn`
+LL | T: [const] Fn<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:21:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `FnMut`
+LL | T: [const] FnMut<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:21:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `FnMut`
+LL | T: [const] FnMut<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:21:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `FnMut`
+LL | T: [const] FnMut<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:28:8
|
-LL | T: ~const FnOnce<()>,
- | ^^^^^^ can't be applied to `FnOnce`
+LL | T: [const] FnOnce<()>,
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:28:8
|
-LL | T: ~const FnOnce<()>,
- | ^^^^^^ can't be applied to `FnOnce`
+LL | T: [const] FnOnce<()>,
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:28:8
|
-LL | T: ~const FnOnce<()>,
- | ^^^^^^ can't be applied to `FnOnce`
+LL | T: [const] FnOnce<()>,
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:35:8
|
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `Fn`
+LL | T: [const] Fn<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:35:8
|
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `Fn`
+LL | T: [const] Fn<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:35:8
|
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `Fn`
+LL | T: [const] Fn<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:49:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `FnMut`
+LL | T: [const] FnMut<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:49:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `FnMut`
+LL | T: [const] FnMut<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:49:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^ can't be applied to `FnMut`
+LL | T: [const] FnMut<()> + [const] Destruct,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs
index ae101927..a447350 100644
--- a/tests/ui/consts/issue-17718-const-bad-values.rs
+++ b/tests/ui/consts/issue-17718-const-bad-values.rs
@@ -5,7 +5,7 @@
#![allow(static_mut_refs)]
const C1: &'static mut [usize] = &mut [];
-//~^ ERROR: mutable borrows of lifetime-extended temporaries
+//~^ ERROR: mutable borrows of temporaries
static mut S: i32 = 3;
const C2: &'static mut i32 = unsafe { &mut S };
diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr
index f0b02bd..68d1a72 100644
--- a/tests/ui/consts/issue-17718-const-bad-values.stderr
+++ b/tests/ui/consts/issue-17718-const-bad-values.stderr
@@ -1,8 +1,12 @@
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/issue-17718-const-bad-values.rs:7:34
|
LL | const C1: &'static mut [usize] = &mut [];
- | ^^^^^^^
+ | ^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error[E0080]: constructing invalid value: encountered mutable reference in `const` value
--> $DIR/issue-17718-const-bad-values.rs:11:1
diff --git a/tests/ui/consts/issue-17718-const-borrow.rs b/tests/ui/consts/issue-17718-const-borrow.rs
index 541d279..6373333 100644
--- a/tests/ui/consts/issue-17718-const-borrow.rs
+++ b/tests/ui/consts/issue-17718-const-borrow.rs
@@ -2,13 +2,13 @@
const A: UnsafeCell<usize> = UnsafeCell::new(1);
const B: &'static UnsafeCell<usize> = &A;
-//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries
+//~^ ERROR: interior mutable shared borrows of temporaries
struct C { a: UnsafeCell<usize> }
const D: C = C { a: UnsafeCell::new(1) };
const E: &'static UnsafeCell<usize> = &D.a;
-//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries
+//~^ ERROR: interior mutable shared borrows of temporaries
const F: &'static C = &D;
-//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries
+//~^ ERROR: interior mutable shared borrows of temporaries
fn main() {}
diff --git a/tests/ui/consts/issue-17718-const-borrow.stderr b/tests/ui/consts/issue-17718-const-borrow.stderr
index 962a81e..420a2c3 100644
--- a/tests/ui/consts/issue-17718-const-borrow.stderr
+++ b/tests/ui/consts/issue-17718-const-borrow.stderr
@@ -1,20 +1,32 @@
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/issue-17718-const-borrow.rs:4:39
|
LL | const B: &'static UnsafeCell<usize> = &A;
- | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/issue-17718-const-borrow.rs:9:39
|
LL | const E: &'static UnsafeCell<usize> = &D.a;
- | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/issue-17718-const-borrow.rs:11:23
|
LL | const F: &'static C = &D;
- | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr
index e5b32e0..367d5be 100644
--- a/tests/ui/consts/issue-73976-monomorphic.stderr
+++ b/tests/ui/consts/issue-73976-monomorphic.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `TypeId: ~const PartialEq` is not satisfied
+error[E0277]: the trait bound `TypeId: [const] PartialEq` is not satisfied
--> $DIR/issue-73976-monomorphic.rs:21:5
|
LL | GetTypeId::<T>::VALUE == GetTypeId::<usize>::VALUE
diff --git a/tests/ui/consts/normalize-before-const-arg-has-type-goal.rs b/tests/ui/consts/normalize-before-const-arg-has-type-goal.rs
new file mode 100644
index 0000000..9caa3c9
--- /dev/null
+++ b/tests/ui/consts/normalize-before-const-arg-has-type-goal.rs
@@ -0,0 +1,19 @@
+trait A<const B: bool> {}
+
+// vv- Let's call this const "UNEVALUATED" for the comment below.
+impl A<{}> for () {}
+//~^ ERROR mismatched types
+
+// During overlap check, we end up trying to prove `(): A<?0c>`. Inference guides
+// `?0c = UNEVALUATED` (which is the `{}` const in the erroneous impl). We then
+// fail to prove `ConstArgHasType<UNEVALUATED, u8>` since `UNEVALUATED` has the
+// type `bool` from the type_of query. We then deeply normalize the predicate for
+// error reporting, which ends up normalizing `UNEVALUATED` to a ConstKind::Error.
+// This ended up ICEing when trying to report an error for the `ConstArgHasType`
+// predicate, since we don't expect `ConstArgHasType(ERROR, Ty)` to ever fail.
+
+trait C<const D: u8> {}
+impl<const D: u8> C<D> for () where (): A<D> {}
+impl<const D: u8> C<D> for () {}
+
+fn main() {}
diff --git a/tests/ui/consts/normalize-before-const-arg-has-type-goal.stderr b/tests/ui/consts/normalize-before-const-arg-has-type-goal.stderr
new file mode 100644
index 0000000..a532318
--- /dev/null
+++ b/tests/ui/consts/normalize-before-const-arg-has-type-goal.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+ --> $DIR/normalize-before-const-arg-has-type-goal.rs:4:8
+ |
+LL | impl A<{}> for () {}
+ | ^^ expected `bool`, found `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/consts/partial_qualif.rs b/tests/ui/consts/partial_qualif.rs
index 6770e13..18438cc 100644
--- a/tests/ui/consts/partial_qualif.rs
+++ b/tests/ui/consts/partial_qualif.rs
@@ -3,7 +3,7 @@
const FOO: &(Cell<usize>, bool) = {
let mut a = (Cell::new(0), false);
a.1 = true; // sets `qualif(a)` to `qualif(a) | qualif(true)`
- &{a} //~ ERROR interior mutable shared borrows of lifetime-extended temporaries
+ &{a} //~ ERROR interior mutable shared borrows of temporaries
};
fn main() {}
diff --git a/tests/ui/consts/partial_qualif.stderr b/tests/ui/consts/partial_qualif.stderr
index eb1a388..b7632eb 100644
--- a/tests/ui/consts/partial_qualif.stderr
+++ b/tests/ui/consts/partial_qualif.stderr
@@ -1,8 +1,12 @@
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/partial_qualif.rs:6:5
|
LL | &{a}
- | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/qualif_overwrite.rs b/tests/ui/consts/qualif_overwrite.rs
index 3b494ca..93310b3 100644
--- a/tests/ui/consts/qualif_overwrite.rs
+++ b/tests/ui/consts/qualif_overwrite.rs
@@ -7,7 +7,7 @@
const FOO: &Option<Cell<usize>> = {
let mut a = Some(Cell::new(0));
a = None; // sets `qualif(a)` to `qualif(a) | qualif(None)`
- &{a} //~ ERROR interior mutable shared borrows of lifetime-extended temporaries
+ &{a} //~ ERROR interior mutable shared borrows of temporaries
};
fn main() {}
diff --git a/tests/ui/consts/qualif_overwrite.stderr b/tests/ui/consts/qualif_overwrite.stderr
index 92430a8..4aaaa4b 100644
--- a/tests/ui/consts/qualif_overwrite.stderr
+++ b/tests/ui/consts/qualif_overwrite.stderr
@@ -1,8 +1,12 @@
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/qualif_overwrite.rs:10:5
|
LL | &{a}
- | ^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/qualif_overwrite_2.rs b/tests/ui/consts/qualif_overwrite_2.rs
index e06fd32..e739790 100644
--- a/tests/ui/consts/qualif_overwrite_2.rs
+++ b/tests/ui/consts/qualif_overwrite_2.rs
@@ -5,7 +5,7 @@
const FOO: &Option<Cell<usize>> = {
let mut a = (Some(Cell::new(0)),);
a.0 = None; // sets `qualif(a)` to `qualif(a) | qualif(None)`
- &{a.0} //~ ERROR interior mutable shared borrows of lifetime-extended temporaries
+ &{a.0} //~ ERROR interior mutable shared borrows of temporaries
};
fn main() {}
diff --git a/tests/ui/consts/qualif_overwrite_2.stderr b/tests/ui/consts/qualif_overwrite_2.stderr
index a994ab6..bc16814 100644
--- a/tests/ui/consts/qualif_overwrite_2.stderr
+++ b/tests/ui/consts/qualif_overwrite_2.stderr
@@ -1,8 +1,12 @@
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/qualif_overwrite_2.rs:8:5
|
LL | &{a.0}
- | ^^^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^^^^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/recursive-static-write.rs b/tests/ui/consts/recursive-static-write.rs
new file mode 100644
index 0000000..dc5813d
--- /dev/null
+++ b/tests/ui/consts/recursive-static-write.rs
@@ -0,0 +1,24 @@
+//! Ensure that writing to `S` while initializing `S` errors.
+//! Regression test for <https://github.com/rust-lang/rust/issues/142404>.
+#![allow(dead_code)]
+
+struct Foo {
+ x: i32,
+ y: (),
+}
+
+static S: Foo = Foo {
+ x: 0,
+ y: unsafe {
+ (&raw const S.x).cast_mut().write(1); //~ERROR access itself during initialization
+ },
+};
+
+static mut S2: Foo = Foo {
+ x: 0,
+ y: unsafe {
+ S2.x = 1; //~ERROR access itself during initialization
+ },
+};
+
+fn main() {}
diff --git a/tests/ui/consts/recursive-static-write.stderr b/tests/ui/consts/recursive-static-write.stderr
new file mode 100644
index 0000000..f5b5c49
--- /dev/null
+++ b/tests/ui/consts/recursive-static-write.stderr
@@ -0,0 +1,15 @@
+error[E0080]: encountered static that tried to access itself during initialization
+ --> $DIR/recursive-static-write.rs:13:9
+ |
+LL | (&raw const S.x).cast_mut().write(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `S` failed here
+
+error[E0080]: encountered static that tried to access itself during initialization
+ --> $DIR/recursive-static-write.rs:20:9
+ |
+LL | S2.x = 1;
+ | ^^^^^^^^ evaluation of `S2` failed here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr
index fee33a8..c814576 100644
--- a/tests/ui/consts/recursive-zst-static.default.stderr
+++ b/tests/ui/consts/recursive-zst-static.default.stderr
@@ -1,20 +1,20 @@
-error[E0080]: encountered static that tried to initialize itself with itself
+error[E0080]: encountered static that tried to access itself during initialization
--> $DIR/recursive-zst-static.rs:10:18
|
LL | static FOO: () = FOO;
| ^^^ evaluation of `FOO` failed here
error[E0391]: cycle detected when evaluating initializer of static `A`
- --> $DIR/recursive-zst-static.rs:13:16
+ --> $DIR/recursive-zst-static.rs:13:1
|
LL | static A: () = B;
- | ^
+ | ^^^^^^^^^^^^
|
note: ...which requires evaluating initializer of static `B`...
- --> $DIR/recursive-zst-static.rs:14:16
+ --> $DIR/recursive-zst-static.rs:14:1
|
LL | static B: () = A;
- | ^
+ | ^^^^^^^^^^^^
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
= note: cycle used when running analysis passes on this crate
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
diff --git a/tests/ui/consts/recursive-zst-static.rs b/tests/ui/consts/recursive-zst-static.rs
index 852caae..853af6d 100644
--- a/tests/ui/consts/recursive-zst-static.rs
+++ b/tests/ui/consts/recursive-zst-static.rs
@@ -8,7 +8,7 @@
// See https://github.com/rust-lang/rust/issues/71078 for more details.
static FOO: () = FOO;
-//~^ ERROR encountered static that tried to initialize itself with itself
+//~^ ERROR encountered static that tried to access itself during initialization
static A: () = B; //~ ERROR cycle detected when evaluating initializer of static `A`
static B: () = A;
diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr
index fee33a8..c814576 100644
--- a/tests/ui/consts/recursive-zst-static.unleash.stderr
+++ b/tests/ui/consts/recursive-zst-static.unleash.stderr
@@ -1,20 +1,20 @@
-error[E0080]: encountered static that tried to initialize itself with itself
+error[E0080]: encountered static that tried to access itself during initialization
--> $DIR/recursive-zst-static.rs:10:18
|
LL | static FOO: () = FOO;
| ^^^ evaluation of `FOO` failed here
error[E0391]: cycle detected when evaluating initializer of static `A`
- --> $DIR/recursive-zst-static.rs:13:16
+ --> $DIR/recursive-zst-static.rs:13:1
|
LL | static A: () = B;
- | ^
+ | ^^^^^^^^^^^^
|
note: ...which requires evaluating initializer of static `B`...
- --> $DIR/recursive-zst-static.rs:14:16
+ --> $DIR/recursive-zst-static.rs:14:1
|
LL | static B: () = A;
- | ^
+ | ^^^^^^^^^^^^
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
= note: cycle used when running analysis passes on this crate
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
diff --git a/tests/ui/consts/refs-to-cell-in-final.rs b/tests/ui/consts/refs-to-cell-in-final.rs
index 28a26f8..2bd0623 100644
--- a/tests/ui/consts/refs-to-cell-in-final.rs
+++ b/tests/ui/consts/refs-to-cell-in-final.rs
@@ -11,9 +11,9 @@ unsafe impl<T> Sync for SyncPtr<T> {}
// The resulting constant would pass all validation checks, so it is crucial that this gets rejected
// by static const checks!
static RAW_SYNC_S: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
-//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries
+//~^ ERROR: interior mutable shared borrows of temporaries
const RAW_SYNC_C: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
-//~^ ERROR: interior mutable shared borrows of lifetime-extended temporaries
+//~^ ERROR: interior mutable shared borrows of temporaries
// This one does not get promoted because of `Drop`, and then enters interesting codepaths because
// as a value it has no interior mutability, but as a type it does. See
@@ -39,7 +39,7 @@ fn drop(&mut self) {}
// Not okay, since we are borrowing something with interior mutability.
const INTERIOR_MUT_VARIANT: &Option<UnsafeCell<bool>> = &{
- //~^ERROR: interior mutable shared borrows of lifetime-extended temporaries
+ //~^ERROR: interior mutable shared borrows of temporaries
let mut x = None;
assert!(x.is_none());
x = Some(UnsafeCell::new(false));
diff --git a/tests/ui/consts/refs-to-cell-in-final.stderr b/tests/ui/consts/refs-to-cell-in-final.stderr
index 41f7a23..ac866db 100644
--- a/tests/ui/consts/refs-to-cell-in-final.stderr
+++ b/tests/ui/consts/refs-to-cell-in-final.stderr
@@ -1,18 +1,24 @@
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/refs-to-cell-in-final.rs:13:54
|
LL | static RAW_SYNC_S: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
- | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary
|
- = help: to fix this, the value can be extracted to a separate `static` item and then referenced
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/refs-to-cell-in-final.rs:15:53
|
LL | const RAW_SYNC_C: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
- | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/refs-to-cell-in-final.rs:41:57
|
LL | const INTERIOR_MUT_VARIANT: &Option<UnsafeCell<bool>> = &{
@@ -23,7 +29,11 @@
LL | | x = Some(UnsafeCell::new(false));
LL | | x
LL | | };
- | |_^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | |_^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/unsafe_cell_in_const.rs b/tests/ui/consts/unsafe_cell_in_const.rs
new file mode 100644
index 0000000..b867ae1
--- /dev/null
+++ b/tests/ui/consts/unsafe_cell_in_const.rs
@@ -0,0 +1,15 @@
+//! Ensure we do not complain about zero-sized `UnsafeCell` in a const in any form.
+//! See <https://github.com/rust-lang/rust/issues/142948>.
+
+//@ check-pass
+use std::cell::UnsafeCell;
+
+const X1: &mut UnsafeCell<[i32; 0]> = UnsafeCell::from_mut(&mut []);
+
+const X2: &mut UnsafeCell<[i32]> = UnsafeCell::from_mut(&mut []);
+
+trait Trait {}
+impl Trait for [i32; 0] {}
+const X3: &mut UnsafeCell<dyn Trait> = UnsafeCell::from_mut(&mut []);
+
+fn main() {}
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.rs b/tests/ui/consts/unstable-const-fn-in-libcore.rs
index baeece4..f4b4c68 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.rs
@@ -16,7 +16,7 @@ enum Opt<T> {
impl<T> Opt<T> {
#[rustc_const_unstable(feature = "foo", issue = "none")]
#[stable(feature = "rust1", since = "1.0.0")]
- const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
+ const fn unwrap_or_else<F: [const] FnOnce() -> T>(self, f: F) -> T {
//FIXME ~^ ERROR destructor of
//FIXME ~| ERROR destructor of
match self {
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index 32693ed..95e48b7 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/unstable-const-fn-in-libcore.rs:19:32
|
-LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
- | ^^^^^^ can't be applied to `FnOnce`
+LL | const fn unwrap_or_else<F: [const] FnOnce() -> T>(self, f: F) -> T {
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/unstable-const-fn-in-libcore.rs:19:32
|
-LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
- | ^^^^^^ can't be applied to `FnOnce`
+LL | const fn unwrap_or_else<F: [const] FnOnce() -> T>(self, f: F) -> T {
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -26,19 +26,19 @@
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error[E0493]: destructor of `F` cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:19:60
+ --> $DIR/unstable-const-fn-in-libcore.rs:19:61
|
-LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
- | ^ the destructor for this type cannot be evaluated in constant functions
+LL | const fn unwrap_or_else<F: [const] FnOnce() -> T>(self, f: F) -> T {
+ | ^ the destructor for this type cannot be evaluated in constant functions
...
LL | }
| - value is dropped here
error[E0493]: destructor of `Opt<T>` cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:19:54
+ --> $DIR/unstable-const-fn-in-libcore.rs:19:55
|
-LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
- | ^^^^ the destructor for this type cannot be evaluated in constant functions
+LL | const fn unwrap_or_else<F: [const] FnOnce() -> T>(self, f: F) -> T {
+ | ^^^^ the destructor for this type cannot be evaluated in constant functions
...
LL | }
| - value is dropped here
diff --git a/tests/ui/consts/write-to-static-mut-in-static.rs b/tests/ui/consts/write-to-static-mut-in-static.rs
index ce15d9e..016bfb0 100644
--- a/tests/ui/consts/write-to-static-mut-in-static.rs
+++ b/tests/ui/consts/write-to-static-mut-in-static.rs
@@ -3,8 +3,9 @@
//~^ ERROR modifying a static's initial value
pub static mut C: u32 = unsafe { C = 1; 0 };
+//~^ ERROR static that tried to access itself during initialization
pub static D: u32 = D;
-//~^ ERROR static that tried to initialize itself with itself
+//~^ ERROR static that tried to access itself during initialization
fn main() {}
diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr
index bb5e217..4180bb4 100644
--- a/tests/ui/consts/write-to-static-mut-in-static.stderr
+++ b/tests/ui/consts/write-to-static-mut-in-static.stderr
@@ -4,12 +4,18 @@
LL | pub static mut B: () = unsafe { A = 1; };
| ^^^^^ evaluation of `B` failed here
-error[E0080]: encountered static that tried to initialize itself with itself
- --> $DIR/write-to-static-mut-in-static.rs:7:21
+error[E0080]: encountered static that tried to access itself during initialization
+ --> $DIR/write-to-static-mut-in-static.rs:5:34
+ |
+LL | pub static mut C: u32 = unsafe { C = 1; 0 };
+ | ^^^^^ evaluation of `C` failed here
+
+error[E0080]: encountered static that tried to access itself during initialization
+ --> $DIR/write-to-static-mut-in-static.rs:8:21
|
LL | pub static D: u32 = D;
| ^ evaluation of `D` failed here
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/write_to_static_via_mut_ref.rs b/tests/ui/consts/write_to_static_via_mut_ref.rs
index 6d3ddf0..dc8a7ee 100644
--- a/tests/ui/consts/write_to_static_via_mut_ref.rs
+++ b/tests/ui/consts/write_to_static_via_mut_ref.rs
@@ -1,4 +1,4 @@
-static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable borrows of lifetime-extended temporaries
+static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable borrows of temporaries
fn main() {
assert_eq!(*OH_NO, 42);
*OH_NO = 43; //~ ERROR cannot assign to `*OH_NO`, as `OH_NO` is an immutable static
diff --git a/tests/ui/consts/write_to_static_via_mut_ref.stderr b/tests/ui/consts/write_to_static_via_mut_ref.stderr
index 76926e6..1bcd7b8 100644
--- a/tests/ui/consts/write_to_static_via_mut_ref.stderr
+++ b/tests/ui/consts/write_to_static_via_mut_ref.stderr
@@ -1,8 +1,12 @@
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/write_to_static_via_mut_ref.rs:1:26
|
LL | static OH_NO: &mut i32 = &mut 42;
- | ^^^^^^^
+ | ^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error[E0594]: cannot assign to `*OH_NO`, as `OH_NO` is an immutable static item
--> $DIR/write_to_static_via_mut_ref.rs:4:5
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr b/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
index 0835f76..fe1ce5a 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
@@ -240,96 +240,52 @@
--> $DIR/bad-assoc-ty.rs:56:13
|
LL | fn foo<X: K<_, _>>(x: X) {}
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
+ | ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:59:34
+ --> $DIR/bad-assoc-ty.rs:56:16
+ |
+LL | fn foo<X: K<_, _>>(x: X) {}
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/bad-assoc-ty.rs:60:34
|
LL | fn bar<F>(_: F) where F: Fn() -> _ {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn bar<F>(_: F) where F: Fn() -> _ {}
-LL + fn bar<F, T>(_: F) where F: Fn() -> T {}
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:62:19
+ --> $DIR/bad-assoc-ty.rs:63:19
|
LL | fn baz<F: Fn() -> _>(_: F) {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn baz<F: Fn() -> _>(_: F) {}
-LL + fn baz<F: Fn() -> T, T>(_: F) {}
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:65:33
+ --> $DIR/bad-assoc-ty.rs:66:33
|
LL | struct L<F>(F) where F: Fn() -> _;
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - struct L<F>(F) where F: Fn() -> _;
-LL + struct L<F, T>(F) where F: Fn() -> T;
- |
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:87:38
- |
-LL | fn foo<F>(_: F) where F: Fn() -> _ {}
- | ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn foo<F>(_: F) where F: Fn() -> _ {}
-LL + fn foo<F, T>(_: F) where F: Fn() -> T {}
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:67:30
+ --> $DIR/bad-assoc-ty.rs:68:30
|
LL | struct M<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - struct M<F> where F: Fn() -> _ {
-LL + struct M<F, T> where F: Fn() -> T {
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for enums
- --> $DIR/bad-assoc-ty.rs:71:28
+ --> $DIR/bad-assoc-ty.rs:72:28
|
LL | enum N<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - enum N<F> where F: Fn() -> _ {
-LL + enum N<F, T> where F: Fn() -> T {
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for unions
- --> $DIR/bad-assoc-ty.rs:76:29
+ --> $DIR/bad-assoc-ty.rs:77:29
|
LL | union O<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - union O<F> where F: Fn() -> _ {
-LL + union O<F, T> where F: Fn() -> T {
- |
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
- --> $DIR/bad-assoc-ty.rs:78:5
+ --> $DIR/bad-assoc-ty.rs:79:5
|
LL | foo: F,
| ^^^^^^
@@ -341,18 +297,18 @@
| +++++++++++++++++++++++ +
error[E0121]: the placeholder `_` is not allowed within types on item signatures for traits
- --> $DIR/bad-assoc-ty.rs:82:29
+ --> $DIR/bad-assoc-ty.rs:83:29
|
LL | trait P<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - trait P<F> where F: Fn() -> _ {
-LL + trait P<F, T> where F: Fn() -> T {
- |
-error: aborting due to 29 previous errors; 1 warning emitted
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/bad-assoc-ty.rs:88:38
+ |
+LL | fn foo<F>(_: F) where F: Fn() -> _ {}
+ | ^ not allowed in type signatures
+
+error: aborting due to 30 previous errors; 1 warning emitted
Some errors have detailed explanations: E0121, E0223, E0740.
For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.edition2021.stderr b/tests/ui/did_you_mean/bad-assoc-ty.edition2021.stderr
index 3cc403f..2cf7a15 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.edition2021.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.edition2021.stderr
@@ -222,96 +222,52 @@
--> $DIR/bad-assoc-ty.rs:56:13
|
LL | fn foo<X: K<_, _>>(x: X) {}
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
+ | ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:59:34
+ --> $DIR/bad-assoc-ty.rs:56:16
+ |
+LL | fn foo<X: K<_, _>>(x: X) {}
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/bad-assoc-ty.rs:60:34
|
LL | fn bar<F>(_: F) where F: Fn() -> _ {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn bar<F>(_: F) where F: Fn() -> _ {}
-LL + fn bar<F, T>(_: F) where F: Fn() -> T {}
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:62:19
+ --> $DIR/bad-assoc-ty.rs:63:19
|
LL | fn baz<F: Fn() -> _>(_: F) {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn baz<F: Fn() -> _>(_: F) {}
-LL + fn baz<F: Fn() -> T, T>(_: F) {}
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:65:33
+ --> $DIR/bad-assoc-ty.rs:66:33
|
LL | struct L<F>(F) where F: Fn() -> _;
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - struct L<F>(F) where F: Fn() -> _;
-LL + struct L<F, T>(F) where F: Fn() -> T;
- |
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:87:38
- |
-LL | fn foo<F>(_: F) where F: Fn() -> _ {}
- | ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn foo<F>(_: F) where F: Fn() -> _ {}
-LL + fn foo<F, T>(_: F) where F: Fn() -> T {}
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:67:30
+ --> $DIR/bad-assoc-ty.rs:68:30
|
LL | struct M<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - struct M<F> where F: Fn() -> _ {
-LL + struct M<F, T> where F: Fn() -> T {
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for enums
- --> $DIR/bad-assoc-ty.rs:71:28
+ --> $DIR/bad-assoc-ty.rs:72:28
|
LL | enum N<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - enum N<F> where F: Fn() -> _ {
-LL + enum N<F, T> where F: Fn() -> T {
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for unions
- --> $DIR/bad-assoc-ty.rs:76:29
+ --> $DIR/bad-assoc-ty.rs:77:29
|
LL | union O<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - union O<F> where F: Fn() -> _ {
-LL + union O<F, T> where F: Fn() -> T {
- |
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
- --> $DIR/bad-assoc-ty.rs:78:5
+ --> $DIR/bad-assoc-ty.rs:79:5
|
LL | foo: F,
| ^^^^^^
@@ -323,18 +279,18 @@
| +++++++++++++++++++++++ +
error[E0121]: the placeholder `_` is not allowed within types on item signatures for traits
- --> $DIR/bad-assoc-ty.rs:82:29
+ --> $DIR/bad-assoc-ty.rs:83:29
|
LL | trait P<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - trait P<F> where F: Fn() -> _ {
-LL + trait P<F, T> where F: Fn() -> T {
- |
-error: aborting due to 29 previous errors
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/bad-assoc-ty.rs:88:38
+ |
+LL | fn foo<F>(_: F) where F: Fn() -> _ {}
+ | ^ not allowed in type signatures
+
+error: aborting due to 30 previous errors
Some errors have detailed explanations: E0121, E0223, E0740, E0782.
For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.rs b/tests/ui/did_you_mean/bad-assoc-ty.rs
index 6e56cba..9abda4f 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.rs
+++ b/tests/ui/did_you_mean/bad-assoc-ty.rs
@@ -55,6 +55,7 @@ macro_rules! ty {
trait K<A, B> {}
fn foo<X: K<_, _>>(x: X) {}
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn bar<F>(_: F) where F: Fn() -> _ {}
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
diff --git a/tests/ui/diverging-fn-tail-35849.rs b/tests/ui/diverging-fn-tail-35849.rs
deleted file mode 100644
index f21ce29..0000000
--- a/tests/ui/diverging-fn-tail-35849.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-fn assert_sizeof() -> ! {
- unsafe {
- ::std::mem::transmute::<f64, [u8; 8]>(panic!())
- //~^ ERROR mismatched types
- }
-}
-
-fn main() { }
diff --git a/tests/ui/early-ret-binop-add.rs b/tests/ui/early-ret-binop-add.rs
deleted file mode 100644
index 3fec66f..0000000
--- a/tests/ui/early-ret-binop-add.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-
-#![allow(dead_code)]
-#![allow(unreachable_code)]
-
-use std::ops::Add;
-
-fn wsucc<T:Add<Output=T> + Copy>(n: T) -> T { n + { return n } }
-
-pub fn main() { }
diff --git a/tests/ui/elide-errors-on-mismatched-tuple.rs b/tests/ui/elide-errors-on-mismatched-tuple.rs
deleted file mode 100644
index 7d87b0a..0000000
--- a/tests/ui/elide-errors-on-mismatched-tuple.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Hide irrelevant E0277 errors (#50333)
-
-trait T {}
-
-struct A;
-impl T for A {}
-impl A {
- fn new() -> Self {
- Self {}
- }
-}
-
-fn main() {
- let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three
- //~^ ERROR mismatched types
- let ts: Vec<&dyn T> = vec![&a, &b, &c];
- // There is no E0277 error above, as `a`, `b` and `c` are `TyErr`
-}
diff --git a/tests/ui/elided-test.rs b/tests/ui/elided-test.rs
deleted file mode 100644
index 2bedc25..0000000
--- a/tests/ui/elided-test.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// Since we're not compiling a test runner this function should be elided
-// and the build will fail because main doesn't exist
-#[test]
-fn main() {
-} //~ ERROR `main` function not found in crate `elided_test`
diff --git a/tests/ui/elided-test.stderr b/tests/ui/elided-test.stderr
deleted file mode 100644
index 7aebe5d..0000000
--- a/tests/ui/elided-test.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0601]: `main` function not found in crate `elided_test`
- --> $DIR/elided-test.rs:5:2
- |
-LL | }
- | ^ consider adding a `main` function to `$DIR/elided-test.rs`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/else-if.rs b/tests/ui/else-if.rs
deleted file mode 100644
index 2161b28..0000000
--- a/tests/ui/else-if.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ run-pass
-
-pub fn main() {
- if 1 == 2 {
- assert!((false));
- } else if 2 == 3 {
- assert!((false));
- } else if 3 == 4 { assert!((false)); } else { assert!((true)); }
- if 1 == 2 { assert!((false)); } else if 2 == 2 { assert!((true)); }
- if 1 == 2 {
- assert!((false));
- } else if 2 == 2 {
- if 1 == 1 {
- assert!((true));
- } else { if 2 == 1 { assert!((false)); } else { assert!((false)); } }
- }
- if 1 == 2 {
- assert!((false));
- } else { if 1 == 2 { assert!((false)); } else { assert!((true)); } }
-}
diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs
index 52b81c8..0f00dda 100644
--- a/tests/ui/error-codes/E0017.rs
+++ b/tests/ui/error-codes/E0017.rs
@@ -5,12 +5,12 @@
const C: i32 = 2;
static mut M: i32 = 3;
-const CR: &'static mut i32 = &mut C; //~ ERROR mutable borrows of lifetime-extended temporaries
+const CR: &'static mut i32 = &mut C; //~ ERROR mutable borrows of temporaries
//~| WARN taking a mutable
static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow immutable static item `X` as mutable
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable borrows of lifetime-extended temporaries
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable borrows of temporaries
//~| WARN taking a mutable
fn main() {}
diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr
index b1a94ca..2039e55 100644
--- a/tests/ui/error-codes/E0017.stderr
+++ b/tests/ui/error-codes/E0017.stderr
@@ -13,11 +13,15 @@
| ^^^^^^^^^^^^
= note: `#[warn(const_item_mutation)]` on by default
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/E0017.rs:8:30
|
LL | const CR: &'static mut i32 = &mut C;
- | ^^^^^^
+ | ^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error[E0596]: cannot borrow immutable static item `X` as mutable
--> $DIR/E0017.rs:11:39
@@ -39,11 +43,15 @@
LL | const C: i32 = 2;
| ^^^^^^^^^^^^
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/E0017.rs:13:38
|
LL | static CONST_REF: &'static mut i32 = &mut C;
- | ^^^^^^
+ | ^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 3 previous errors; 2 warnings emitted
diff --git a/tests/ui/error-codes/E0492.stderr b/tests/ui/error-codes/E0492.stderr
index fbbcf8f..43a3a87 100644
--- a/tests/ui/error-codes/E0492.stderr
+++ b/tests/ui/error-codes/E0492.stderr
@@ -1,16 +1,22 @@
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a constant are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/E0492.rs:4:33
|
LL | const B: &'static AtomicUsize = &A;
- | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^ this borrow of an interior mutable value refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
-error[E0492]: interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/E0492.rs:5:34
|
LL | static C: &'static AtomicUsize = &A;
- | ^^ this borrow of an interior mutable value refers to a lifetime-extended temporary
+ | ^^ this borrow of an interior mutable value refers to such a temporary
|
- = help: to fix this, the value can be extracted to a separate `static` item and then referenced
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 2 previous errors
diff --git a/tests/ui/expr/early-return-in-binop.rs b/tests/ui/expr/early-return-in-binop.rs
new file mode 100644
index 0000000..389d252
--- /dev/null
+++ b/tests/ui/expr/early-return-in-binop.rs
@@ -0,0 +1,19 @@
+//! Test early return within binary operation expressions
+
+//@ run-pass
+
+#![allow(dead_code)]
+#![allow(unreachable_code)]
+
+use std::ops::Add;
+
+/// Function that performs addition with an early return in the right operand
+fn add_with_early_return<T: Add<Output = T> + Copy>(n: T) -> T {
+ n + { return n }
+}
+
+pub fn main() {
+ // Test with different numeric types to ensure generic behavior works
+ let _result1 = add_with_early_return(42i32);
+ let _result2 = add_with_early_return(3.14f64);
+}
diff --git a/tests/ui/extern/issue-47725.rs b/tests/ui/extern/issue-47725.rs
index 9ec55be..012673b 100644
--- a/tests/ui/extern/issue-47725.rs
+++ b/tests/ui/extern/issue-47725.rs
@@ -17,12 +17,9 @@
#[link_name]
//~^ ERROR malformed `link_name` attribute input
//~| HELP must be of the form
-//~| WARN attribute should be applied to a foreign function or static [unused_attributes]
-//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-//~| HELP try `#[link(name = "...")]` instead
+//~| NOTE expected this to be of the form `link_name = "..."
extern "C" {
fn bar() -> u32;
}
-//~^^^ NOTE not a foreign function or static
fn main() {}
diff --git a/tests/ui/extern/issue-47725.stderr b/tests/ui/extern/issue-47725.stderr
index 0d3b77b..53d6b49 100644
--- a/tests/ui/extern/issue-47725.stderr
+++ b/tests/ui/extern/issue-47725.stderr
@@ -1,8 +1,11 @@
-error: malformed `link_name` attribute input
+error[E0539]: malformed `link_name` attribute input
--> $DIR/issue-47725.rs:17:1
|
LL | #[link_name]
- | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]`
+ | ^^^^^^^^^^^^
+ | |
+ | expected this to be of the form `link_name = "..."`
+ | help: must be of the form: `#[link_name = "name"]`
warning: attribute should be applied to a foreign function or static
--> $DIR/issue-47725.rs:3:1
@@ -38,23 +41,6 @@
LL | #[link_name = "foobar"]
| ^^^^^^^^^^^^^^^^^^^^^^^
-warning: attribute should be applied to a foreign function or static
- --> $DIR/issue-47725.rs:17:1
- |
-LL | #[link_name]
- | ^^^^^^^^^^^^
-...
-LL | / extern "C" {
-LL | | fn bar() -> u32;
-LL | | }
- | |_- not a foreign function or static
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-help: try `#[link(name = "...")]` instead
- --> $DIR/issue-47725.rs:17:1
- |
-LL | #[link_name]
- | ^^^^^^^^^^^^
+error: aborting due to 1 previous error; 2 warnings emitted
-error: aborting due to 1 previous error; 3 warnings emitted
-
+For more information about this error, try `rustc --explain E0539`.
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 d2b1d71..1243ed5 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
@@ -387,14 +387,6 @@
|
= 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 a foreign function or static
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1
- |
-LL | #![link_name = "1900"]
- | ^^^^^^^^^^^^^^^^^^^^^^ not a foreign function or static
- |
- = 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 a function or static
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
|
@@ -411,6 +403,14 @@
|
= 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 a foreign function or static
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1
+ |
+LL | #![link_name = "1900"]
+ | ^^^^^^^^^^^^^^^^^^^^^^ not a foreign function or static
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
warning: `#[must_use]` has no effect when applied to a module
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1
|
diff --git a/tests/ui/fn/error-recovery-mismatch.stderr b/tests/ui/fn/error-recovery-mismatch.stderr
index f281e77..c046302 100644
--- a/tests/ui/fn/error-recovery-mismatch.stderr
+++ b/tests/ui/fn/error-recovery-mismatch.stderr
@@ -34,12 +34,6 @@
|
LL | fn fold<T>(&self, _: T, &self._) {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn fold<T>(&self, _: T, &self._) {}
-LL + fn fold<T, U>(&self, _: T, &self.U) {}
- |
error: aborting due to 4 previous errors; 1 warning emitted
diff --git a/tests/ui/generics/overlapping-errors-span-issue-123861.stderr b/tests/ui/generics/overlapping-errors-span-issue-123861.stderr
index 9622dff..7d08d8f 100644
--- a/tests/ui/generics/overlapping-errors-span-issue-123861.stderr
+++ b/tests/ui/generics/overlapping-errors-span-issue-123861.stderr
@@ -30,12 +30,6 @@
|
LL | fn mainIterator<_ = _> {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn mainIterator<_ = _> {}
-LL + fn mainIterator<T = T> {}
- |
error: aborting due to 4 previous errors
diff --git a/tests/ui/generics/unconstrained-type-params-inherent-impl.rs b/tests/ui/generics/unconstrained-type-params-inherent-impl.rs
new file mode 100644
index 0000000..c971de0
--- /dev/null
+++ b/tests/ui/generics/unconstrained-type-params-inherent-impl.rs
@@ -0,0 +1,32 @@
+//! Test for unconstrained type parameters in inherent implementations
+
+struct MyType;
+
+struct MyType1<T>(T);
+
+trait Bar {
+ type Out;
+}
+
+impl<T> MyType {
+ //~^ ERROR the type parameter `T` is not constrained
+ // T is completely unused - this should fail
+}
+
+impl<T> MyType1<T> {
+ // OK: T is used in the self type `MyType1<T>`
+}
+
+impl<T, U> MyType1<T> {
+ //~^ ERROR the type parameter `U` is not constrained
+ // T is used in self type, but U is unconstrained - this should fail
+}
+
+impl<T, U> MyType1<T>
+where
+ T: Bar<Out = U>,
+{
+ // OK: T is used in self type, U is constrained through the where clause
+}
+
+fn main() {}
diff --git a/tests/ui/impl-unused-tps-inherent.stderr b/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr
similarity index 66%
rename from tests/ui/impl-unused-tps-inherent.stderr
rename to tests/ui/generics/unconstrained-type-params-inherent-impl.stderr
index 43f63cf..19b02ad 100644
--- a/tests/ui/impl-unused-tps-inherent.stderr
+++ b/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr
@@ -1,14 +1,14 @@
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps-inherent.rs:9:6
+ --> $DIR/unconstrained-type-params-inherent-impl.rs:11:6
|
LL | impl<T> MyType {
| ^ unconstrained type parameter
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps-inherent.rs:17:8
+ --> $DIR/unconstrained-type-params-inherent-impl.rs:20:9
|
-LL | impl<T,U> MyType1<T> {
- | ^ unconstrained type parameter
+LL | impl<T, U> MyType1<T> {
+ | ^ unconstrained type parameter
error: aborting due to 2 previous errors
diff --git a/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr
index 07f029d..c08fc51 100644
--- a/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr
+++ b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^^^ cannot infer type of the type parameter `F` declared on the method `publish_typed`
|
= note: cannot satisfy `_: Clone`
- = note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
+ = note: opaque types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
note: required by a bound in `TypedClient::publish_typed::{anon_assoc#0}`
--> $DIR/not-inferred-generic.rs:4:12
|
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs
index a735ef7..0c7969c 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.rs
+++ b/tests/ui/impl-trait/normalize-tait-in-const.rs
@@ -24,7 +24,7 @@ pub const fn filter_positive<'a>() -> &'a Alias<'a> {
}
use foo::*;
-const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
+const fn with_positive<F: for<'a> [const] Fn(&'a Alias<'a>) + [const] Destruct>(fun: F) {
fun(filter_positive());
}
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index 2b6825b..e17737d 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/normalize-tait-in-const.rs:27:35
|
-LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn with_positive<F: for<'a> [const] Fn(&'a Alias<'a>) + [const] Destruct>(fun: F) {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/normalize-tait-in-const.rs:27:35
|
-LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn with_positive<F: for<'a> [const] Fn(&'a Alias<'a>) + [const] Destruct>(fun: F) {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/impl-unused-rps-in-assoc-type.rs b/tests/ui/impl-unused-rps-in-assoc-type.rs
deleted file mode 100644
index ea41997..0000000
--- a/tests/ui/impl-unused-rps-in-assoc-type.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Test that lifetime parameters must be constrained if they appear in
-// an associated type def'n. Issue #22077.
-
-trait Fun {
- type Output;
- fn call<'x>(&'x self) -> Self::Output;
-}
-
-struct Holder { x: String }
-
-impl<'a> Fun for Holder { //~ ERROR E0207
- type Output = &'a str;
- fn call<'b>(&'b self) -> &'b str {
- &self.x[..]
- }
-}
-
-fn main() { }
diff --git a/tests/ui/impl-unused-tps-inherent.rs b/tests/ui/impl-unused-tps-inherent.rs
deleted file mode 100644
index 83a228e..0000000
--- a/tests/ui/impl-unused-tps-inherent.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-struct MyType;
-
-struct MyType1<T>(T);
-
-trait Bar {
- type Out;
-}
-
-impl<T> MyType {
- //~^ ERROR the type parameter `T` is not constrained
-}
-
-impl<T> MyType1<T> {
- // OK, T is used in `Foo<T>`.
-}
-
-impl<T,U> MyType1<T> {
- //~^ ERROR the type parameter `U` is not constrained
-}
-
-impl<T,U> MyType1<T> where T: Bar<Out=U> {
- // OK, T is used in `Foo<T>`.
-}
-
-fn main() { }
diff --git a/tests/ui/impl-unused-tps.rs b/tests/ui/impl-unused-tps.rs
deleted file mode 100644
index a5836db..0000000
--- a/tests/ui/impl-unused-tps.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-trait Foo<A> {
- fn get(&self, A: &A) {}
-}
-
-trait Bar {
- type Out;
-}
-
-impl<T> Foo<T> for [isize; 0] {
- // OK, T is used in `Foo<T>`.
-}
-
-impl<T, U> Foo<T> for [isize; 1] {
- //~^ ERROR the type parameter `U` is not constrained
-}
-
-impl<T, U> Foo<T> for [isize; 2]
-where
- T: Bar<Out = U>,
-{
- // OK, `U` is now constrained by the output type parameter.
-}
-
-impl<T: Bar<Out = U>, U> Foo<T> for [isize; 3] {
- // OK, same as above but written differently.
-}
-
-impl<T, U> Foo<T> for U {
- //~^ ERROR conflicting implementations of trait `Foo<_>` for type `[isize; 0]`
-}
-
-impl<T, U> Bar for T {
- //~^ ERROR the type parameter `U` is not constrained
-
- type Out = U;
-
- // Using `U` in an associated type within the impl is not good enough!
-}
-
-impl<T, U> Bar for T
-where
- T: Bar<Out = U>,
-{
- //~^^^^ ERROR the type parameter `U` is not constrained by the impl trait, self type, or predicates
- //~| ERROR conflicting implementations of trait `Bar`
- // This crafty self-referential attempt is still no good.
-}
-
-impl<T, U, V> Foo<T> for T
-where
- (T, U): Bar<Out = V>,
-{
- //~^^^^ ERROR the type parameter `U` is not constrained
- //~| ERROR the type parameter `V` is not constrained
- //~| ERROR conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]`
-
- // Here, `V` is bound by an output type parameter, but the inputs
- // are not themselves constrained.
-}
-
-impl<T, U, V> Foo<(T, U)> for T
-where
- (T, U): Bar<Out = V>,
-{
- //~^^^^ ERROR conflicting implementations of trait `Foo<([isize; 0], _)>` for type `[isize; 0]`
- // As above, but both T and U ARE constrained.
-}
-
-fn main() {}
diff --git a/tests/ui/implicit-method-bind.rs b/tests/ui/implicit-method-bind.rs
deleted file mode 100644
index 5e27516..0000000
--- a/tests/ui/implicit-method-bind.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
- let _f = 10i32.abs; //~ ERROR attempted to take value of method
-}
diff --git a/tests/ui/implicit-method-bind.stderr b/tests/ui/implicit-method-bind.stderr
deleted file mode 100644
index e935711..0000000
--- a/tests/ui/implicit-method-bind.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0615]: attempted to take value of method `abs` on type `i32`
- --> $DIR/implicit-method-bind.rs:2:20
- |
-LL | let _f = 10i32.abs;
- | ^^^ method, not a field
- |
-help: use parentheses to call the method
- |
-LL | let _f = 10i32.abs();
- | ++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0615`.
diff --git a/tests/ui/double-type-import.rs b/tests/ui/imports/duplicate-use-bindings.rs
similarity index 72%
rename from tests/ui/double-type-import.rs
rename to tests/ui/imports/duplicate-use-bindings.rs
index 6b1eb65..8cec23e 100644
--- a/tests/ui/double-type-import.rs
+++ b/tests/ui/imports/duplicate-use-bindings.rs
@@ -1,3 +1,5 @@
+//! Test that duplicate use bindings in same namespace produce error
+
mod foo {
pub use self::bar::X;
use self::bar::X;
diff --git a/tests/ui/double-type-import.stderr b/tests/ui/imports/duplicate-use-bindings.stderr
similarity index 90%
rename from tests/ui/double-type-import.stderr
rename to tests/ui/imports/duplicate-use-bindings.stderr
index 8a8fe05..1d4f1fc 100644
--- a/tests/ui/double-type-import.stderr
+++ b/tests/ui/imports/duplicate-use-bindings.stderr
@@ -1,5 +1,5 @@
error[E0252]: the name `X` is defined multiple times
- --> $DIR/double-type-import.rs:3:9
+ --> $DIR/duplicate-use-bindings.rs:5:9
|
LL | pub use self::bar::X;
| ------------ previous import of the type `X` here
diff --git a/tests/ui/indexing/indexing-integral-types.rs b/tests/ui/indexing/indexing-integral-types.rs
new file mode 100644
index 0000000..a91696a
--- /dev/null
+++ b/tests/ui/indexing/indexing-integral-types.rs
@@ -0,0 +1,20 @@
+//! Test that only usize can be used for indexing arrays and slices.
+
+pub fn main() {
+ let v: Vec<isize> = vec![0, 1, 2, 3, 4, 5];
+ let s: String = "abcdef".to_string();
+
+ // Valid indexing with usize
+ v[3_usize];
+ v[3];
+ v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8`
+ v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8`
+ v[3u32]; //~ ERROR the type `[isize]` cannot be indexed by `u32`
+ v[3i32]; //~ ERROR the type `[isize]` cannot be indexed by `i32`
+ s.as_bytes()[3_usize];
+ s.as_bytes()[3];
+ s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8`
+ s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8`
+ s.as_bytes()[3u32]; //~ ERROR the type `[u8]` cannot be indexed by `u32`
+ s.as_bytes()[3i32]; //~ ERROR the type `[u8]` cannot be indexed by `i32`
+}
diff --git a/tests/ui/integral-indexing.stderr b/tests/ui/indexing/indexing-integral-types.stderr
similarity index 91%
rename from tests/ui/integral-indexing.stderr
rename to tests/ui/indexing/indexing-integral-types.stderr
index 26253e0..b63991e 100644
--- a/tests/ui/integral-indexing.stderr
+++ b/tests/ui/indexing/indexing-integral-types.stderr
@@ -1,5 +1,5 @@
error[E0277]: the type `[isize]` cannot be indexed by `u8`
- --> $DIR/integral-indexing.rs:6:7
+ --> $DIR/indexing-integral-types.rs:10:7
|
LL | v[3u8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -11,7 +11,7 @@
= note: required for `Vec<isize>` to implement `Index<u8>`
error[E0277]: the type `[isize]` cannot be indexed by `i8`
- --> $DIR/integral-indexing.rs:7:7
+ --> $DIR/indexing-integral-types.rs:11:7
|
LL | v[3i8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -23,7 +23,7 @@
= note: required for `Vec<isize>` to implement `Index<i8>`
error[E0277]: the type `[isize]` cannot be indexed by `u32`
- --> $DIR/integral-indexing.rs:8:7
+ --> $DIR/indexing-integral-types.rs:12:7
|
LL | v[3u32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
@@ -35,7 +35,7 @@
= note: required for `Vec<isize>` to implement `Index<u32>`
error[E0277]: the type `[isize]` cannot be indexed by `i32`
- --> $DIR/integral-indexing.rs:9:7
+ --> $DIR/indexing-integral-types.rs:13:7
|
LL | v[3i32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
@@ -47,7 +47,7 @@
= note: required for `Vec<isize>` to implement `Index<i32>`
error[E0277]: the type `[u8]` cannot be indexed by `u8`
- --> $DIR/integral-indexing.rs:12:18
+ --> $DIR/indexing-integral-types.rs:16:18
|
LL | s.as_bytes()[3u8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -59,7 +59,7 @@
= note: required for `[u8]` to implement `Index<u8>`
error[E0277]: the type `[u8]` cannot be indexed by `i8`
- --> $DIR/integral-indexing.rs:13:18
+ --> $DIR/indexing-integral-types.rs:17:18
|
LL | s.as_bytes()[3i8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -71,7 +71,7 @@
= note: required for `[u8]` to implement `Index<i8>`
error[E0277]: the type `[u8]` cannot be indexed by `u32`
- --> $DIR/integral-indexing.rs:14:18
+ --> $DIR/indexing-integral-types.rs:18:18
|
LL | s.as_bytes()[3u32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
@@ -83,7 +83,7 @@
= note: required for `[u8]` to implement `Index<u32>`
error[E0277]: the type `[u8]` cannot be indexed by `i32`
- --> $DIR/integral-indexing.rs:15:18
+ --> $DIR/indexing-integral-types.rs:19:18
|
LL | s.as_bytes()[3i32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
diff --git a/tests/ui/inline-disallow-on-variant.rs b/tests/ui/inline-disallow-on-variant.rs
deleted file mode 100644
index d92a4e8..0000000
--- a/tests/ui/inline-disallow-on-variant.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-enum Foo {
- #[inline]
- //~^ ERROR attribute should be applied
- Variant,
-}
-
-fn main() {}
diff --git a/tests/ui/inlined-main.rs b/tests/ui/inlined-main.rs
deleted file mode 100644
index 731ac0d..0000000
--- a/tests/ui/inlined-main.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ run-pass
-
-#[inline(always)]
-fn main() {}
diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs
deleted file mode 100644
index 1dce1cd..0000000
--- a/tests/ui/inner-attrs-on-impl.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//@ run-pass
-
-struct Foo;
-
-impl Foo {
- #![cfg(false)]
-
- fn method(&self) -> bool { false }
-}
-
-impl Foo {
- #![cfg(not(FALSE))]
-
- // check that we don't eat attributes too eagerly.
- #[cfg(false)]
- fn method(&self) -> bool { false }
-
- fn method(&self) -> bool { true }
-}
-
-
-pub fn main() {
- assert!(Foo.method());
-}
diff --git a/tests/ui/inner-module.rs b/tests/ui/inner-module.rs
deleted file mode 100644
index 111f2ca..0000000
--- a/tests/ui/inner-module.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-
-mod inner {
- pub mod inner2 {
- pub fn hello() { println!("hello, modular world"); }
- }
- pub fn hello() { inner2::hello(); }
-}
-
-pub fn main() { inner::hello(); inner::inner2::hello(); }
diff --git a/tests/ui/inner-static-type-parameter.rs b/tests/ui/inner-static-type-parameter.rs
deleted file mode 100644
index a1994e7..0000000
--- a/tests/ui/inner-static-type-parameter.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// see #9186
-
-enum Bar<T> { What } //~ ERROR parameter `T` is never used
-
-fn foo<T>() {
- static a: Bar<T> = Bar::What;
-//~^ ERROR can't use generic parameters from outer item
-}
-
-fn main() {
-}
diff --git a/tests/ui/integral-indexing.rs b/tests/ui/integral-indexing.rs
deleted file mode 100644
index e20553a..0000000
--- a/tests/ui/integral-indexing.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-pub fn main() {
- let v: Vec<isize> = vec![0, 1, 2, 3, 4, 5];
- let s: String = "abcdef".to_string();
- v[3_usize];
- v[3];
- v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8`
- v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8`
- v[3u32]; //~ ERROR the type `[isize]` cannot be indexed by `u32`
- v[3i32]; //~ ERROR the type `[isize]` cannot be indexed by `i32`
- s.as_bytes()[3_usize];
- s.as_bytes()[3];
- s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8`
- s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8`
- s.as_bytes()[3u32]; //~ ERROR the type `[u8]` cannot be indexed by `u32`
- s.as_bytes()[3i32]; //~ ERROR the type `[u8]` cannot be indexed by `i32`
-}
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.rs b/tests/ui/invalid_dispatch_from_dyn_impls.rs
deleted file mode 100644
index b1d4b26..0000000
--- a/tests/ui/invalid_dispatch_from_dyn_impls.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-#![feature(unsize, dispatch_from_dyn)]
-
-use std::{
- ops::DispatchFromDyn,
- marker::{Unsize, PhantomData},
-};
-
-struct WrapperWithExtraField<T>(T, i32);
-
-impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
-//~^ ERROR [E0378]
-where
- T: DispatchFromDyn<U>,
-{}
-
-
-struct MultiplePointers<T: ?Sized>{
- ptr1: *const T,
- ptr2: *const T,
-}
-
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
-//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
-where
- T: Unsize<U>,
-{}
-
-
-struct NothingToCoerce<T: ?Sized> {
- data: PhantomData<T>,
-}
-
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
-//~^ ERROR implementing `DispatchFromDyn` requires a field to be coerced
-
-#[repr(C)]
-struct HasReprC<T: ?Sized>(Box<T>);
-
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
-//~^ ERROR [E0378]
-where
- T: Unsize<U>,
-{}
-
-#[repr(align(64))]
-struct OverAlignedZst;
-struct OverAligned<T: ?Sized>(Box<T>, OverAlignedZst);
-
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
-//~^ ERROR [E0378]
- where
- T: Unsize<U>,
-{}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-46604.rs b/tests/ui/issues/issue-46604.rs
index 0396094..e15f0b5 100644
--- a/tests/ui/issues/issue-46604.rs
+++ b/tests/ui/issues/issue-46604.rs
@@ -1,4 +1,4 @@
-static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR mutable borrows of lifetime-extended temporaries
+static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR mutable borrows of temporaries
fn write<T: AsRef<[u8]>>(buffer: T) { }
fn main() {
diff --git a/tests/ui/issues/issue-46604.stderr b/tests/ui/issues/issue-46604.stderr
index f00f3f0..d983674 100644
--- a/tests/ui/issues/issue-46604.stderr
+++ b/tests/ui/issues/issue-46604.stderr
@@ -1,8 +1,12 @@
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/issue-46604.rs:1:25
|
LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item
--> $DIR/issue-46604.rs:6:5
diff --git a/tests/ui/lint/unused/must-use-macros.fixed b/tests/ui/lint/unused/must-use-macros.fixed
new file mode 100644
index 0000000..609d0c6
--- /dev/null
+++ b/tests/ui/lint/unused/must-use-macros.fixed
@@ -0,0 +1,60 @@
+// Makes sure the suggestions of the `unused_must_use` lint are not inside
+//
+// See <https://github.com/rust-lang/rust/issues/143025>
+
+//@ check-pass
+//@ run-rustfix
+
+#![expect(unused_macros)]
+#![warn(unused_must_use)]
+
+fn main() {
+ {
+ macro_rules! cmp {
+ ($a:tt, $b:tt) => {
+ $a == $b
+ };
+ }
+
+ // FIXME(Urgau): For some unknown reason the spans we get are not
+ // recorded to be from any expansions, preventing us from either
+ // suggesting in front of the macro or not at all.
+ // cmp!(1, 1);
+ }
+
+ {
+ macro_rules! cmp {
+ ($a:ident, $b:ident) => {
+ $a == $b
+ }; //~^ WARN unused comparison that must be used
+ }
+
+ let a = 1;
+ let b = 1;
+ let _ = cmp!(a, b);
+ //~^ SUGGESTION let _
+ }
+
+ {
+ macro_rules! cmp {
+ ($a:expr, $b:expr) => {
+ $a == $b
+ }; //~^ WARN unused comparison that must be used
+ }
+
+ let _ = cmp!(1, 1);
+ //~^ SUGGESTION let _
+ }
+
+ {
+ macro_rules! cmp {
+ ($a:tt, $b:tt) => {
+ $a.eq(&$b)
+ };
+ }
+
+ let _ = cmp!(1, 1);
+ //~^ WARN unused return value
+ //~| SUGGESTION let _
+ }
+}
diff --git a/tests/ui/lint/unused/must-use-macros.rs b/tests/ui/lint/unused/must-use-macros.rs
new file mode 100644
index 0000000..63e246e
--- /dev/null
+++ b/tests/ui/lint/unused/must-use-macros.rs
@@ -0,0 +1,60 @@
+// Makes sure the suggestions of the `unused_must_use` lint are not inside
+//
+// See <https://github.com/rust-lang/rust/issues/143025>
+
+//@ check-pass
+//@ run-rustfix
+
+#![expect(unused_macros)]
+#![warn(unused_must_use)]
+
+fn main() {
+ {
+ macro_rules! cmp {
+ ($a:tt, $b:tt) => {
+ $a == $b
+ };
+ }
+
+ // FIXME(Urgau): For some unknown reason the spans we get are not
+ // recorded to be from any expansions, preventing us from either
+ // suggesting in front of the macro or not at all.
+ // cmp!(1, 1);
+ }
+
+ {
+ macro_rules! cmp {
+ ($a:ident, $b:ident) => {
+ $a == $b
+ }; //~^ WARN unused comparison that must be used
+ }
+
+ let a = 1;
+ let b = 1;
+ cmp!(a, b);
+ //~^ SUGGESTION let _
+ }
+
+ {
+ macro_rules! cmp {
+ ($a:expr, $b:expr) => {
+ $a == $b
+ }; //~^ WARN unused comparison that must be used
+ }
+
+ cmp!(1, 1);
+ //~^ SUGGESTION let _
+ }
+
+ {
+ macro_rules! cmp {
+ ($a:tt, $b:tt) => {
+ $a.eq(&$b)
+ };
+ }
+
+ cmp!(1, 1);
+ //~^ WARN unused return value
+ //~| SUGGESTION let _
+ }
+}
diff --git a/tests/ui/lint/unused/must-use-macros.stderr b/tests/ui/lint/unused/must-use-macros.stderr
new file mode 100644
index 0000000..2ad174e
--- /dev/null
+++ b/tests/ui/lint/unused/must-use-macros.stderr
@@ -0,0 +1,48 @@
+warning: unused comparison that must be used
+ --> $DIR/must-use-macros.rs:28:17
+ |
+LL | $a == $b
+ | ^^^^^^^^ the comparison produces a value
+...
+LL | cmp!(a, b);
+ | ---------- in this macro invocation
+ |
+note: the lint level is defined here
+ --> $DIR/must-use-macros.rs:9:9
+ |
+LL | #![warn(unused_must_use)]
+ | ^^^^^^^^^^^^^^^
+ = note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `let _ = ...` to ignore the resulting value
+ |
+LL | let _ = cmp!(a, b);
+ | +++++++
+
+warning: unused comparison that must be used
+ --> $DIR/must-use-macros.rs:41:17
+ |
+LL | $a == $b
+ | ^^^^^^^^ the comparison produces a value
+...
+LL | cmp!(1, 1);
+ | ---------- in this macro invocation
+ |
+ = note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `let _ = ...` to ignore the resulting value
+ |
+LL | let _ = cmp!(1, 1);
+ | +++++++
+
+warning: unused return value of `std::cmp::PartialEq::eq` that must be used
+ --> $DIR/must-use-macros.rs:56:9
+ |
+LL | cmp!(1, 1);
+ | ^^^^^^^^^^
+ |
+help: use `let _ = ...` to ignore the resulting value
+ |
+LL | let _ = cmp!(1, 1);
+ | +++++++
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr
index 3a520ff..e845246 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr
@@ -90,31 +90,6 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: unused attribute
- --> $DIR/unused-attr-duplicate.rs:102:1
- |
-LL | #[used]
- | ^^^^^^^ help: remove this attribute
- |
-note: attribute also specified here
- --> $DIR/unused-attr-duplicate.rs:101:1
- |
-LL | #[used]
- | ^^^^^^^
-
-error: unused attribute
- --> $DIR/unused-attr-duplicate.rs:86:5
- |
-LL | #[link_name = "this_does_not_exist"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
- |
-note: attribute also specified here
- --> $DIR/unused-attr-duplicate.rs:88:5
- |
-LL | #[link_name = "rust_dbg_extern_identity_u32"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-error: unused attribute
--> $DIR/unused-attr-duplicate.rs:14:1
|
LL | #![crate_name = "unused_attr_duplicate2"]
@@ -265,6 +240,19 @@
| ^^^^^^^^^^^^^^^
error: unused attribute
+ --> $DIR/unused-attr-duplicate.rs:86:5
+ |
+LL | #[link_name = "this_does_not_exist"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/unused-attr-duplicate.rs:88:5
+ |
+LL | #[link_name = "rust_dbg_extern_identity_u32"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+error: unused attribute
--> $DIR/unused-attr-duplicate.rs:92:1
|
LL | #[export_name = "exported_symbol_name"]
@@ -289,5 +277,17 @@
LL | #[no_mangle]
| ^^^^^^^^^^^^
+error: unused attribute
+ --> $DIR/unused-attr-duplicate.rs:102:1
+ |
+LL | #[used]
+ | ^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/unused-attr-duplicate.rs:101:1
+ |
+LL | #[used]
+ | ^^^^^^^
+
error: aborting due to 23 previous errors
diff --git a/tests/ui/macros/issue-118048.rs b/tests/ui/macros/issue-118048.rs
index 15a834f..3b3ab3b 100644
--- a/tests/ui/macros/issue-118048.rs
+++ b/tests/ui/macros/issue-118048.rs
@@ -6,5 +6,6 @@ fn foo(_: $ty, _: $ty) {}
foo!(_);
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn main() {}
diff --git a/tests/ui/macros/issue-118048.stderr b/tests/ui/macros/issue-118048.stderr
index 4dc5ef7..f5468b3 100644
--- a/tests/ui/macros/issue-118048.stderr
+++ b/tests/ui/macros/issue-118048.stderr
@@ -2,20 +2,16 @@
--> $DIR/issue-118048.rs:7:6
|
LL | foo!(_);
- | ^
- | |
- | not allowed in type signatures
- | not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL ~ fn foo<T>(_: $ty, _: $ty) {}
-LL | }
-LL | }
-LL |
-LL ~ foo!(T);
- |
+ | ^ not allowed in type signatures
-error: aborting due to 1 previous error
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/issue-118048.rs:7:6
+ |
+LL | foo!(_);
+ | ^ not allowed in type signatures
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/macros/macro-span-issue-116502.rs b/tests/ui/macros/macro-span-issue-116502.rs
index 4c254289..b5ae383 100644
--- a/tests/ui/macros/macro-span-issue-116502.rs
+++ b/tests/ui/macros/macro-span-issue-116502.rs
@@ -5,6 +5,8 @@ fn bug() {
macro_rules! m {
() => {
_ //~ ERROR the placeholder `_` is not allowed within types on item signatures for structs
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
};
}
struct S<T = m!()>(m!(), T)
diff --git a/tests/ui/macros/macro-span-issue-116502.stderr b/tests/ui/macros/macro-span-issue-116502.stderr
index 2a581f7..68f8874 100644
--- a/tests/ui/macros/macro-span-issue-116502.stderr
+++ b/tests/ui/macros/macro-span-issue-116502.stderr
@@ -2,22 +2,35 @@
--> $DIR/macro-span-issue-116502.rs:7:13
|
LL | _
- | ^
- | |
- | not allowed in type signatures
- | not allowed in type signatures
- | not allowed in type signatures
+ | ^ not allowed in type signatures
...
-LL | struct S<T = m!()>(m!(), T)
- | ---- ---- in this macro invocation
- | |
- | in this macro invocation
-LL | where
LL | T: Trait<m!()>;
| ---- in this macro invocation
|
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 1 previous error
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/macro-span-issue-116502.rs:7:13
+ |
+LL | _
+ | ^ not allowed in type signatures
+...
+LL | struct S<T = m!()>(m!(), T)
+ | ---- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/macro-span-issue-116502.rs:7:13
+ |
+LL | _
+ | ^ not allowed in type signatures
+...
+LL | struct S<T = m!()>(m!(), T)
+ | ---- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/macros/must-use-in-macro-55516.stderr b/tests/ui/macros/must-use-in-macro-55516.stderr
index 7bf4aaa..b93d40d 100644
--- a/tests/ui/macros/must-use-in-macro-55516.stderr
+++ b/tests/ui/macros/must-use-in-macro-55516.stderr
@@ -7,7 +7,10 @@
= note: this `Result` may be an `Err` variant, which should be handled
= note: `-W unused-must-use` implied by `-W unused`
= help: to override `-W unused` add `#[allow(unused_must_use)]`
- = note: this warning originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `let _ = ...` to ignore the resulting value
+ |
+LL | let _ = write!(&mut example, "{}", 42);
+ | +++++++
warning: 1 warning emitted
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
index 3f3d9252..c858051 100644
--- a/tests/ui/macros/stringify.rs
+++ b/tests/ui/macros/stringify.rs
@@ -483,7 +483,6 @@ trait Trait<'a>: Sized
c1!(item, [ impl<T> Struct<T> {} ], "impl<T> Struct<T> {}");
c1!(item, [ pub impl Trait for Struct {} ], "pub impl Trait for Struct {}");
c1!(item, [ impl<T> const Trait for T {} ], "impl<T> const Trait for T {}");
- c1!(item, [ impl ~const Struct {} ], "impl ~const Struct {}");
// ItemKind::MacCall
c1!(item, [ mac!(); ], "mac!();");
@@ -730,7 +729,7 @@ fn test_ty() {
c1!(ty, [ dyn Send + 'a ], "dyn Send + 'a");
c1!(ty, [ dyn 'a + Send ], "dyn 'a + Send");
c1!(ty, [ dyn ?Sized ], "dyn ?Sized");
- c1!(ty, [ dyn ~const Clone ], "dyn ~const Clone");
+ c1!(ty, [ dyn [const] Clone ], "dyn [const] Clone");
c1!(ty, [ dyn for<'a> Send ], "dyn for<'a> Send");
// TyKind::ImplTrait
@@ -738,7 +737,7 @@ fn test_ty() {
c1!(ty, [ impl Send + 'a ], "impl Send + 'a");
c1!(ty, [ impl 'a + Send ], "impl 'a + Send");
c1!(ty, [ impl ?Sized ], "impl ?Sized");
- c1!(ty, [ impl ~const Clone ], "impl ~const Clone");
+ c1!(ty, [ impl [const] Clone ], "impl [const] Clone");
c1!(ty, [ impl for<'a> Send ], "impl for<'a> Send");
// TyKind::Paren
diff --git a/tests/ui/methods/method-missing-call.rs b/tests/ui/methods/method-missing-call.rs
deleted file mode 100644
index 7ce1e9a..0000000
--- a/tests/ui/methods/method-missing-call.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Tests to make sure that parens are needed for method calls without arguments.
-// outputs text to make sure either an anonymous function is provided or
-// open-close '()' parens are given
-
-
-struct Point {
- x: isize,
- y: isize
-}
-impl Point {
- fn new() -> Point {
- Point{x:0, y:0}
- }
- fn get_x(&self) -> isize {
- self.x
- }
-}
-
-fn main() {
- let point: Point = Point::new();
- let px: isize = point
- .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point`
-
- // Ensure the span is useful
- let ys = &[1,2,3,4,5,6,7];
- let a = ys.iter()
- .map(|x| x)
- .filter(|&&x| x == 1)
- .filter_map; //~ ERROR attempted to take value of method `filter_map` on type
-}
diff --git a/tests/ui/methods/method-missing-call.stderr b/tests/ui/methods/method-missing-call.stderr
deleted file mode 100644
index bc50846..0000000
--- a/tests/ui/methods/method-missing-call.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0615]: attempted to take value of method `get_x` on type `Point`
- --> $DIR/method-missing-call.rs:22:26
- |
-LL | .get_x;
- | ^^^^^ method, not a field
- |
-help: use parentheses to call the method
- |
-LL | .get_x();
- | ++
-
-error[E0615]: attempted to take value of method `filter_map` on type `Filter<Map<std::slice::Iter<'_, {integer}>, {closure@$DIR/method-missing-call.rs:27:20: 27:23}>, {closure@$DIR/method-missing-call.rs:28:23: 28:28}>`
- --> $DIR/method-missing-call.rs:29:16
- |
-LL | .filter_map;
- | ^^^^^^^^^^ method, not a field
- |
-help: use parentheses to call the method
- |
-LL | .filter_map(_);
- | +++
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0615`.
diff --git a/tests/ui/methods/method-value-without-call.rs b/tests/ui/methods/method-value-without-call.rs
new file mode 100644
index 0000000..43bee48
--- /dev/null
+++ b/tests/ui/methods/method-value-without-call.rs
@@ -0,0 +1,33 @@
+//! Test taking a method value without parentheses
+
+struct Point {
+ x: isize,
+ y: isize,
+}
+
+impl Point {
+ fn new() -> Point {
+ Point { x: 0, y: 0 }
+ }
+
+ fn get_x(&self) -> isize {
+ self.x
+ }
+}
+
+fn main() {
+ // Test with primitive type method
+ let _f = 10i32.abs; //~ ERROR attempted to take value of method
+
+ // Test with custom type method
+ let point: Point = Point::new();
+ let px: isize = point.get_x; //~ ERROR attempted to take value of method `get_x` on type `Point`
+
+ // Test with method chains - ensure the span is useful
+ let ys = &[1, 2, 3, 4, 5, 6, 7];
+ let a = ys
+ .iter()
+ .map(|x| x)
+ .filter(|&&x| x == 1)
+ .filter_map; //~ ERROR attempted to take value of method `filter_map` on type
+}
diff --git a/tests/ui/methods/method-value-without-call.stderr b/tests/ui/methods/method-value-without-call.stderr
new file mode 100644
index 0000000..0c3870e
--- /dev/null
+++ b/tests/ui/methods/method-value-without-call.stderr
@@ -0,0 +1,36 @@
+error[E0615]: attempted to take value of method `abs` on type `i32`
+ --> $DIR/method-value-without-call.rs:20:20
+ |
+LL | let _f = 10i32.abs;
+ | ^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | let _f = 10i32.abs();
+ | ++
+
+error[E0615]: attempted to take value of method `get_x` on type `Point`
+ --> $DIR/method-value-without-call.rs:24:27
+ |
+LL | let px: isize = point.get_x;
+ | ^^^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | let px: isize = point.get_x();
+ | ++
+
+error[E0615]: attempted to take value of method `filter_map` on type `Filter<Map<std::slice::Iter<'_, {integer}>, {closure@$DIR/method-value-without-call.rs:30:14: 30:17}>, {closure@$DIR/method-value-without-call.rs:31:17: 31:22}>`
+ --> $DIR/method-value-without-call.rs:32:10
+ |
+LL | .filter_map;
+ | ^^^^^^^^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | .filter_map(_);
+ | +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0615`.
diff --git a/tests/ui/mir/enum/convert_non_enum_break.rs b/tests/ui/mir/enum/convert_non_enum_break.rs
new file mode 100644
index 0000000..de062c3
--- /dev/null
+++ b/tests/ui/mir/enum/convert_non_enum_break.rs
@@ -0,0 +1,20 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x10000
+
+#[allow(dead_code)]
+#[repr(u32)]
+enum Foo {
+ A,
+ B,
+}
+
+#[allow(dead_code)]
+struct Bar {
+ a: u16,
+ b: u16,
+}
+
+fn main() {
+ let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 0, b: 1 }) };
+}
diff --git a/tests/ui/mir/enum/convert_non_enum_niche_break.rs b/tests/ui/mir/enum/convert_non_enum_niche_break.rs
new file mode 100644
index 0000000..9ff4849
--- /dev/null
+++ b/tests/ui/mir/enum/convert_non_enum_niche_break.rs
@@ -0,0 +1,27 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x5
+
+#[allow(dead_code)]
+#[repr(u16)]
+enum Mix {
+ A,
+ B(u16),
+}
+
+#[allow(dead_code)]
+enum Nested {
+ C(Mix),
+ D,
+ E,
+}
+
+#[allow(dead_code)]
+struct Bar {
+ a: u16,
+ b: u16,
+}
+
+fn main() {
+ let _val: Nested = unsafe { std::mem::transmute::<_, Nested>(Bar { a: 5, b: 0 }) };
+}
diff --git a/tests/ui/mir/enum/convert_non_enum_niche_ok.rs b/tests/ui/mir/enum/convert_non_enum_niche_ok.rs
new file mode 100644
index 0000000..24027da
--- /dev/null
+++ b/tests/ui/mir/enum/convert_non_enum_niche_ok.rs
@@ -0,0 +1,29 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+#[repr(u16)]
+enum Mix {
+ A,
+ B(u16),
+}
+
+#[allow(dead_code)]
+enum Nested {
+ C(Mix),
+ D,
+ E,
+}
+
+#[allow(dead_code)]
+struct Bar {
+ a: u16,
+ b: u16,
+}
+
+fn main() {
+ let _val: Nested = unsafe { std::mem::transmute::<_, Nested>(Bar { a: 0, b: 0 }) };
+ let _val: Nested = unsafe { std::mem::transmute::<_, Nested>(Bar { a: 1, b: 0 }) };
+ let _val: Nested = unsafe { std::mem::transmute::<_, Nested>(Bar { a: 2, b: 0 }) };
+ let _val: Nested = unsafe { std::mem::transmute::<_, Nested>(Bar { a: 3, b: 0 }) };
+}
diff --git a/tests/ui/mir/enum/convert_non_enum_ok.rs b/tests/ui/mir/enum/convert_non_enum_ok.rs
new file mode 100644
index 0000000..37fc643
--- /dev/null
+++ b/tests/ui/mir/enum/convert_non_enum_ok.rs
@@ -0,0 +1,20 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+#[repr(u32)]
+enum Foo {
+ A,
+ B,
+}
+
+#[allow(dead_code)]
+struct Bar {
+ a: u16,
+ b: u16,
+}
+
+fn main() {
+ let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 0, b: 0 }) };
+ let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 1, b: 0 }) };
+}
diff --git a/tests/ui/mir/enum/niche_option_tuple_break.rs b/tests/ui/mir/enum/niche_option_tuple_break.rs
new file mode 100644
index 0000000..43eef3a
--- /dev/null
+++ b/tests/ui/mir/enum/niche_option_tuple_break.rs
@@ -0,0 +1,20 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x3
+
+#[allow(dead_code)]
+enum Foo {
+ A,
+ B,
+}
+
+#[allow(dead_code)]
+struct Bar {
+ a: usize,
+ b: usize,
+}
+
+fn main() {
+ let _val: Option<(usize, Foo)> =
+ unsafe { std::mem::transmute::<_, Option<(usize, Foo)>>(Bar { a: 3, b: 3 }) };
+}
diff --git a/tests/ui/mir/enum/niche_option_tuple_ok.rs b/tests/ui/mir/enum/niche_option_tuple_ok.rs
new file mode 100644
index 0000000..71c885c
--- /dev/null
+++ b/tests/ui/mir/enum/niche_option_tuple_ok.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+enum Foo {
+ A,
+ B,
+}
+
+#[allow(dead_code)]
+struct Bar {
+ a: usize,
+ b: usize,
+}
+
+fn main() {
+ let _val: Option<(usize, Foo)> =
+ unsafe { std::mem::transmute::<_, Option<(usize, Foo)>>(Bar { a: 0, b: 0 }) };
+ let _val: Option<(usize, Foo)> =
+ unsafe { std::mem::transmute::<_, Option<(usize, Foo)>>(Bar { a: 1, b: 0 }) };
+}
diff --git a/tests/ui/mir/enum/numbered_variants_break.rs b/tests/ui/mir/enum/numbered_variants_break.rs
new file mode 100644
index 0000000..e3e71dc
--- /dev/null
+++ b/tests/ui/mir/enum/numbered_variants_break.rs
@@ -0,0 +1,13 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x3
+
+#[allow(dead_code)]
+enum Foo {
+ A,
+ B,
+}
+
+fn main() {
+ let _val: Foo = unsafe { std::mem::transmute::<u8, Foo>(3) };
+}
diff --git a/tests/ui/mir/enum/numbered_variants_ok.rs b/tests/ui/mir/enum/numbered_variants_ok.rs
new file mode 100644
index 0000000..995a2f6
--- /dev/null
+++ b/tests/ui/mir/enum/numbered_variants_ok.rs
@@ -0,0 +1,13 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+enum Foo {
+ A,
+ B,
+}
+
+fn main() {
+ let _val: Foo = unsafe { std::mem::transmute::<u8, Foo>(0) };
+ let _val: Foo = unsafe { std::mem::transmute::<u8, Foo>(1) };
+}
diff --git a/tests/ui/mir/enum/option_with_bigger_niche_break.rs b/tests/ui/mir/enum/option_with_bigger_niche_break.rs
new file mode 100644
index 0000000..c66614b
--- /dev/null
+++ b/tests/ui/mir/enum/option_with_bigger_niche_break.rs
@@ -0,0 +1,14 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x0
+
+#[repr(u32)]
+#[allow(dead_code)]
+enum Foo {
+ A = 2,
+ B,
+}
+
+fn main() {
+ let _val: Option<Foo> = unsafe { std::mem::transmute::<u32, Option<Foo>>(0) };
+}
diff --git a/tests/ui/mir/enum/option_with_bigger_niche_ok.rs b/tests/ui/mir/enum/option_with_bigger_niche_ok.rs
new file mode 100644
index 0000000..1d44ffd
--- /dev/null
+++ b/tests/ui/mir/enum/option_with_bigger_niche_ok.rs
@@ -0,0 +1,14 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[repr(u32)]
+#[allow(dead_code)]
+enum Foo {
+ A = 2,
+ B,
+}
+
+fn main() {
+ let _val: Option<Foo> = unsafe { std::mem::transmute::<u32, Option<Foo>>(2) };
+ let _val: Option<Foo> = unsafe { std::mem::transmute::<u32, Option<Foo>>(3) };
+}
diff --git a/tests/ui/mir/enum/plain_no_data_break.rs b/tests/ui/mir/enum/plain_no_data_break.rs
new file mode 100644
index 0000000..db68e75
--- /dev/null
+++ b/tests/ui/mir/enum/plain_no_data_break.rs
@@ -0,0 +1,14 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x1
+
+#[repr(u32)]
+#[allow(dead_code)]
+enum Foo {
+ A = 2,
+ B,
+}
+
+fn main() {
+ let _val: Foo = unsafe { std::mem::transmute::<u32, Foo>(1) };
+}
diff --git a/tests/ui/mir/enum/plain_no_data_ok.rs b/tests/ui/mir/enum/plain_no_data_ok.rs
new file mode 100644
index 0000000..bbdc18f
--- /dev/null
+++ b/tests/ui/mir/enum/plain_no_data_ok.rs
@@ -0,0 +1,14 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[repr(u32)]
+#[allow(dead_code)]
+enum Foo {
+ A = 2,
+ B,
+}
+
+fn main() {
+ let _val: Foo = unsafe { std::mem::transmute::<u32, Foo>(2) };
+ let _val: Foo = unsafe { std::mem::transmute::<u32, Foo>(3) };
+}
diff --git a/tests/ui/mir/enum/single_ok.rs b/tests/ui/mir/enum/single_ok.rs
new file mode 100644
index 0000000..06b5a23
--- /dev/null
+++ b/tests/ui/mir/enum/single_ok.rs
@@ -0,0 +1,11 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+enum Single {
+ A
+}
+
+fn main() {
+ let _val: Single = unsafe { std::mem::transmute::<(), Single>(()) };
+}
diff --git a/tests/ui/mir/enum/single_with_repr_break.rs b/tests/ui/mir/enum/single_with_repr_break.rs
new file mode 100644
index 0000000..5a4ec85
--- /dev/null
+++ b/tests/ui/mir/enum/single_with_repr_break.rs
@@ -0,0 +1,13 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x1
+
+#[allow(dead_code)]
+#[repr(u16)]
+enum Single {
+ A
+}
+
+fn main() {
+ let _val: Single = unsafe { std::mem::transmute::<u16, Single>(1) };
+}
diff --git a/tests/ui/mir/enum/single_with_repr_ok.rs b/tests/ui/mir/enum/single_with_repr_ok.rs
new file mode 100644
index 0000000..b0ed2ba
--- /dev/null
+++ b/tests/ui/mir/enum/single_with_repr_ok.rs
@@ -0,0 +1,12 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+#[repr(u16)]
+enum Single {
+ A
+}
+
+fn main() {
+ let _val: Single = unsafe { std::mem::transmute::<u16, Single>(0) };
+}
diff --git a/tests/ui/mir/enum/with_niche_int_break.rs b/tests/ui/mir/enum/with_niche_int_break.rs
new file mode 100644
index 0000000..0ec60a3
--- /dev/null
+++ b/tests/ui/mir/enum/with_niche_int_break.rs
@@ -0,0 +1,21 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x4
+
+#[allow(dead_code)]
+#[repr(u16)]
+enum Mix {
+ A,
+ B(u16),
+}
+
+#[allow(dead_code)]
+enum Nested {
+ C(Mix),
+ D,
+ E,
+}
+
+fn main() {
+ let _val: Nested = unsafe { std::mem::transmute::<u32, Nested>(4) };
+}
diff --git a/tests/ui/mir/enum/with_niche_int_ok.rs b/tests/ui/mir/enum/with_niche_int_ok.rs
new file mode 100644
index 0000000..9a3ff3a
--- /dev/null
+++ b/tests/ui/mir/enum/with_niche_int_ok.rs
@@ -0,0 +1,23 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+#[repr(u16)]
+enum Mix {
+ A,
+ B(u16),
+}
+
+#[allow(dead_code)]
+enum Nested {
+ C(Mix),
+ D,
+ E,
+}
+
+fn main() {
+ let _val: Nested = unsafe { std::mem::transmute::<u32, Nested>(0) };
+ let _val: Nested = unsafe { std::mem::transmute::<u32, Nested>(1) };
+ let _val: Nested = unsafe { std::mem::transmute::<u32, Nested>(2) };
+ let _val: Nested = unsafe { std::mem::transmute::<u32, Nested>(3) };
+}
diff --git a/tests/ui/mir/enum/with_niche_ptr_ok.rs b/tests/ui/mir/enum/with_niche_ptr_ok.rs
new file mode 100644
index 0000000..969d955
--- /dev/null
+++ b/tests/ui/mir/enum/with_niche_ptr_ok.rs
@@ -0,0 +1,14 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+fn main() {
+ let _val = unsafe {
+ std::mem::transmute::<*const usize, Option<unsafe extern "C" fn()>>(std::ptr::null())
+ };
+ let _val = unsafe {
+ std::mem::transmute::<*const usize, Option<unsafe extern "C" fn()>>(usize::MAX as *const _)
+ };
+ let _val = unsafe { std::mem::transmute::<usize, Option<unsafe extern "C" fn()>>(0) };
+ let _val = unsafe { std::mem::transmute::<usize, Option<unsafe extern "C" fn()>>(1) };
+ let _val = unsafe { std::mem::transmute::<usize, Option<unsafe extern "C" fn()>>(usize::MAX) };
+}
diff --git a/tests/ui/mir/enum/wrap_break.rs b/tests/ui/mir/enum/wrap_break.rs
new file mode 100644
index 0000000..4491394
--- /dev/null
+++ b/tests/ui/mir/enum/wrap_break.rs
@@ -0,0 +1,14 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0x0
+#![feature(never_type)]
+#![allow(invalid_value)]
+
+#[allow(dead_code)]
+enum Wrap {
+ A(!),
+}
+
+fn main() {
+ let _val: Wrap = unsafe { std::mem::transmute::<(), Wrap>(()) };
+}
diff --git a/tests/ui/mir/enum/wrap_ok.rs b/tests/ui/mir/enum/wrap_ok.rs
new file mode 100644
index 0000000..2881675
--- /dev/null
+++ b/tests/ui/mir/enum/wrap_ok.rs
@@ -0,0 +1,12 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+enum Wrap {
+ A(u32),
+}
+
+fn main() {
+ let _val: Wrap = unsafe { std::mem::transmute::<u32, Wrap>(2) };
+ let _val: Wrap = unsafe { std::mem::transmute::<u32, Wrap>(u32::MAX) };
+}
diff --git a/tests/ui/mismatched_types/elide-on-tuple-mismatch.rs b/tests/ui/mismatched_types/elide-on-tuple-mismatch.rs
new file mode 100644
index 0000000..c36d041
--- /dev/null
+++ b/tests/ui/mismatched_types/elide-on-tuple-mismatch.rs
@@ -0,0 +1,25 @@
+//! Regression test for issue #50333: elide irrelevant E0277 errors on tuple mismatch
+
+// Hide irrelevant E0277 errors (#50333)
+
+trait T {}
+
+struct A;
+
+impl T for A {}
+
+impl A {
+ fn new() -> Self {
+ Self {}
+ }
+}
+
+fn main() {
+ // This creates a tuple type mismatch: 2-element tuple destructured into 3 variables
+ let (a, b, c) = (A::new(), A::new());
+ //~^ ERROR mismatched types
+
+ // This line should NOT produce an E0277 error about `Sized` trait bounds,
+ // because `a`, `b`, and `c` are `TyErr` due to the mismatch above
+ let _ts: Vec<&dyn T> = vec![&a, &b, &c];
+}
diff --git a/tests/ui/elide-errors-on-mismatched-tuple.stderr b/tests/ui/mismatched_types/elide-on-tuple-mismatch.stderr
similarity index 72%
rename from tests/ui/elide-errors-on-mismatched-tuple.stderr
rename to tests/ui/mismatched_types/elide-on-tuple-mismatch.stderr
index f852a22..7de45eb 100644
--- a/tests/ui/elide-errors-on-mismatched-tuple.stderr
+++ b/tests/ui/mismatched_types/elide-on-tuple-mismatch.stderr
@@ -1,7 +1,7 @@
error[E0308]: mismatched types
- --> $DIR/elide-errors-on-mismatched-tuple.rs:14:9
+ --> $DIR/elide-on-tuple-mismatch.rs:19:9
|
-LL | let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three
+LL | let (a, b, c) = (A::new(), A::new());
| ^^^^^^^^^ -------------------- this expression has type `(A, A)`
| |
| expected a tuple with 2 elements, found one with 3 elements
diff --git a/tests/ui/integral-variable-unification-error.rs b/tests/ui/mismatched_types/int-float-type-mismatch.rs
similarity index 64%
rename from tests/ui/integral-variable-unification-error.rs
rename to tests/ui/mismatched_types/int-float-type-mismatch.rs
index 8d16213..b45d027 100644
--- a/tests/ui/integral-variable-unification-error.rs
+++ b/tests/ui/mismatched_types/int-float-type-mismatch.rs
@@ -1,3 +1,6 @@
+//! Check that a type mismatch error is reported when trying
+//! to unify a {float} value assignment to an {integer} variable.
+
fn main() {
let mut x //~ NOTE expected due to the type of this binding
=
diff --git a/tests/ui/integral-variable-unification-error.stderr b/tests/ui/mismatched_types/int-float-type-mismatch.stderr
similarity index 86%
rename from tests/ui/integral-variable-unification-error.stderr
rename to tests/ui/mismatched_types/int-float-type-mismatch.stderr
index 1caa604..43b8609 100644
--- a/tests/ui/integral-variable-unification-error.stderr
+++ b/tests/ui/mismatched_types/int-float-type-mismatch.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/integral-variable-unification-error.rs:5:9
+ --> $DIR/int-float-type-mismatch.rs:8:9
|
LL | let mut x
| ----- expected due to the type of this binding
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/submodule/mod.rs b/tests/ui/modules/module_suggestion_when_module_not_found/submodule/mod.rs
new file mode 100644
index 0000000..cb92417
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/submodule/mod.rs
@@ -0,0 +1 @@
+//@ ignore-auxiliary
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/submodule2.rs b/tests/ui/modules/module_suggestion_when_module_not_found/submodule2.rs
new file mode 100644
index 0000000..cb92417
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/submodule2.rs
@@ -0,0 +1 @@
+//@ ignore-auxiliary
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/success.rs b/tests/ui/modules/module_suggestion_when_module_not_found/success.rs
new file mode 100644
index 0000000..888e6ab
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/success.rs
@@ -0,0 +1,4 @@
+//@ ignore-auxiliary
+
+use submodule3::ferris; // these modules are unresolved.
+use submodule4::error;
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/success/compiletest-ignore-dir b/tests/ui/modules/module_suggestion_when_module_not_found/success/compiletest-ignore-dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/success/compiletest-ignore-dir
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/success/submodule3/mod.rs b/tests/ui/modules/module_suggestion_when_module_not_found/success/submodule3/mod.rs
new file mode 100644
index 0000000..8337712
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/success/submodule3/mod.rs
@@ -0,0 +1 @@
+//
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/success/submodule4.rs b/tests/ui/modules/module_suggestion_when_module_not_found/success/submodule4.rs
new file mode 100644
index 0000000..8337712
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/success/submodule4.rs
@@ -0,0 +1 @@
+//
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/suggestion.rs b/tests/ui/modules/module_suggestion_when_module_not_found/suggestion.rs
new file mode 100644
index 0000000..f4c24bf
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/suggestion.rs
@@ -0,0 +1,7 @@
+//@ edition:2024
+use submodule::cat; //~ ERROR unresolved import `submodule`
+use submodule2::help; //~ ERROR unresolved import `submodule2`
+mod success;
+fn main() {}
+//~? ERROR unresolved import `submodule3`
+//~? ERROR unresolved import `submodule4`
diff --git a/tests/ui/modules/module_suggestion_when_module_not_found/suggestion.stderr b/tests/ui/modules/module_suggestion_when_module_not_found/suggestion.stderr
new file mode 100644
index 0000000..6375d71
--- /dev/null
+++ b/tests/ui/modules/module_suggestion_when_module_not_found/suggestion.stderr
@@ -0,0 +1,49 @@
+error[E0432]: unresolved import `submodule`
+ --> $DIR/suggestion.rs:2:5
+ |
+LL | use submodule::cat;
+ | ^^^^^^^^^ use of unresolved module or unlinked crate `submodule`
+ |
+help: to make use of source file $DIR/submodule/mod.rs, use `mod submodule` in this file to declare the module
+ |
+LL + mod submodule;
+ |
+
+error[E0432]: unresolved import `submodule2`
+ --> $DIR/suggestion.rs:3:5
+ |
+LL | use submodule2::help;
+ | ^^^^^^^^^^ use of unresolved module or unlinked crate `submodule2`
+ |
+help: to make use of source file $DIR/submodule2.rs, use `mod submodule2` in this file to declare the module
+ |
+LL + mod submodule2;
+ |
+
+error[E0432]: unresolved import `submodule3`
+ --> $DIR/success.rs:3:5
+ |
+LL | use submodule3::ferris; // these modules are unresolved.
+ | ^^^^^^^^^^ use of unresolved module or unlinked crate `submodule3`
+ |
+help: to make use of source file $DIR/success/submodule3/mod.rs, use `mod submodule3` in this file to declare the module
+ --> $DIR/suggestion.rs:2:1
+ |
+LL + mod submodule3;
+ |
+
+error[E0432]: unresolved import `submodule4`
+ --> $DIR/success.rs:4:5
+ |
+LL | use submodule4::error;
+ | ^^^^^^^^^^ use of unresolved module or unlinked crate `submodule4`
+ |
+help: to make use of source file $DIR/success/submodule4.rs, use `mod submodule4` in this file to declare the module
+ --> $DIR/suggestion.rs:2:1
+ |
+LL + mod submodule4;
+ |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/modules/nested-modules-basic.rs b/tests/ui/modules/nested-modules-basic.rs
new file mode 100644
index 0000000..12eccec
--- /dev/null
+++ b/tests/ui/modules/nested-modules-basic.rs
@@ -0,0 +1,19 @@
+//! Basic test for nested module functionality and path resolution
+
+//@ run-pass
+
+mod inner {
+ pub mod inner2 {
+ pub fn hello() {
+ println!("hello, modular world");
+ }
+ }
+ pub fn hello() {
+ inner2::hello();
+ }
+}
+
+pub fn main() {
+ inner::hello();
+ inner::inner2::hello();
+}
diff --git a/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr b/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr
index f82d613..e71a6de 100644
--- a/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr
+++ b/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr
@@ -12,7 +12,10 @@
LL | assert_eq!(mod_file_aux::bar(), 10);
| ^^^^^^^^^^^^ use of unresolved module or unlinked crate `mod_file_aux`
|
- = help: you might be missing a crate named `mod_file_aux`
+help: to make use of source file $DIR/mod_file_aux.rs, use `mod mod_file_aux` in this file to declare the module
+ |
+LL + mod mod_file_aux;
+ |
error: aborting due to 2 previous errors
diff --git a/tests/ui/panic-runtime/auxiliary/depends.rs b/tests/ui/panic-runtime/auxiliary/depends.rs
deleted file mode 100644
index 7a35619..0000000
--- a/tests/ui/panic-runtime/auxiliary/depends.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ no-prefer-dynamic
-
-#![feature(panic_runtime)]
-#![crate_type = "rlib"]
-#![panic_runtime]
-#![no_std]
-
-extern crate needs_panic_runtime;
diff --git a/tests/ui/panic-runtime/auxiliary/needs-panic-runtime.rs b/tests/ui/panic-runtime/auxiliary/needs-panic-runtime.rs
deleted file mode 100644
index fbafee0..0000000
--- a/tests/ui/panic-runtime/auxiliary/needs-panic-runtime.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ no-prefer-dynamic
-
-#![feature(needs_panic_runtime)]
-#![crate_type = "rlib"]
-#![needs_panic_runtime]
-#![no_std]
diff --git a/tests/ui/panic-runtime/runtime-depend-on-needs-runtime.rs b/tests/ui/panic-runtime/runtime-depend-on-needs-runtime.rs
deleted file mode 100644
index eb00c07..0000000
--- a/tests/ui/panic-runtime/runtime-depend-on-needs-runtime.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ dont-check-compiler-stderr
-//@ aux-build:needs-panic-runtime.rs
-//@ aux-build:depends.rs
-
-extern crate depends;
-
-fn main() {}
-
-//~? ERROR the crate `depends` cannot depend on a crate that needs a panic runtime, but it depends on `needs_panic_runtime`
diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs
index ec0e83c..1bd67bb 100644
--- a/tests/ui/parser/bounds-type.rs
+++ b/tests/ui/parser/bounds-type.rs
@@ -10,10 +10,10 @@ struct S<
T: Tr +, // OK
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
- T: ~const Tr, // OK
- T: ~const ?Tr, //~ ERROR `~const` trait not allowed with `?` trait polarity modifier
- T: ~const Tr + 'a, // OK
- T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds
+ T: [const] Tr, // OK
+ T: [const] ?Tr, //~ ERROR `[const]` trait not allowed with `?` trait polarity modifier
+ T: [const] Tr + 'a, // OK
+ T: [const] 'a, //~ ERROR `[const]` may only modify trait bounds, not lifetime bounds
T: const 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds
T: async Tr, // OK
diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr
index 09c35c1..7c3e92a 100644
--- a/tests/ui/parser/bounds-type.stderr
+++ b/tests/ui/parser/bounds-type.stderr
@@ -12,19 +12,19 @@
LL | T: ?'a,
| ^
-error: `~const` trait not allowed with `?` trait polarity modifier
- --> $DIR/bounds-type.rs:14:15
+error: `[const]` trait not allowed with `?` trait polarity modifier
+ --> $DIR/bounds-type.rs:14:16
|
-LL | T: ~const ?Tr,
- | ------ ^
+LL | T: [const] ?Tr,
+ | ------- ^
| |
- | there is not a well-defined meaning for a `~const ?` trait
+ | there is not a well-defined meaning for a `[const] ?` trait
-error: `~const` may only modify trait bounds, not lifetime bounds
+error: `[const]` may only modify trait bounds, not lifetime bounds
--> $DIR/bounds-type.rs:16:8
|
-LL | T: ~const 'a,
- | ^^^^^^
+LL | T: [const] 'a,
+ | ^^^^^^^
error: `const` may only modify trait bounds, not lifetime bounds
--> $DIR/bounds-type.rs:17:8
diff --git a/tests/ui/double-ref.rs b/tests/ui/parser/reference-whitespace-parsing.rs
similarity index 91%
rename from tests/ui/double-ref.rs
rename to tests/ui/parser/reference-whitespace-parsing.rs
index eecf68f..7109c59 100644
--- a/tests/ui/double-ref.rs
+++ b/tests/ui/parser/reference-whitespace-parsing.rs
@@ -1,3 +1,5 @@
+//! Test parsing of multiple references with various whitespace arrangements
+
//@ run-pass
#![allow(dead_code)]
diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs
index 8f6221c..1cbd2ff 100644
--- a/tests/ui/parser/trait-object-delimiters.rs
+++ b/tests/ui/parser/trait-object-delimiters.rs
@@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t
fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
-//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
+//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `[`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
//~| ERROR at least one trait is required for an object type
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr
index be130ac..16d5392 100644
--- a/tests/ui/parser/trait-object-delimiters.stderr
+++ b/tests/ui/parser/trait-object-delimiters.stderr
@@ -39,11 +39,11 @@
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| ^ expected parameter name
-error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
+error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `[`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
--> $DIR/trait-object-delimiters.rs:10:17
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
- | -^ expected one of 13 possible tokens
+ | -^ expected one of 14 possible tokens
| |
| help: missing `,`
diff --git a/tests/ui/recursion/recursive-static-definition.rs b/tests/ui/recursion/recursive-static-definition.rs
index 55db6a8..4f0624e 100644
--- a/tests/ui/recursion/recursive-static-definition.rs
+++ b/tests/ui/recursion/recursive-static-definition.rs
@@ -1,5 +1,5 @@
pub static FOO: u32 = FOO;
-//~^ ERROR encountered static that tried to initialize itself with itself
+//~^ ERROR encountered static that tried to access itself during initialization
#[derive(Copy, Clone)]
pub union Foo {
@@ -7,6 +7,6 @@ pub union Foo {
}
pub static BAR: Foo = BAR;
-//~^ ERROR encountered static that tried to initialize itself with itself
+//~^ ERROR encountered static that tried to access itself during initialization
fn main() {}
diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr
index ce93c41..1e40058 100644
--- a/tests/ui/recursion/recursive-static-definition.stderr
+++ b/tests/ui/recursion/recursive-static-definition.stderr
@@ -1,10 +1,10 @@
-error[E0080]: encountered static that tried to initialize itself with itself
+error[E0080]: encountered static that tried to access itself during initialization
--> $DIR/recursive-static-definition.rs:1:23
|
LL | pub static FOO: u32 = FOO;
| ^^^ evaluation of `FOO` failed here
-error[E0080]: encountered static that tried to initialize itself with itself
+error[E0080]: encountered static that tried to access itself during initialization
--> $DIR/recursive-static-definition.rs:9:23
|
LL | pub static BAR: Foo = BAR;
diff --git a/tests/ui/self/self-infer.stderr b/tests/ui/self/self-infer.stderr
index c6bdff2..f9db559 100644
--- a/tests/ui/self/self-infer.stderr
+++ b/tests/ui/self/self-infer.stderr
@@ -3,24 +3,12 @@
|
LL | fn f(self: _) {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn f(self: _) {}
-LL + fn f<T>(self: T) {}
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/self-infer.rs:5:17
|
LL | fn g(self: &_) {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn g(self: &_) {}
-LL + fn g<T>(self: &T) {}
- |
error: aborting due to 2 previous errors
diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs
index 4c28568..01fed85 100644
--- a/tests/ui/simd/intrinsic/float-math-pass.rs
+++ b/tests/ui/simd/intrinsic/float-math-pass.rs
@@ -85,6 +85,9 @@ fn main() {
let r = simd_round(h);
assert_eq!(x, r);
+ let r = simd_round_ties_even(h);
+ assert_eq!(z, r);
+
let r = simd_trunc(h);
assert_eq!(z, r);
}
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
index fdf06b7..caec607 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
@@ -43,6 +43,10 @@ fn main() {
simd_shl(y, y);
simd_shr(x, x);
simd_shr(y, y);
+ simd_funnel_shl(x, x, x);
+ simd_funnel_shl(y, y, y);
+ simd_funnel_shr(x, x, x);
+ simd_funnel_shr(y, y, y);
simd_and(x, x);
simd_and(y, y);
simd_or(x, x);
@@ -73,6 +77,10 @@ fn main() {
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
simd_shr(0, 0);
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
+ simd_funnel_shl(0, 0, 0);
+ //~^ ERROR expected SIMD input type, found non-SIMD `i32`
+ simd_funnel_shr(0, 0, 0);
+ //~^ ERROR expected SIMD input type, found non-SIMD `i32`
simd_and(0, 0);
//~^ ERROR expected SIMD input type, found non-SIMD `i32`
simd_or(0, 0);
@@ -95,6 +103,10 @@ fn main() {
//~^ ERROR unsupported operation on `f32x4` with element `f32`
simd_shr(z, z);
//~^ ERROR unsupported operation on `f32x4` with element `f32`
+ simd_funnel_shl(z, z, z);
+ //~^ ERROR unsupported operation on `f32x4` with element `f32`
+ simd_funnel_shr(z, z, z);
+ //~^ ERROR unsupported operation on `f32x4` with element `f32`
simd_and(z, z);
//~^ ERROR unsupported operation on `f32x4` with element `f32`
simd_or(z, z);
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
index 76db6d5..a27a8d7 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
@@ -1,147 +1,171 @@
error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:64:9
+ --> $DIR/generic-arithmetic-2.rs:68:9
|
LL | simd_add(0, 0);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_sub` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:66:9
+ --> $DIR/generic-arithmetic-2.rs:70:9
|
LL | simd_sub(0, 0);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_mul` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:68:9
+ --> $DIR/generic-arithmetic-2.rs:72:9
|
LL | simd_mul(0, 0);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_div` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:70:9
+ --> $DIR/generic-arithmetic-2.rs:74:9
|
LL | simd_div(0, 0);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_shl` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:72:9
+ --> $DIR/generic-arithmetic-2.rs:76:9
|
LL | simd_shl(0, 0);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_shr` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:74:9
+ --> $DIR/generic-arithmetic-2.rs:78:9
|
LL | simd_shr(0, 0);
| ^^^^^^^^^^^^^^
+error[E0511]: invalid monomorphization of `simd_funnel_shl` intrinsic: expected SIMD input type, found non-SIMD `i32`
+ --> $DIR/generic-arithmetic-2.rs:80:9
+ |
+LL | simd_funnel_shl(0, 0, 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_funnel_shr` intrinsic: expected SIMD input type, found non-SIMD `i32`
+ --> $DIR/generic-arithmetic-2.rs:82:9
+ |
+LL | simd_funnel_shr(0, 0, 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0511]: invalid monomorphization of `simd_and` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:76:9
+ --> $DIR/generic-arithmetic-2.rs:84:9
|
LL | simd_and(0, 0);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_or` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:78:9
+ --> $DIR/generic-arithmetic-2.rs:86:9
|
LL | simd_or(0, 0);
| ^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_xor` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:80:9
+ --> $DIR/generic-arithmetic-2.rs:88:9
|
LL | simd_xor(0, 0);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_neg` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:83:9
+ --> $DIR/generic-arithmetic-2.rs:91:9
|
LL | simd_neg(0);
| ^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:85:9
+ --> $DIR/generic-arithmetic-2.rs:93:9
|
LL | simd_bswap(0);
| ^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:87:9
+ --> $DIR/generic-arithmetic-2.rs:95:9
|
LL | simd_bitreverse(0);
| ^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:89:9
+ --> $DIR/generic-arithmetic-2.rs:97:9
|
LL | simd_ctlz(0);
| ^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: expected SIMD input type, found non-SIMD `i32`
- --> $DIR/generic-arithmetic-2.rs:91:9
+ --> $DIR/generic-arithmetic-2.rs:99:9
|
LL | simd_cttz(0);
| ^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:94:9
+ --> $DIR/generic-arithmetic-2.rs:102:9
|
LL | simd_shl(z, z);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:96:9
+ --> $DIR/generic-arithmetic-2.rs:104:9
|
LL | simd_shr(z, z);
| ^^^^^^^^^^^^^^
+error[E0511]: invalid monomorphization of `simd_funnel_shl` intrinsic: unsupported operation on `f32x4` with element `f32`
+ --> $DIR/generic-arithmetic-2.rs:106:9
+ |
+LL | simd_funnel_shl(z, z, z);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_funnel_shr` intrinsic: unsupported operation on `f32x4` with element `f32`
+ --> $DIR/generic-arithmetic-2.rs:108:9
+ |
+LL | simd_funnel_shr(z, z, z);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:98:9
+ --> $DIR/generic-arithmetic-2.rs:110:9
|
LL | simd_and(z, z);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:100:9
+ --> $DIR/generic-arithmetic-2.rs:112:9
|
LL | simd_or(z, z);
| ^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:102:9
+ --> $DIR/generic-arithmetic-2.rs:114:9
|
LL | simd_xor(z, z);
| ^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:104:9
+ --> $DIR/generic-arithmetic-2.rs:116:9
|
LL | simd_bswap(z);
| ^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:106:9
+ --> $DIR/generic-arithmetic-2.rs:118:9
|
LL | simd_bitreverse(z);
| ^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:108:9
+ --> $DIR/generic-arithmetic-2.rs:120:9
|
LL | simd_ctlz(z);
| ^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_ctpop` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:110:9
+ --> $DIR/generic-arithmetic-2.rs:122:9
|
LL | simd_ctpop(z);
| ^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: unsupported operation on `f32x4` with element `f32`
- --> $DIR/generic-arithmetic-2.rs:112:9
+ --> $DIR/generic-arithmetic-2.rs:124:9
|
LL | simd_cttz(z);
| ^^^^^^^^^^^^
-error: aborting due to 24 previous errors
+error: aborting due to 28 previous errors
For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
index 3f0325d..4c97fb2 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
@@ -83,6 +83,80 @@ fn main() {
all_eq!(simd_shr(simd_shl(y1, y2), y2), y1);
all_eq!(simd_shr(simd_shl(y2, y1), y1), y2);
+ all_eq!(
+ simd_funnel_shl(x1, x2, x1),
+ i32x4([
+ (1 << 1) | (2 >> 31),
+ (2 << 2) | (3 >> 30),
+ (3 << 3) | (4 >> 29),
+ (4 << 4) | (5 >> 28)
+ ])
+ );
+ all_eq!(
+ simd_funnel_shl(x2, x1, x1),
+ i32x4([
+ (2 << 1) | (1 >> 31),
+ (3 << 2) | (2 >> 30),
+ (4 << 3) | (3 >> 29),
+ (5 << 4) | (4 >> 28)
+ ])
+ );
+ all_eq!(
+ simd_funnel_shl(y1, y2, y1),
+ U32::<4>([
+ (1 << 1) | (2 >> 31),
+ (2 << 2) | (3 >> 30),
+ (3 << 3) | (4 >> 29),
+ (4 << 4) | (5 >> 28)
+ ])
+ );
+ all_eq!(
+ simd_funnel_shl(y2, y1, y1),
+ U32::<4>([
+ (2 << 1) | (1 >> 31),
+ (3 << 2) | (2 >> 30),
+ (4 << 3) | (3 >> 29),
+ (5 << 4) | (4 >> 28)
+ ])
+ );
+
+ all_eq!(
+ simd_funnel_shr(x1, x2, x1),
+ i32x4([
+ (1 << 31) | (2 >> 1),
+ (2 << 30) | (3 >> 2),
+ (3 << 29) | (4 >> 3),
+ (4 << 28) | (5 >> 4)
+ ])
+ );
+ all_eq!(
+ simd_funnel_shr(x2, x1, x1),
+ i32x4([
+ (2 << 31) | (1 >> 1),
+ (3 << 30) | (2 >> 2),
+ (4 << 29) | (3 >> 3),
+ (5 << 28) | (4 >> 4)
+ ])
+ );
+ all_eq!(
+ simd_funnel_shr(y1, y2, y1),
+ U32::<4>([
+ (1 << 31) | (2 >> 1),
+ (2 << 30) | (3 >> 2),
+ (3 << 29) | (4 >> 3),
+ (4 << 28) | (5 >> 4)
+ ])
+ );
+ all_eq!(
+ simd_funnel_shr(y2, y1, y1),
+ U32::<4>([
+ (2 << 31) | (1 >> 1),
+ (3 << 30) | (2 >> 2),
+ (4 << 29) | (3 >> 3),
+ (5 << 28) | (4 >> 4)
+ ])
+ );
+
// ensure we get logical vs. arithmetic shifts correct
let (a, b, c, d) = (-12, -123, -1234, -12345);
all_eq!(simd_shr(i32x4([a, b, c, d]), x1), i32x4([a >> 1, b >> 2, c >> 3, d >> 4]));
diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
new file mode 100644
index 0000000..ece1702
--- /dev/null
+++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
@@ -0,0 +1,16 @@
+#![feature(sized_hierarchy)]
+
+use std::marker::PointeeSized;
+
+type Foo = dyn PointeeSized;
+//~^ ERROR `PointeeSized` cannot be used with trait objects
+
+fn foo(f: &Foo) {}
+
+fn main() {
+ foo(&());
+
+ let x = main;
+ let y: Box<dyn PointeeSized> = x;
+//~^ ERROR `PointeeSized` cannot be used with trait objects
+}
diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
new file mode 100644
index 0000000..a833c69
--- /dev/null
+++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
@@ -0,0 +1,14 @@
+error: `PointeeSized` cannot be used with trait objects
+ --> $DIR/reject-dyn-pointeesized.rs:5:12
+ |
+LL | type Foo = dyn PointeeSized;
+ | ^^^^^^^^^^^^^^^^
+
+error: `PointeeSized` cannot be used with trait objects
+ --> $DIR/reject-dyn-pointeesized.rs:14:16
+ |
+LL | let y: Box<dyn PointeeSized> = x;
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/specialization/const_trait_impl.rs b/tests/ui/specialization/const_trait_impl.rs
index d842601..2df92df 100644
--- a/tests/ui/specialization/const_trait_impl.rs
+++ b/tests/ui/specialization/const_trait_impl.rs
@@ -10,7 +10,7 @@ pub unsafe trait Sup {
#[rustc_specialization_trait]
#[const_trait]
-pub unsafe trait Sub: ~const Sup {}
+pub unsafe trait Sub: [const] Sup {}
unsafe impl const Sup for u8 {
default fn foo() -> u32 {
@@ -31,19 +31,19 @@ pub trait A {
fn a() -> u32;
}
-impl<T: ~const Default> const A for T {
+impl<T: [const] Default> const A for T {
default fn a() -> u32 {
2
}
}
-impl<T: ~const Default + ~const Sup> const A for T {
+impl<T: [const] Default + [const] Sup> const A for T {
default fn a() -> u32 {
3
}
}
-impl<T: ~const Default + ~const Sub> const A for T {
+impl<T: [const] Default + [const] Sub> const A for T {
fn a() -> u32 {
T::foo()
}
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index 3e1260f..ea3ec16 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,57 +1,57 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const_trait_impl.rs:34:9
|
-LL | impl<T: ~const Default> const A for T {
- | ^^^^^^ can't be applied to `Default`
+LL | impl<T: [const] Default> const A for T {
+ | ^^^^^^^ can't be applied to `Default`
|
-note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Default` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/default.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const_trait_impl.rs:40:9
|
-LL | impl<T: ~const Default + ~const Sup> const A for T {
- | ^^^^^^ can't be applied to `Default`
+LL | impl<T: [const] Default + [const] Sup> const A for T {
+ | ^^^^^^^ can't be applied to `Default`
|
-note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Default` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/default.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const_trait_impl.rs:46:9
|
-LL | impl<T: ~const Default + ~const Sub> const A for T {
- | ^^^^^^ can't be applied to `Default`
+LL | impl<T: [const] Default + [const] Sub> const A for T {
+ | ^^^^^^^ can't be applied to `Default`
|
-note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Default` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/default.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const_trait_impl.rs:40:9
|
-LL | impl<T: ~const Default + ~const Sup> const A for T {
- | ^^^^^^ can't be applied to `Default`
+LL | impl<T: [const] Default + [const] Sup> const A for T {
+ | ^^^^^^^ can't be applied to `Default`
|
-note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Default` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/default.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const_trait_impl.rs:34:9
|
-LL | impl<T: ~const Default> const A for T {
- | ^^^^^^ can't be applied to `Default`
+LL | impl<T: [const] Default> const A for T {
+ | ^^^^^^^ can't be applied to `Default`
|
-note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Default` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/default.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const_trait_impl.rs:46:9
|
-LL | impl<T: ~const Default + ~const Sub> const A for T {
- | ^^^^^^ can't be applied to `Default`
+LL | impl<T: [const] Default + [const] Sub> const A for T {
+ | ^^^^^^^ can't be applied to `Default`
|
-note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Default` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/default.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/statics/check-immutable-mut-slices.rs b/tests/ui/statics/check-immutable-mut-slices.rs
index 9e5ca50..19545a1c 100644
--- a/tests/ui/statics/check-immutable-mut-slices.rs
+++ b/tests/ui/statics/check-immutable-mut-slices.rs
@@ -1,6 +1,6 @@
// Checks that immutable static items can't have mutable slices
static TEST: &'static mut [isize] = &mut [];
-//~^ ERROR mutable borrows of lifetime-extended temporaries
+//~^ ERROR mutable borrows of temporaries
pub fn main() { }
diff --git a/tests/ui/statics/check-immutable-mut-slices.stderr b/tests/ui/statics/check-immutable-mut-slices.stderr
index 3552175..a9486fc 100644
--- a/tests/ui/statics/check-immutable-mut-slices.stderr
+++ b/tests/ui/statics/check-immutable-mut-slices.stderr
@@ -1,8 +1,12 @@
-error[E0764]: mutable borrows of lifetime-extended temporaries in the top-level scope of a static are not allowed
+error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
--> $DIR/check-immutable-mut-slices.rs:3:37
|
LL | static TEST: &'static mut [isize] = &mut [];
- | ^^^^^^^
+ | ^^^^^^^ this mutable borrow refers to such a temporary
+ |
+ = note: Temporaries in constants and statics can have their lifetime extended until the end of the program
+ = note: To avoid accidentally creating global mutable state, such temporaries must be immutable
+ = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
error: aborting due to 1 previous error
diff --git a/tests/ui/statics/read_before_init.rs b/tests/ui/statics/read_before_init.rs
index d779ef6..32cc255 100644
--- a/tests/ui/statics/read_before_init.rs
+++ b/tests/ui/statics/read_before_init.rs
@@ -8,13 +8,15 @@
use std::mem::MaybeUninit;
-pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0));
-//~^ ERROR: encountered static that tried to initialize itself with itself
+pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0, 1));
+//~^ ERROR: encountered static that tried to access itself during initialization
+pub static Y: (i32, MaybeUninit<i32>) = (1, foo(&Y.0, 0));
+//~^ ERROR: encountered static that tried to access itself during initialization
-const fn foo(x: &i32) -> MaybeUninit<i32> {
+const fn foo(x: &i32, num: usize) -> MaybeUninit<i32> {
let mut temp = MaybeUninit::<i32>::uninit();
unsafe {
- std::ptr::copy(x, temp.as_mut_ptr(), 1);
+ std::ptr::copy(x, temp.as_mut_ptr(), num);
}
temp
}
diff --git a/tests/ui/statics/read_before_init.stderr b/tests/ui/statics/read_before_init.stderr
index aeebcf7..239568c 100644
--- a/tests/ui/statics/read_before_init.stderr
+++ b/tests/ui/statics/read_before_init.stderr
@@ -1,17 +1,31 @@
-error[E0080]: encountered static that tried to initialize itself with itself
+error[E0080]: encountered static that tried to access itself during initialization
--> $DIR/read_before_init.rs:11:45
|
-LL | pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0));
- | ^^^^^^^^^ evaluation of `X` failed inside this call
+LL | pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0, 1));
+ | ^^^^^^^^^^^^ evaluation of `X` failed inside this call
|
note: inside `foo`
- --> $DIR/read_before_init.rs:17:9
+ --> $DIR/read_before_init.rs:19:9
|
-LL | std::ptr::copy(x, temp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | std::ptr::copy(x, temp.as_mut_ptr(), num);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `std::ptr::copy::<i32>`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-error: aborting due to 1 previous error
+error[E0080]: encountered static that tried to access itself during initialization
+ --> $DIR/read_before_init.rs:13:45
+ |
+LL | pub static Y: (i32, MaybeUninit<i32>) = (1, foo(&Y.0, 0));
+ | ^^^^^^^^^^^^ evaluation of `Y` failed inside this call
+ |
+note: inside `foo`
+ --> $DIR/read_before_init.rs:19:9
+ |
+LL | std::ptr::copy(x, temp.as_mut_ptr(), num);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `std::ptr::copy::<i32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/statics/static-generic-param-soundness.rs b/tests/ui/statics/static-generic-param-soundness.rs
new file mode 100644
index 0000000..aabcca51
--- /dev/null
+++ b/tests/ui/statics/static-generic-param-soundness.rs
@@ -0,0 +1,20 @@
+//! Originally, inner statics in generic functions were generated only once, causing the same
+//! static to be shared across all generic instantiations. This created a soundness hole where
+//! different types could be coerced through thread-local storage in safe code.
+//!
+//! This test checks that generic parameters from outer scopes cannot be used in inner statics,
+//! preventing this soundness issue.
+//!
+//! See https://github.com/rust-lang/rust/issues/9186
+
+enum Bar<T> {
+ //~^ ERROR parameter `T` is never used
+ What,
+}
+
+fn foo<T>() {
+ static a: Bar<T> = Bar::What;
+ //~^ ERROR can't use generic parameters from outer item
+}
+
+fn main() {}
diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/statics/static-generic-param-soundness.stderr
similarity index 85%
rename from tests/ui/inner-static-type-parameter.stderr
rename to tests/ui/statics/static-generic-param-soundness.stderr
index 88d33b4..47554c7 100644
--- a/tests/ui/inner-static-type-parameter.stderr
+++ b/tests/ui/statics/static-generic-param-soundness.stderr
@@ -1,5 +1,5 @@
error[E0401]: can't use generic parameters from outer item
- --> $DIR/inner-static-type-parameter.rs:6:19
+ --> $DIR/static-generic-param-soundness.rs:16:19
|
LL | fn foo<T>() {
| - type parameter from outer item
@@ -9,9 +9,9 @@
= note: a `static` is a separate item from the item that contains it
error[E0392]: type parameter `T` is never used
- --> $DIR/inner-static-type-parameter.rs:3:10
+ --> $DIR/static-generic-param-soundness.rs:10:10
|
-LL | enum Bar<T> { What }
+LL | enum Bar<T> {
| ^ unused type parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.rs b/tests/ui/structs-enums/recover-enum-with-bad-where.rs
new file mode 100644
index 0000000..cf7747d
--- /dev/null
+++ b/tests/ui/structs-enums/recover-enum-with-bad-where.rs
@@ -0,0 +1,8 @@
+pub enum Foo<T>
+where:
+//~^ ERROR unexpected colon after `where`
+ T: Missing, {}
+//~^ ERROR cannot find trait `Missing` in this scope
+// (evidence that we continue parsing after the erroneous colon)
+
+fn main() {}
diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.stderr b/tests/ui/structs-enums/recover-enum-with-bad-where.stderr
new file mode 100644
index 0000000..30b73f5
--- /dev/null
+++ b/tests/ui/structs-enums/recover-enum-with-bad-where.stderr
@@ -0,0 +1,15 @@
+error: unexpected colon after `where`
+ --> $DIR/recover-enum-with-bad-where.rs:2:6
+ |
+LL | where:
+ | ^ help: remove the colon
+
+error[E0405]: cannot find trait `Missing` in this scope
+ --> $DIR/recover-enum-with-bad-where.rs:4:8
+ |
+LL | T: Missing, {}
+ | ^^^^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.stderr b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr
index 68d8f54..8b7d67a 100644
--- a/tests/ui/suggestions/bad-infer-in-trait-impl.stderr
+++ b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr
@@ -3,12 +3,6 @@
|
LL | fn bar(s: _) {}
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn bar(s: _) {}
-LL + fn bar<T>(s: T) {}
- |
error[E0050]: method `bar` has 1 parameter but the declaration in trait `Foo::bar` has 0
--> $DIR/bad-infer-in-trait-impl.rs:6:15
diff --git a/tests/ui/test-attrs/test-function-elided-no-main.rs b/tests/ui/test-attrs/test-function-elided-no-main.rs
new file mode 100644
index 0000000..9765458
--- /dev/null
+++ b/tests/ui/test-attrs/test-function-elided-no-main.rs
@@ -0,0 +1,8 @@
+//! Test that #[test] functions are elided when not running tests, causing missing main error
+
+#[test]
+fn main() {
+ // This function would normally serve as main, but since it's marked with #[test],
+ // it gets elided when not running tests
+}
+//~^ ERROR `main` function not found in crate `test_function_elided_no_main`
diff --git a/tests/ui/test-attrs/test-function-elided-no-main.stderr b/tests/ui/test-attrs/test-function-elided-no-main.stderr
new file mode 100644
index 0000000..0bae690
--- /dev/null
+++ b/tests/ui/test-attrs/test-function-elided-no-main.stderr
@@ -0,0 +1,9 @@
+error[E0601]: `main` function not found in crate `test_function_elided_no_main`
+ --> $DIR/test-function-elided-no-main.rs:7:2
+ |
+LL | }
+ | ^ consider adding a `main` function to `$DIR/test-function-elided-no-main.rs`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
index 9141d32..ff1ce94 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
@@ -6,15 +6,15 @@
#[const_trait]
trait Trait {
- type Assoc: ~const Trait;
+ type Assoc: [const] Trait;
fn func() -> i32;
}
-const fn unqualified<T: ~const Trait>() -> i32 {
+const fn unqualified<T: [const] Trait>() -> i32 {
T::Assoc::func()
}
-const fn qualified<T: ~const Trait>() -> i32 {
+const fn qualified<T: [const] Trait>() -> i32 {
<T as Trait>::Assoc::func()
}
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
index 19e86b5..5773f22 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
@@ -5,7 +5,7 @@
#[const_trait]
trait Trait {
- type Assoc: ~const Trait;
+ type Assoc: [const] Trait;
fn func() -> i32;
}
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr
index 4cd8700..a0474e6 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr
@@ -1,10 +1,10 @@
-error[E0277]: the trait bound `U: ~const Other` is not satisfied
+error[E0277]: the trait bound `U: [const] Other` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5
|
LL | T::Assoc::<U>::func();
| ^^^^^^^^^^^^^
-error[E0277]: the trait bound `U: ~const Other` is not satisfied
+error[E0277]: the trait bound `U: [const] Other` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5
|
LL | <T as Trait>::Assoc::<U>::func();
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr
index 4cd8700..a0474e6 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr
@@ -1,10 +1,10 @@
-error[E0277]: the trait bound `U: ~const Other` is not satisfied
+error[E0277]: the trait bound `U: [const] Other` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5
|
LL | T::Assoc::<U>::func();
| ^^^^^^^^^^^^^
-error[E0277]: the trait bound `U: ~const Other` is not satisfied
+error[E0277]: the trait bound `U: [const] Other` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5
|
LL | <T as Trait>::Assoc::<U>::func();
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs
index e1c30b5..5338c27 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs
@@ -1,7 +1,7 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
-// Check that `~const` item bounds only hold if the where clauses on the
+// Check that `[const]` item bounds only hold if the where clauses on the
// associated type are also const.
// i.e. check that we validate the const conditions for the associated type
// when considering one of implied const bounds.
@@ -10,9 +10,9 @@
#[const_trait]
trait Trait {
- type Assoc<U>: ~const Trait
+ type Assoc<U>: [const] Trait
where
- U: ~const Other;
+ U: [const] Other;
fn func();
}
@@ -20,14 +20,14 @@ trait Trait {
#[const_trait]
trait Other {}
-const fn fails<T: ~const Trait, U: Other>() {
+const fn fails<T: [const] Trait, U: Other>() {
T::Assoc::<U>::func();
- //~^ ERROR the trait bound `U: ~const Other` is not satisfied
+ //~^ ERROR the trait bound `U: [const] Other` is not satisfied
<T as Trait>::Assoc::<U>::func();
- //~^ ERROR the trait bound `U: ~const Other` is not satisfied
+ //~^ ERROR the trait bound `U: [const] Other` is not satisfied
}
-const fn works<T: ~const Trait, U: ~const Other>() {
+const fn works<T: [const] Trait, U: [const] Other>() {
T::Assoc::<U>::func();
<T as Trait>::Assoc::<U>::func();
}
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr
index 9c29a89..20b01d0 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr
@@ -1,10 +1,10 @@
-error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+error[E0277]: the trait bound `T: [const] Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail.rs:17:5
|
LL | T::Assoc::func();
| ^^^^^^^^
-error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+error[E0277]: the trait bound `T: [const] Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail.rs:19:5
|
LL | <T as Trait>::Assoc::func();
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr
index 9c29a89..20b01d0 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr
@@ -1,10 +1,10 @@
-error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+error[E0277]: the trait bound `T: [const] Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail.rs:17:5
|
LL | T::Assoc::func();
| ^^^^^^^^
-error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+error[E0277]: the trait bound `T: [const] Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail.rs:19:5
|
LL | <T as Trait>::Assoc::func();
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs
index 3761fea..4940b3a 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs
@@ -1,7 +1,7 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
-// Check that `~const` item bounds only hold if the parent trait is `~const`.
+// Check that `[const]` item bounds only hold if the parent trait is `[const]`.
// i.e. check that we validate the const conditions for the associated type
// when considering one of implied const bounds.
@@ -9,18 +9,18 @@
#[const_trait]
trait Trait {
- type Assoc: ~const Trait;
+ type Assoc: [const] Trait;
fn func();
}
const fn unqualified<T: Trait>() {
T::Assoc::func();
- //~^ ERROR the trait bound `T: ~const Trait` is not satisfied
+ //~^ ERROR the trait bound `T: [const] Trait` is not satisfied
<T as Trait>::Assoc::func();
- //~^ ERROR the trait bound `T: ~const Trait` is not satisfied
+ //~^ ERROR the trait bound `T: [const] Trait` is not satisfied
}
-const fn works<T: ~const Trait>() {
+const fn works<T: [const] Trait>() {
T::Assoc::func();
<T as Trait>::Assoc::func();
}
diff --git a/tests/ui/traits/const-traits/assoc-type.current.stderr b/tests/ui/traits/const-traits/assoc-type.current.stderr
index 7526369..1e58efe 100644
--- a/tests/ui/traits/const-traits/assoc-type.current.stderr
+++ b/tests/ui/traits/const-traits/assoc-type.current.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied
+error[E0277]: the trait bound `NonConstAdd: [const] Add` is not satisfied
--> $DIR/assoc-type.rs:37:16
|
LL | type Bar = NonConstAdd;
@@ -7,8 +7,8 @@
note: required by a bound in `Foo::Bar`
--> $DIR/assoc-type.rs:33:15
|
-LL | type Bar: ~const Add;
- | ^^^^^^^^^^ required by this bound in `Foo::Bar`
+LL | type Bar: [const] Add;
+ | ^^^^^^^^^^^ required by this bound in `Foo::Bar`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/assoc-type.next.stderr b/tests/ui/traits/const-traits/assoc-type.next.stderr
index 7526369..1e58efe 100644
--- a/tests/ui/traits/const-traits/assoc-type.next.stderr
+++ b/tests/ui/traits/const-traits/assoc-type.next.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied
+error[E0277]: the trait bound `NonConstAdd: [const] Add` is not satisfied
--> $DIR/assoc-type.rs:37:16
|
LL | type Bar = NonConstAdd;
@@ -7,8 +7,8 @@
note: required by a bound in `Foo::Bar`
--> $DIR/assoc-type.rs:33:15
|
-LL | type Bar: ~const Add;
- | ^^^^^^^^^^ required by this bound in `Foo::Bar`
+LL | type Bar: [const] Add;
+ | ^^^^^^^^^^^ required by this bound in `Foo::Bar`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/assoc-type.rs b/tests/ui/traits/const-traits/assoc-type.rs
index a169b61..1faef1b 100644
--- a/tests/ui/traits/const-traits/assoc-type.rs
+++ b/tests/ui/traits/const-traits/assoc-type.rs
@@ -30,12 +30,12 @@ fn add(self, rhs: Self) -> Self {
#[const_trait]
trait Foo {
- type Bar: ~const Add;
+ type Bar: [const] Add;
}
impl const Foo for NonConstAdd {
type Bar = NonConstAdd;
- //~^ ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied
+ //~^ ERROR the trait bound `NonConstAdd: [const] Add` is not satisfied
}
#[const_trait]
diff --git a/tests/ui/traits/const-traits/auxiliary/minicore.rs b/tests/ui/traits/const-traits/auxiliary/minicore.rs
index 073337b..d2133bb 100644
--- a/tests/ui/traits/const-traits/auxiliary/minicore.rs
+++ b/tests/ui/traits/const-traits/auxiliary/minicore.rs
@@ -86,14 +86,14 @@ enum ControlFlow<B, C = ()> {
#[const_trait]
#[lang = "fn"]
#[rustc_paren_sugar]
-pub trait Fn<Args: Tuple>: ~const FnMut<Args> {
+pub trait Fn<Args: Tuple>: [const] FnMut<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
#[const_trait]
#[lang = "fn_mut"]
#[rustc_paren_sugar]
-pub trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
+pub trait FnMut<Args: Tuple>: [const] FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
@@ -142,7 +142,7 @@ pub trait Drop {
#[const_trait]
pub trait Residual<O> {
- type TryType: ~const Try<Output = O, Residual = Self> + Try<Output = O, Residual = Self>;
+ type TryType: [const] Try<Output = O, Residual = Self> + Try<Output = O, Residual = Self>;
}
const fn size_of<T>() -> usize {
@@ -183,7 +183,7 @@ pub unsafe trait SliceIndex<T: PointeeSized> {
impl<T, I> const Index<I> for [T]
where
- I: ~const SliceIndex<[T]>,
+ I: [const] SliceIndex<[T]>,
{
type Output = I::Output;
@@ -195,7 +195,7 @@ fn index(&self, index: I) -> &I::Output {
impl<T, I, const N: usize> const Index<I> for [T; N]
where
- [T]: ~const Index<I>,
+ [T]: [const] Index<I>,
{
type Output = <[T] as Index<I>>::Output;
@@ -265,7 +265,7 @@ const fn as_mut(&mut self) -> Option<&mut T> {
const fn as_deref<T>(opt: &Option<T>) -> Option<&T::Target>
where
- T: ~const Deref,
+ T: [const] Deref,
{
match opt {
Option::Some(t) => Option::Some(t.deref()),
@@ -285,7 +285,7 @@ pub trait From<T>: Sized {
impl<T, U> const Into<U> for T
where
- U: ~const From<T>,
+ U: [const] From<T>,
{
fn into(self) -> U {
U::from(self)
@@ -323,7 +323,7 @@ fn ne(&self, other: &Rhs) -> bool {
impl<A: PointeeSized, B: PointeeSized> const PartialEq<&B> for &A
where
- A: ~const PartialEq<B>,
+ A: [const] PartialEq<B>,
{
fn eq(&self, other: &&B) -> bool {
PartialEq::eq(*self, *other)
@@ -373,7 +373,7 @@ const fn get_ref(self) -> &'a T {
impl<P: Deref> Pin<P> {
const fn as_ref(&self) -> Pin<&P::Target>
where
- P: ~const Deref,
+ P: [const] Deref,
{
unsafe { Pin::new_unchecked(&*self.pointer) }
}
@@ -403,7 +403,7 @@ const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
}
}
-impl<P: ~const Deref> const Deref for Pin<P> {
+impl<P: [const] Deref> const Deref for Pin<P> {
type Target = P::Target;
fn deref(&self) -> &P::Target {
Pin::get_ref(Pin::as_ref(self))
@@ -467,7 +467,7 @@ pub trait Clone: Sized {
fn clone(&self) -> Self;
fn clone_from(&mut self, source: &Self)
where
- Self: ~const Destruct,
+ Self: [const] Destruct,
{
*self = source.clone()
}
@@ -476,7 +476,7 @@ fn clone_from(&mut self, source: &Self)
#[lang = "structural_peq"]
pub trait StructuralPartialEq {}
-pub const fn drop<T: ~const Destruct>(_: T) {}
+pub const fn drop<T: [const] Destruct>(_: T) {}
#[rustc_intrinsic]
const fn const_eval_select<ARG: Tuple, F, G, RET>(
diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs
index 21f4374..70dfaf7 100644
--- a/tests/ui/traits/const-traits/call-const-closure.rs
+++ b/tests/ui/traits/const-traits/call-const-closure.rs
@@ -15,7 +15,7 @@ fn foo(&self) {}
const FOO: () = {
(const || ().foo())();
- //~^ ERROR the trait bound `(): ~const Bar` is not satisfied
+ //~^ ERROR the trait bound `(): [const] Bar` is not satisfied
// FIXME(const_trait_impl): The constness environment for const closures is wrong.
};
diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.stderr
index fe7c115..4bb8b2e 100644
--- a/tests/ui/traits/const-traits/call-const-closure.stderr
+++ b/tests/ui/traits/const-traits/call-const-closure.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `(): ~const Bar` is not satisfied
+error[E0277]: the trait bound `(): [const] Bar` is not satisfied
--> $DIR/call-const-closure.rs:17:18
|
LL | (const || ().foo())();
diff --git a/tests/ui/traits/const-traits/call-const-in-tilde-const.rs b/tests/ui/traits/const-traits/call-const-in-conditionally-const.rs
similarity index 86%
rename from tests/ui/traits/const-traits/call-const-in-tilde-const.rs
rename to tests/ui/traits/const-traits/call-const-in-conditionally-const.rs
index b6d1517..4e8c2cd 100644
--- a/tests/ui/traits/const-traits/call-const-in-tilde-const.rs
+++ b/tests/ui/traits/const-traits/call-const-in-conditionally-const.rs
@@ -5,7 +5,7 @@
fn foo();
}
-const fn foo<T: ~const Foo>() {
+const fn foo<T: [const] Foo>() {
const { T::foo() }
//~^ ERROR the trait bound `T: const Foo` is not satisfied
}
diff --git a/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr b/tests/ui/traits/const-traits/call-const-in-conditionally-const.stderr
similarity index 80%
rename from tests/ui/traits/const-traits/call-const-in-tilde-const.stderr
rename to tests/ui/traits/const-traits/call-const-in-conditionally-const.stderr
index b9dabce..f14b640 100644
--- a/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr
+++ b/tests/ui/traits/const-traits/call-const-in-conditionally-const.stderr
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `T: const Foo` is not satisfied
- --> $DIR/call-const-in-tilde-const.rs:9:13
+ --> $DIR/call-const-in-conditionally-const.rs:9:13
|
LL | const { T::foo() }
| ^
diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.rs b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs
index e06d04d..c03d3e9 100644
--- a/tests/ui/traits/const-traits/call-const-trait-method-fail.rs
+++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs
@@ -24,7 +24,7 @@ pub const fn add_i32(a: i32, b: i32) -> i32 {
pub const fn add_u32(a: u32, b: u32) -> u32 {
a.plus(b)
- //~^ ERROR the trait bound `u32: ~const Plus`
+ //~^ ERROR the trait bound `u32: [const] Plus`
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
index 6485033..4aaf533 100644
--- a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
+error[E0277]: the trait bound `u32: [const] Plus` is not satisfied
--> $DIR/call-const-trait-method-fail.rs:26:5
|
LL | a.plus(b)
diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.rs b/tests/ui/traits/const-traits/call-generic-in-impl.rs
index b63458b..f38590f 100644
--- a/tests/ui/traits/const-traits/call-generic-in-impl.rs
+++ b/tests/ui/traits/const-traits/call-generic-in-impl.rs
@@ -6,7 +6,7 @@ trait MyPartialEq {
fn eq(&self, other: &Self) -> bool;
}
-impl<T: ~const PartialEq> const MyPartialEq for T {
+impl<T: [const] PartialEq> const MyPartialEq for T {
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(self, other)
}
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.rs b/tests/ui/traits/const-traits/call-generic-method-chain.rs
index b515c0e..1ad71c4 100644
--- a/tests/ui/traits/const-traits/call-generic-method-chain.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.rs
@@ -16,11 +16,11 @@ fn ne(&self, other: &S) -> bool {
}
}
-const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+const fn equals_self<T: [const] PartialEq>(t: &T) -> bool {
*t == *t
}
-const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
+const fn equals_self_wrapper<T: [const] PartialEq>(t: &T) -> bool {
equals_self(t)
}
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
index fdc4398..58f293b 100644
--- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
@@ -14,16 +14,16 @@ fn ne(&self, other: &S) -> bool {
}
}
-// This duplicate bound should not result in ambiguities. It should be equivalent to a single ~const
-// bound.
-const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
+// This duplicate bound should not result in ambiguities.
+// It should be equivalent to a single [const] bound.
+const fn equals_self<T: PartialEq + [const] PartialEq>(t: &T) -> bool {
*t == *t
}
trait A: PartialEq {}
impl<T: PartialEq> A for T {}
-const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
+const fn equals_self2<T: A + [const] PartialEq>(t: &T) -> bool {
*t == *t
}
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.rs b/tests/ui/traits/const-traits/call-generic-method-fail.rs
index 3ab5cc5..4528f3b 100644
--- a/tests/ui/traits/const-traits/call-generic-method-fail.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.rs
@@ -3,7 +3,7 @@
pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
*t == *t
- //~^ ERROR the trait bound `T: ~const PartialEq` is not satisfied
+ //~^ ERROR the trait bound `T: [const] PartialEq` is not satisfied
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
index 9facf80..a2fba14 100644
--- a/tests/ui/traits/const-traits/call-generic-method-fail.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `T: ~const PartialEq` is not satisfied
+error[E0277]: the trait bound `T: [const] PartialEq` is not satisfied
--> $DIR/call-generic-method-fail.rs:5:5
|
LL | *t == *t
diff --git a/tests/ui/traits/const-traits/call-generic-method-nonconst.rs b/tests/ui/traits/const-traits/call-generic-method-nonconst.rs
index 446a74e..0efc8a9 100644
--- a/tests/ui/traits/const-traits/call-generic-method-nonconst.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-nonconst.rs
@@ -14,7 +14,7 @@ fn eq(&self, _: &S) -> bool {
}
}
-const fn equals_self<T: ~const Foo>(t: &T) -> bool {
+const fn equals_self<T: [const] Foo>(t: &T) -> bool {
true
}
diff --git a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
index 11bbe8b..9c1e0fe 100644
--- a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
@@ -9,8 +9,8 @@
note: required by a bound in `equals_self`
--> $DIR/call-generic-method-nonconst.rs:17:25
|
-LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool {
- | ^^^^^^^^^^ required by this bound in `equals_self`
+LL | const fn equals_self<T: [const] Foo>(t: &T) -> bool {
+ | ^^^^^^^^^^^ required by this bound in `equals_self`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.rs b/tests/ui/traits/const-traits/call-generic-method-pass.rs
index bc671c8..aa52a7b 100644
--- a/tests/ui/traits/const-traits/call-generic-method-pass.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.rs
@@ -16,7 +16,7 @@ fn ne(&self, other: &S) -> bool {
}
}
-const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+const fn equals_self<T: [const] PartialEq>(t: &T) -> bool {
*t == *t
}
diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs b/tests/ui/traits/const-traits/conditionally-const-and-const-params.rs
similarity index 71%
rename from tests/ui/traits/const-traits/tilde-const-and-const-params.rs
rename to tests/ui/traits/const-traits/conditionally-const-and-const-params.rs
index 428223d..2955388 100644
--- a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
+++ b/tests/ui/traits/const-traits/conditionally-const-and-const-params.rs
@@ -5,8 +5,8 @@
struct Foo<const N: usize>;
impl<const N: usize> Foo<N> {
- fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
- //~^ ERROR `~const` is not allowed here
+ fn add<A: [const] Add42>(self) -> Foo<{ A::add(N) }> {
+ //~^ ERROR `[const]` is not allowed here
//~| ERROR the trait bound `A: const Add42` is not satisfied
Foo
}
@@ -23,8 +23,8 @@ fn add(a: usize) -> usize {
}
}
-fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
- //~^ ERROR `~const` is not allowed here
+fn bar<A: [const] Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+ //~^ ERROR `[const]` is not allowed here
//~| ERROR the trait bound `A: const Add42` is not satisfied
Foo
}
diff --git a/tests/ui/traits/const-traits/conditionally-const-and-const-params.stderr b/tests/ui/traits/const-traits/conditionally-const-and-const-params.stderr
new file mode 100644
index 0000000..ebd816a
--- /dev/null
+++ b/tests/ui/traits/const-traits/conditionally-const-and-const-params.stderr
@@ -0,0 +1,39 @@
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-and-const-params.rs:8:15
+ |
+LL | fn add<A: [const] Add42>(self) -> Foo<{ A::add(N) }> {
+ | ^^^^^^^
+ |
+note: this function is not `const`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-and-const-params.rs:8:8
+ |
+LL | fn add<A: [const] Add42>(self) -> Foo<{ A::add(N) }> {
+ | ^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-and-const-params.rs:26:11
+ |
+LL | fn bar<A: [const] Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+ | ^^^^^^^
+ |
+note: this function is not `const`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-and-const-params.rs:26:4
+ |
+LL | fn bar<A: [const] Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+ | ^^^
+
+error[E0277]: the trait bound `A: const Add42` is not satisfied
+ --> $DIR/conditionally-const-and-const-params.rs:26:62
+ |
+LL | fn bar<A: [const] Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+ | ^
+
+error[E0277]: the trait bound `A: const Add42` is not satisfied
+ --> $DIR/conditionally-const-and-const-params.rs:8:45
+ |
+LL | fn add<A: [const] Add42>(self) -> Foo<{ A::add(N) }> {
+ | ^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/tilde-const-assoc-fn-in-trait-impl.rs b/tests/ui/traits/const-traits/conditionally-const-assoc-fn-in-trait-impl.rs
similarity index 83%
rename from tests/ui/traits/const-traits/tilde-const-assoc-fn-in-trait-impl.rs
rename to tests/ui/traits/const-traits/conditionally-const-assoc-fn-in-trait-impl.rs
index 73b2bdc..7f01c0b 100644
--- a/tests/ui/traits/const-traits/tilde-const-assoc-fn-in-trait-impl.rs
+++ b/tests/ui/traits/const-traits/conditionally-const-assoc-fn-in-trait-impl.rs
@@ -5,11 +5,11 @@
#[const_trait]
trait Main {
- fn compute<T: ~const Aux>() -> u32;
+ fn compute<T: [const] Aux>() -> u32;
}
impl const Main for () {
- fn compute<T: ~const Aux>() -> u32 {
+ fn compute<T: [const] Aux>() -> u32 {
T::generate()
}
}
diff --git a/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs b/tests/ui/traits/const-traits/conditionally-const-in-struct-args.rs
similarity index 84%
rename from tests/ui/traits/const-traits/tilde-const-in-struct-args.rs
rename to tests/ui/traits/const-traits/conditionally-const-in-struct-args.rs
index e7ec3d3..0c64469 100644
--- a/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs
+++ b/tests/ui/traits/const-traits/conditionally-const-in-struct-args.rs
@@ -11,7 +11,7 @@ trait Trait<const N: u32> {}
const fn f<
T: Trait<
{
- struct I<U: ~const Trait<0>>(U);
+ struct I<U: [const] Trait<0>>(U);
0
},
>,
diff --git a/tests/ui/traits/const-traits/tilde-const-inherent-assoc-const-fn.rs b/tests/ui/traits/const-traits/conditionally-const-inherent-assoc-const-fn.rs
similarity index 81%
rename from tests/ui/traits/const-traits/tilde-const-inherent-assoc-const-fn.rs
rename to tests/ui/traits/const-traits/conditionally-const-inherent-assoc-const-fn.rs
index 0e01069..56478a6 100644
--- a/tests/ui/traits/const-traits/tilde-const-inherent-assoc-const-fn.rs
+++ b/tests/ui/traits/const-traits/conditionally-const-inherent-assoc-const-fn.rs
@@ -10,7 +10,7 @@ fn foo(&self) {}
struct Bar<T>(T);
impl<T> Bar<T> {
- const fn foo(&self) where T: ~const Foo {
+ const fn foo(&self) where T: [const] Foo {
self.0.foo()
}
}
diff --git a/tests/ui/traits/const-traits/conditionally-const-invalid-places.rs b/tests/ui/traits/const-traits/conditionally-const-invalid-places.rs
new file mode 100644
index 0000000..5262700
--- /dev/null
+++ b/tests/ui/traits/const-traits/conditionally-const-invalid-places.rs
@@ -0,0 +1,61 @@
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Trait {}
+
+// Regression test for issue #90052.
+fn non_const_function<T: [const] Trait>() {} //~ ERROR `[const]` is not allowed
+
+struct Struct<T: [const] Trait> { field: T } //~ ERROR `[const]` is not allowed here
+struct TupleStruct<T: [const] Trait>(T); //~ ERROR `[const]` is not allowed here
+struct UnitStruct<T: [const] Trait>; //~ ERROR `[const]` is not allowed here
+//~^ ERROR parameter `T` is never used
+
+enum Enum<T: [const] Trait> { Variant(T) } //~ ERROR `[const]` is not allowed here
+
+union Union<T: [const] Trait> { field: T } //~ ERROR `[const]` is not allowed here
+//~^ ERROR field must implement `Copy`
+
+type Type<T: [const] Trait> = T; //~ ERROR `[const]` is not allowed here
+
+const CONSTANT<T: [const] Trait>: () = (); //~ ERROR `[const]` is not allowed here
+//~^ ERROR generic const items are experimental
+
+trait NonConstTrait {
+ type Type<T: [const] Trait>: [const] Trait;
+ //~^ ERROR `[const]` is not allowed
+ //~| ERROR `[const]` is not allowed
+ fn non_const_function<T: [const] Trait>(); //~ ERROR `[const]` is not allowed
+ const CONSTANT<T: [const] Trait>: (); //~ ERROR `[const]` is not allowed
+ //~^ ERROR generic const items are experimental
+}
+
+impl NonConstTrait for () {
+ type Type<T: [const] Trait> = (); //~ ERROR `[const]` is not allowed
+ //~^ ERROR overflow evaluating the requirement `(): Trait`
+ fn non_const_function<T: [const] Trait>() {} //~ ERROR `[const]` is not allowed
+ const CONSTANT<T: [const] Trait>: () = (); //~ ERROR `[const]` is not allowed
+ //~^ ERROR generic const items are experimental
+}
+
+struct Implementor;
+
+impl Implementor {
+ type Type<T: [const] Trait> = (); //~ ERROR `[const]` is not allowed
+ //~^ ERROR inherent associated types are unstable
+ fn non_const_function<T: [const] Trait>() {} //~ ERROR `[const]` is not allowed
+ const CONSTANT<T: [const] Trait>: () = (); //~ ERROR `[const]` is not allowed
+ //~^ ERROR generic const items are experimental
+}
+
+// non-const traits
+trait Child0: [const] Trait {} //~ ERROR `[const]` is not allowed
+trait Child1 where Self: [const] Trait {} //~ ERROR `[const]` is not allowed
+
+// non-const impl
+impl<T: [const] Trait> Trait for T {} //~ ERROR `[const]` is not allowed
+
+// inherent impl (regression test for issue #117004)
+impl<T: [const] Trait> Struct<T> {} //~ ERROR `[const]` is not allowed
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr
new file mode 100644
index 0000000..d0dd950
--- /dev/null
+++ b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr
@@ -0,0 +1,310 @@
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:7:26
+ |
+LL | fn non_const_function<T: [const] Trait>() {}
+ | ^^^^^^^
+ |
+note: this function is not `const`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:7:4
+ |
+LL | fn non_const_function<T: [const] Trait>() {}
+ | ^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:9:18
+ |
+LL | struct Struct<T: [const] Trait> { field: T }
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:10:23
+ |
+LL | struct TupleStruct<T: [const] Trait>(T);
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:11:22
+ |
+LL | struct UnitStruct<T: [const] Trait>;
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:14:14
+ |
+LL | enum Enum<T: [const] Trait> { Variant(T) }
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:16:16
+ |
+LL | union Union<T: [const] Trait> { field: T }
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:19:14
+ |
+LL | type Type<T: [const] Trait> = T;
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:21:19
+ |
+LL | const CONSTANT<T: [const] Trait>: () = ();
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:25:18
+ |
+LL | type Type<T: [const] Trait>: [const] Trait;
+ | ^^^^^^^
+ |
+note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:25:5
+ |
+LL | type Type<T: [const] Trait>: [const] Trait;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:25:34
+ |
+LL | type Type<T: [const] Trait>: [const] Trait;
+ | ^^^^^^^
+ |
+note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:25:5
+ |
+LL | type Type<T: [const] Trait>: [const] Trait;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:28:30
+ |
+LL | fn non_const_function<T: [const] Trait>();
+ | ^^^^^^^
+ |
+note: this function is not `const`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:28:8
+ |
+LL | fn non_const_function<T: [const] Trait>();
+ | ^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:29:23
+ |
+LL | const CONSTANT<T: [const] Trait>: ();
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:34:18
+ |
+LL | type Type<T: [const] Trait> = ();
+ | ^^^^^^^
+ |
+note: associated types in non-const impls cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:34:5
+ |
+LL | type Type<T: [const] Trait> = ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:36:30
+ |
+LL | fn non_const_function<T: [const] Trait>() {}
+ | ^^^^^^^
+ |
+note: this function is not `const`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:36:8
+ |
+LL | fn non_const_function<T: [const] Trait>() {}
+ | ^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:37:23
+ |
+LL | const CONSTANT<T: [const] Trait>: () = ();
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:44:18
+ |
+LL | type Type<T: [const] Trait> = ();
+ | ^^^^^^^
+ |
+note: inherent associated types cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:44:5
+ |
+LL | type Type<T: [const] Trait> = ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:46:30
+ |
+LL | fn non_const_function<T: [const] Trait>() {}
+ | ^^^^^^^
+ |
+note: this function is not `const`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:46:8
+ |
+LL | fn non_const_function<T: [const] Trait>() {}
+ | ^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:47:23
+ |
+LL | const CONSTANT<T: [const] Trait>: () = ();
+ | ^^^^^^^
+ |
+ = note: this item cannot have `[const]` trait bounds
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:52:15
+ |
+LL | trait Child0: [const] Trait {}
+ | ^^^^^^^
+ |
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:52:1
+ |
+LL | trait Child0: [const] Trait {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:53:26
+ |
+LL | trait Child1 where Self: [const] Trait {}
+ | ^^^^^^^
+ |
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:53:1
+ |
+LL | trait Child1 where Self: [const] Trait {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:56:9
+ |
+LL | impl<T: [const] Trait> Trait for T {}
+ | ^^^^^^^
+ |
+note: this impl is not `const`, so it cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:56:1
+ |
+LL | impl<T: [const] Trait> Trait for T {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `[const]` is not allowed here
+ --> $DIR/conditionally-const-invalid-places.rs:59:9
+ |
+LL | impl<T: [const] Trait> Struct<T> {}
+ | ^^^^^^^
+ |
+note: inherent impls cannot have `[const]` trait bounds
+ --> $DIR/conditionally-const-invalid-places.rs:59:1
+ |
+LL | impl<T: [const] Trait> Struct<T> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: generic const items are experimental
+ --> $DIR/conditionally-const-invalid-places.rs:21:15
+ |
+LL | const CONSTANT<T: [const] Trait>: () = ();
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
+ = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: generic const items are experimental
+ --> $DIR/conditionally-const-invalid-places.rs:29:19
+ |
+LL | const CONSTANT<T: [const] Trait>: ();
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
+ = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: generic const items are experimental
+ --> $DIR/conditionally-const-invalid-places.rs:37:19
+ |
+LL | const CONSTANT<T: [const] Trait>: () = ();
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
+ = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: generic const items are experimental
+ --> $DIR/conditionally-const-invalid-places.rs:47:19
+ |
+LL | const CONSTANT<T: [const] Trait>: () = ();
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
+ = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0392]: type parameter `T` is never used
+ --> $DIR/conditionally-const-invalid-places.rs:11:19
+ |
+LL | struct UnitStruct<T: [const] Trait>;
+ | ^ unused type parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+ --> $DIR/conditionally-const-invalid-places.rs:16:33
+ |
+LL | union Union<T: [const] Trait> { field: T }
+ | ^^^^^^^^
+ |
+ = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+ |
+LL | union Union<T: [const] Trait> { field: std::mem::ManuallyDrop<T> }
+ | +++++++++++++++++++++++ +
+
+error[E0275]: overflow evaluating the requirement `(): Trait`
+ --> $DIR/conditionally-const-invalid-places.rs:34:35
+ |
+LL | type Type<T: [const] Trait> = ();
+ | ^^
+ |
+note: required by a bound in `NonConstTrait::Type`
+ --> $DIR/conditionally-const-invalid-places.rs:25:34
+ |
+LL | type Type<T: [const] Trait>: [const] Trait;
+ | ^^^^^^^^^^^^^ required by this bound in `NonConstTrait::Type`
+
+error[E0658]: inherent associated types are unstable
+ --> $DIR/conditionally-const-invalid-places.rs:44:5
+ |
+LL | type Type<T: [const] Trait> = ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
+ = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 30 previous errors
+
+Some errors have detailed explanations: E0275, E0392, E0658, E0740.
+For more information about an error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/const-traits/tilde-const-trait-assoc-tys.rs b/tests/ui/traits/const-traits/conditionally-const-trait-bound-assoc-tys.rs
similarity index 71%
rename from tests/ui/traits/const-traits/tilde-const-trait-assoc-tys.rs
rename to tests/ui/traits/const-traits/conditionally-const-trait-bound-assoc-tys.rs
index 53ddb5c..b0bd846 100644
--- a/tests/ui/traits/const-traits/tilde-const-trait-assoc-tys.rs
+++ b/tests/ui/traits/const-traits/conditionally-const-trait-bound-assoc-tys.rs
@@ -4,11 +4,11 @@
#[const_trait]
trait Trait {
- type Assoc<T: ~const Bound>;
+ type Assoc<T: [const] Bound>;
}
impl const Trait for () {
- type Assoc<T: ~const Bound> = T;
+ type Assoc<T: [const] Bound> = T;
}
#[const_trait]
diff --git a/tests/ui/traits/const-traits/conditionally-const-trait-bound-syntax.rs b/tests/ui/traits/const-traits/conditionally-const-trait-bound-syntax.rs
new file mode 100644
index 0000000..89950c6
--- /dev/null
+++ b/tests/ui/traits/const-traits/conditionally-const-trait-bound-syntax.rs
@@ -0,0 +1,9 @@
+//@ compile-flags: -Z parse-crate-root-only
+//@ check-pass
+
+#![feature(const_trait_impl)]
+
+struct S<
+ T: for<'a> [const] Tr<'a> + 'static + [const] std::ops::Add,
+ T: for<'a: 'b> [const] m::Trait<'a>,
+>;
diff --git a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
index c735f85..9411127 100644
--- a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
+++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
@@ -8,8 +8,8 @@ trait MyTrait {
}
trait OtherTrait {
- fn do_something_else() where Self: ~const MyTrait;
- //~^ ERROR `~const` is not allowed here
+ fn do_something_else() where Self: [const] MyTrait;
+ //~^ ERROR `[const]` is not allowed here
}
struct MyStruct<T>(T);
@@ -19,8 +19,8 @@ fn do_something(&self) {}
}
impl<T> MyStruct<T> {
- pub fn foo(&self) where T: ~const MyTrait {
- //~^ ERROR `~const` is not allowed here
+ pub fn foo(&self) where T: [const] MyTrait {
+ //~^ ERROR `[const]` is not allowed here
self.0.do_something();
}
}
diff --git a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
index 50ab52a..901c2cb 100644
--- a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
+++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
@@ -1,25 +1,25 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/const-bound-on-not-const-associated-fn.rs:11:40
|
-LL | fn do_something_else() where Self: ~const MyTrait;
- | ^^^^^^
+LL | fn do_something_else() where Self: [const] MyTrait;
+ | ^^^^^^^
|
-note: this function is not `const`, so it cannot have `~const` trait bounds
+note: this function is not `const`, so it cannot have `[const]` trait bounds
--> $DIR/const-bound-on-not-const-associated-fn.rs:11:8
|
-LL | fn do_something_else() where Self: ~const MyTrait;
+LL | fn do_something_else() where Self: [const] MyTrait;
| ^^^^^^^^^^^^^^^^^
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/const-bound-on-not-const-associated-fn.rs:22:32
|
-LL | pub fn foo(&self) where T: ~const MyTrait {
- | ^^^^^^
+LL | pub fn foo(&self) where T: [const] MyTrait {
+ | ^^^^^^^
|
-note: this function is not `const`, so it cannot have `~const` trait bounds
+note: this function is not `const`, so it cannot have `[const]` trait bounds
--> $DIR/const-bound-on-not-const-associated-fn.rs:22:12
|
-LL | pub fn foo(&self) where T: ~const MyTrait {
+LL | pub fn foo(&self) where T: [const] MyTrait {
| ^^^
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
index e446eb1..ae31d9a 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
@@ -3,9 +3,9 @@
trait NonConst {}
-const fn perform<T: ~const NonConst>() {}
-//~^ ERROR `~const` can only be applied to `#[const_trait]` traits
-//~| ERROR `~const` can only be applied to `#[const_trait]` traits
+const fn perform<T: [const] NonConst>() {}
+//~^ ERROR `[const]` can only be applied to `#[const_trait]` traits
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
fn operate<T: const NonConst>() {}
//~^ ERROR `const` can only be applied to `#[const_trait]` traits
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
index f97d3a9..6c68e4e 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-bounds-non-const-trait.rs:6:21
|
-LL | const fn perform<T: ~const NonConst>() {}
- | ^^^^^^ can't be applied to `NonConst`
+LL | const fn perform<T: [const] NonConst>() {}
+ | ^^^^^^^ can't be applied to `NonConst`
|
help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
|
LL | #[const_trait] trait NonConst {}
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-bounds-non-const-trait.rs:6:21
|
-LL | const fn perform<T: ~const NonConst>() {}
- | ^^^^^^ can't be applied to `NonConst`
+LL | const fn perform<T: [const] NonConst>() {}
+ | ^^^^^^^ can't be applied to `NonConst`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs
index b1b0e68..35127ed 100644
--- a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs
@@ -4,7 +4,7 @@
#![feature(const_trait_impl, const_closures)]
#![allow(incomplete_features)]
-const fn test() -> impl ~const Fn() {
+const fn test() -> impl [const] Fn() {
const move || {}
}
diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
index 57afa22..fdfe3b9 100644
--- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
@@ -1,29 +1,29 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-parse-not-item.rs:7:25
|
-LL | const fn test() -> impl ~const Fn() {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn test() -> impl [const] Fn() {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-parse-not-item.rs:7:25
|
-LL | const fn test() -> impl ~const Fn() {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn test() -> impl [const] Fn() {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-parse-not-item.rs:7:25
|
-LL | const fn test() -> impl ~const Fn() {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn test() -> impl [const] Fn() {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.rs b/tests/ui/traits/const-traits/const-closure-trait-method-fail.rs
index 8c62864..cbcc4aa 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.rs
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.rs
@@ -11,7 +11,7 @@ impl Tr for () {
fn a(self) -> i32 { 42 }
}
-const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+const fn need_const_closure<T: [const] FnOnce(()) -> i32>(x: T) -> i32 {
x(())
}
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
index 2a97846..89b202b 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-trait-method-fail.rs:14:32
|
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
- | ^^^^^^ can't be applied to `FnOnce`
+LL | const fn need_const_closure<T: [const] FnOnce(()) -> i32>(x: T) -> i32 {
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-trait-method-fail.rs:14:32
|
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
- | ^^^^^^ can't be applied to `FnOnce`
+LL | const fn need_const_closure<T: [const] FnOnce(()) -> i32>(x: T) -> i32 {
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.rs b/tests/ui/traits/const-traits/const-closure-trait-method.rs
index ebee4da..831d6e2 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method.rs
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.rs
@@ -11,7 +11,7 @@ impl const Tr for () {
fn a(self) -> i32 { 42 }
}
-const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+const fn need_const_closure<T: [const] FnOnce(()) -> i32>(x: T) -> i32 {
x(())
}
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
index 9c63b7e..6de25dc 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-trait-method.rs:14:32
|
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
- | ^^^^^^ can't be applied to `FnOnce`
+LL | const fn need_const_closure<T: [const] FnOnce(()) -> i32>(x: T) -> i32 {
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-trait-method.rs:14:32
|
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
- | ^^^^^^ can't be applied to `FnOnce`
+LL | const fn need_const_closure<T: [const] FnOnce(()) -> i32>(x: T) -> i32 {
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/const-closures.rs b/tests/ui/traits/const-traits/const-closures.rs
index 98f8d03..2f6f4dc 100644
--- a/tests/ui/traits/const-traits/const-closures.rs
+++ b/tests/ui/traits/const-traits/const-closures.rs
@@ -5,9 +5,9 @@
const fn answer_p1<F>(f: &F) -> u8
where
- F: ~const FnOnce() -> u8,
- F: ~const FnMut() -> u8,
- F: ~const Fn() -> u8,
+ F: [const] FnOnce() -> u8,
+ F: [const] FnMut() -> u8,
+ F: [const] Fn() -> u8,
{
f() * 7
}
@@ -20,7 +20,7 @@ const fn answer_p2() -> u8 {
answer_p1(&three)
}
-const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
+const fn answer<F: [const] Fn() -> u8>(f: &F) -> u8 {
f() + f()
}
diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr
index 92f3ba2..19869b4 100644
--- a/tests/ui/traits/const-traits/const-closures.stderr
+++ b/tests/ui/traits/const-traits/const-closures.stderr
@@ -1,76 +1,76 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:8:12
|
-LL | F: ~const FnOnce() -> u8,
- | ^^^^^^ can't be applied to `FnOnce`
+LL | F: [const] FnOnce() -> u8,
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:9:12
|
-LL | F: ~const FnMut() -> u8,
- | ^^^^^^ can't be applied to `FnMut`
+LL | F: [const] FnMut() -> u8,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:10:12
|
-LL | F: ~const Fn() -> u8,
- | ^^^^^^ can't be applied to `Fn`
+LL | F: [const] Fn() -> u8,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:8:12
|
-LL | F: ~const FnOnce() -> u8,
- | ^^^^^^ can't be applied to `FnOnce`
+LL | F: [const] FnOnce() -> u8,
+ | ^^^^^^^ can't be applied to `FnOnce`
|
-note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:9:12
|
-LL | F: ~const FnMut() -> u8,
- | ^^^^^^ can't be applied to `FnMut`
+LL | F: [const] FnMut() -> u8,
+ | ^^^^^^^ can't be applied to `FnMut`
|
-note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:10:12
|
-LL | F: ~const Fn() -> u8,
- | ^^^^^^ can't be applied to `Fn`
+LL | F: [const] Fn() -> u8,
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:23:20
|
-LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn answer<F: [const] Fn() -> u8>(f: &F) -> u8 {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/const-closures.rs:23:20
|
-LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn answer<F: [const] Fn() -> u8>(f: &F) -> u8 {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/const-cond-for-rpitit.rs b/tests/ui/traits/const-traits/const-cond-for-rpitit.rs
index 50bf93f..da83e05 100644
--- a/tests/ui/traits/const-traits/const-cond-for-rpitit.rs
+++ b/tests/ui/traits/const-traits/const-cond-for-rpitit.rs
@@ -6,15 +6,15 @@
#[const_trait]
pub trait Foo {
- fn method(self) -> impl ~const Bar;
+ fn method(self) -> impl [const] Bar;
}
#[const_trait]
pub trait Bar {}
struct A<T>(T);
-impl<T> const Foo for A<T> where A<T>: ~const Bar {
- fn method(self) -> impl ~const Bar {
+impl<T> const Foo for A<T> where A<T>: [const] Bar {
+ fn method(self) -> impl [const] Bar {
self
}
}
diff --git a/tests/ui/traits/const-traits/const-default-method-bodies.rs b/tests/ui/traits/const-traits/const-default-method-bodies.rs
index 0ef11a7..27e828c 100644
--- a/tests/ui/traits/const-traits/const-default-method-bodies.rs
+++ b/tests/ui/traits/const-traits/const-default-method-bodies.rs
@@ -23,7 +23,7 @@ fn b(self) {}
const fn test() {
NonConstImpl.a();
- //~^ ERROR the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
+ //~^ ERROR the trait bound `NonConstImpl: [const] ConstDefaultFn` is not satisfied
ConstImpl.a();
}
diff --git a/tests/ui/traits/const-traits/const-default-method-bodies.stderr b/tests/ui/traits/const-traits/const-default-method-bodies.stderr
index 903f7d3..03ca6f1 100644
--- a/tests/ui/traits/const-traits/const-default-method-bodies.stderr
+++ b/tests/ui/traits/const-traits/const-default-method-bodies.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
+error[E0277]: the trait bound `NonConstImpl: [const] ConstDefaultFn` is not satisfied
--> $DIR/const-default-method-bodies.rs:25:18
|
LL | NonConstImpl.a();
diff --git a/tests/ui/traits/const-traits/const-drop-bound.rs b/tests/ui/traits/const-traits/const-drop-bound.rs
index 4819da7..7fa9b10 100644
--- a/tests/ui/traits/const-traits/const-drop-bound.rs
+++ b/tests/ui/traits/const-traits/const-drop-bound.rs
@@ -5,7 +5,7 @@
use std::marker::Destruct;
-const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
+const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: [const] Destruct {
match res {
Ok(t) => Some(t),
Err(_e) => None,
@@ -16,8 +16,8 @@ const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
const fn baz<T, E>(res: Result<Foo<T>, Foo<E>>) -> Option<Foo<T>>
where
- T: ~const Destruct,
- E: ~const Destruct,
+ T: [const] Destruct,
+ E: [const] Destruct,
{
foo(res)
}
diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr
index 76207ea..c2309ea 100644
--- a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr
@@ -5,17 +5,17 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `const Drop`
- --> $DIR/const-drop-fail-2.rs:25:25
+ --> $DIR/const-drop-fail-2.rs:25:26
|
-LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
- | -------- ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<T: [const] A> const Drop for ConstDropImplWithBounds<T> {
+ | --------- ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `check`
--> $DIR/const-drop-fail-2.rs:21:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.rs b/tests/ui/traits/const-traits/const-drop-fail-2.rs
index 1bcc87e..3f98a9f 100644
--- a/tests/ui/traits/const-traits/const-drop-fail-2.rs
+++ b/tests/ui/traits/const-traits/const-drop-fail-2.rs
@@ -18,11 +18,11 @@ trait A { fn a() { } }
impl A for NonTrivialDrop {}
-const fn check<T: ~const Destruct>(_: T) {}
+const fn check<T: [const] Destruct>(_: T) {}
struct ConstDropImplWithBounds<T: A>(PhantomData<T>);
-impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
+impl<T: [const] A> const Drop for ConstDropImplWithBounds<T> {
fn drop(&mut self) {
T::a();
}
@@ -35,7 +35,7 @@ fn drop(&mut self) {
struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);
-impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
+impl<T: [const] A> const Drop for ConstDropImplWithNonConstBounds<T> {
fn drop(&mut self) {
T::a();
}
diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr
index 76207ea..c2309ea 100644
--- a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr
@@ -5,17 +5,17 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `const Drop`
- --> $DIR/const-drop-fail-2.rs:25:25
+ --> $DIR/const-drop-fail-2.rs:25:26
|
-LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
- | -------- ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<T: [const] A> const Drop for ConstDropImplWithBounds<T> {
+ | --------- ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `check`
--> $DIR/const-drop-fail-2.rs:21:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr
index f38e642..9c49ee5 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr
@@ -10,8 +10,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:35:5
@@ -25,8 +25,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr
index f38e642..9c49ee5 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr
@@ -10,8 +10,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:35:5
@@ -25,8 +25,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr
index f38e642..9c49ee5 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr
@@ -10,8 +10,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:35:5
@@ -25,8 +25,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr
index f38e642..9c49ee5 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr
@@ -10,8 +10,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:35:5
@@ -25,8 +25,8 @@
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:24:19
|
-LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^^^^^^^^ required by this bound in `check`
+LL | const fn check<T: [const] Destruct>(_: T) {}
+ | ^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/const-drop-fail.rs b/tests/ui/traits/const-traits/const-drop-fail.rs
index a7f3d56..4513d71 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.rs
+++ b/tests/ui/traits/const-traits/const-drop-fail.rs
@@ -21,7 +21,7 @@ impl const Drop for ConstImplWithDropGlue {
fn drop(&mut self) {}
}
-const fn check<T: ~const Destruct>(_: T) {}
+const fn check<T: [const] Destruct>(_: T) {}
macro_rules! check_all {
($($exp:expr),*$(,)?) => {$(
diff --git a/tests/ui/traits/const-traits/const-drop.rs b/tests/ui/traits/const-traits/const-drop.rs
index e2d87ae..5df3a77 100644
--- a/tests/ui/traits/const-traits/const-drop.rs
+++ b/tests/ui/traits/const-traits/const-drop.rs
@@ -16,7 +16,7 @@ fn drop(&mut self) {
}
}
-const fn a<T: ~const Destruct>(_: T) {}
+const fn a<T: [const] Destruct>(_: T) {}
//FIXME ~^ ERROR destructor of
const fn b() -> u8 {
@@ -108,7 +108,7 @@ fn drop(&mut self) {
}
}
- // These types should pass because ~const in a non-const context should have no effect.
+ // These types should pass because [const] in a non-const context should have no effect.
a(HasDropGlue(Box::new(0)));
a(HasDropImpl);
diff --git a/tests/ui/traits/const-traits/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs
index d7fe43e..dc96042 100644
--- a/tests/ui/traits/const-traits/const-impl-trait.rs
+++ b/tests/ui/traits/const-traits/const-impl-trait.rs
@@ -8,23 +8,23 @@
use std::marker::Destruct;
-const fn cmp(a: &impl ~const PartialEq) -> bool {
+const fn cmp(a: &impl [const] PartialEq) -> bool {
a == a
}
const fn wrap(
- x: impl ~const PartialEq + ~const Destruct,
-) -> impl ~const PartialEq + ~const Destruct {
+ x: impl [const] PartialEq + [const] Destruct,
+) -> impl [const] PartialEq + [const] Destruct {
x
}
#[const_trait]
trait Foo {
- fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+ fn huh() -> impl [const] PartialEq + [const] Destruct + Copy;
}
impl const Foo for () {
- fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
+ fn huh() -> impl [const] PartialEq + [const] Destruct + Copy {
123
}
}
@@ -43,16 +43,16 @@ trait T {}
struct S;
impl const T for S {}
-const fn rpit() -> impl ~const T {
+const fn rpit() -> impl [const] T {
S
}
-const fn apit(_: impl ~const T + ~const Destruct) {}
+const fn apit(_: impl [const] T + [const] Destruct) {}
-const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> {
+const fn rpit_assoc_bound() -> impl IntoIterator<Item: [const] T> {
Some(S)
}
-const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
+const fn apit_assoc_bound(_: impl IntoIterator<Item: [const] T> + [const] Destruct) {}
fn main() {}
diff --git a/tests/ui/traits/const-traits/const-impl-trait.stderr b/tests/ui/traits/const-traits/const-impl-trait.stderr
index ee922f9..cbb68d8 100644
--- a/tests/ui/traits/const-traits/const-impl-trait.stderr
+++ b/tests/ui/traits/const-traits/const-impl-trait.stderr
@@ -9,8 +9,8 @@
note: required by a bound in `cmp`
--> $DIR/const-impl-trait.rs:11:23
|
-LL | const fn cmp(a: &impl ~const PartialEq) -> bool {
- | ^^^^^^^^^^^^^^^^ required by this bound in `cmp`
+LL | const fn cmp(a: &impl [const] PartialEq) -> bool {
+ | ^^^^^^^^^^^^^^^^^ required by this bound in `cmp`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/const-in-closure.rs b/tests/ui/traits/const-traits/const-in-closure.rs
index ebc17a5..0657c5a 100644
--- a/tests/ui/traits/const-traits/const-in-closure.rs
+++ b/tests/ui/traits/const-traits/const-in-closure.rs
@@ -3,13 +3,14 @@
#![feature(const_trait_impl)]
-#[const_trait] trait Trait {
+#[const_trait]
+trait Trait {
fn method();
}
const fn foo<T: Trait>() {
let _ = || {
- // Make sure this doesn't enforce `T: ~const Trait`
+ // Make sure this doesn't enforce `T: [const] Trait`
T::method();
};
}
@@ -17,7 +18,9 @@ const fn foo<T: Trait>() {
fn bar<T: const Trait>() {
let _ = || {
// Make sure unconditionally const bounds propagate from parent.
- const { T::method(); };
+ const {
+ T::method();
+ };
};
}
diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr
index 47e6929..acf19ba 100644
--- a/tests/ui/traits/const-traits/const-opaque.no.stderr
+++ b/tests/ui/traits/const-traits/const-opaque.no.stderr
@@ -9,8 +9,8 @@
note: required by a bound in `bar`
--> $DIR/const-opaque.rs:26:17
|
-LL | const fn bar<T: ~const Foo>(t: T) -> impl ~const Foo {
- | ^^^^^^^^^^ required by this bound in `bar`
+LL | const fn bar<T: [const] Foo>(t: T) -> impl [const] Foo {
+ | ^^^^^^^^^^^ required by this bound in `bar`
error[E0277]: the trait bound `(): const Foo` is not satisfied
--> $DIR/const-opaque.rs:33:12
diff --git a/tests/ui/traits/const-traits/const-opaque.rs b/tests/ui/traits/const-traits/const-opaque.rs
index 96cdd7d..56ebf0a 100644
--- a/tests/ui/traits/const-traits/const-opaque.rs
+++ b/tests/ui/traits/const-traits/const-opaque.rs
@@ -9,7 +9,7 @@ trait Foo {
fn method(&self);
}
-impl<T: ~const Foo> const Foo for (T,) {
+impl<T: [const] Foo> const Foo for (T,) {
fn method(&self) {}
}
@@ -23,7 +23,7 @@ impl Foo for () {
fn method(&self) {}
}
-const fn bar<T: ~const Foo>(t: T) -> impl ~const Foo {
+const fn bar<T: [const] Foo>(t: T) -> impl [const] Foo {
(t,)
}
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
index 2dac197..ece8752 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
@@ -7,12 +7,12 @@ trait Trait {}
fn main() {
let _: &dyn const Trait; //~ ERROR const trait bounds are not allowed in trait object types
- let _: &dyn ~const Trait; //~ ERROR `~const` is not allowed here
+ let _: &dyn [const] Trait; //~ ERROR `[const]` is not allowed here
}
// Regression test for issue #119525.
trait NonConst {}
const fn handle(_: &dyn const NonConst) {}
//~^ ERROR const trait bounds are not allowed in trait object types
-const fn take(_: &dyn ~const NonConst) {}
-//~^ ERROR `~const` is not allowed here
+const fn take(_: &dyn [const] NonConst) {}
+//~^ ERROR `[const]` is not allowed here
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
index bd29b4b..090555c 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
@@ -4,13 +4,13 @@
LL | let _: &dyn const Trait;
| ^^^^^^^^^^^
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/const-trait-bounds-trait-objects.rs:10:17
|
-LL | let _: &dyn ~const Trait;
- | ^^^^^^
+LL | let _: &dyn [const] Trait;
+ | ^^^^^^^
|
- = note: trait objects cannot have `~const` trait bounds
+ = note: trait objects cannot have `[const]` trait bounds
error: const trait bounds are not allowed in trait object types
--> $DIR/const-trait-bounds-trait-objects.rs:15:25
@@ -18,13 +18,13 @@
LL | const fn handle(_: &dyn const NonConst) {}
| ^^^^^^^^^^^^^^
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/const-trait-bounds-trait-objects.rs:17:23
|
-LL | const fn take(_: &dyn ~const NonConst) {}
- | ^^^^^^
+LL | const fn take(_: &dyn [const] NonConst) {}
+ | ^^^^^^^
|
- = note: trait objects cannot have `~const` trait bounds
+ = note: trait objects cannot have `[const]` trait bounds
error: aborting due to 4 previous errors
diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
index f90ff91..5376baf 100644
--- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
@@ -12,7 +12,7 @@
#[const_trait]
trait Main {
- fn compute<T: ~const Aux>() -> u32;
+ fn compute<T: [const] Aux>() -> u32;
}
impl const Main for () {
diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
index 566961b..736fde3 100644
--- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
@@ -10,7 +10,7 @@
error[E0049]: associated function `compute` has 0 type parameters but its trait declaration has 1 type parameter
--> $DIR/const-trait-impl-parameter-mismatch.rs:19:16
|
-LL | fn compute<T: ~const Aux>() -> u32;
+LL | fn compute<T: [const] Aux>() -> u32;
| - expected 1 type parameter
...
LL | fn compute<'x>() -> u32 {
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
index 87ac789..ce61eb9 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
@@ -22,7 +22,7 @@
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
-error[E0277]: the trait bound `(): ~const PartialEq` is not satisfied
+error[E0277]: the trait bound `(): [const] PartialEq` is not satisfied
--> $DIR/derive-const-use.rs:16:14
|
LL | #[derive_const(Default, PartialEq)]
diff --git a/tests/ui/traits/const-traits/cross-crate.gatednc.stderr b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
index 4d5abf6..1da5191 100644
--- a/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
+error[E0277]: the trait bound `cross_crate::NonConst: [const] cross_crate::MyTrait` is not satisfied
--> $DIR/cross-crate.rs:19:14
|
LL | NonConst.func();
diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs
index 96acdc3..ea97f75 100644
--- a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs
+++ b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs
@@ -4,13 +4,13 @@
trait Tr {}
impl Tr for () {}
-const fn foo<T>() where T: ~const Tr {}
+const fn foo<T>() where T: [const] Tr {}
#[const_trait]
pub trait Foo {
fn foo() {
foo::<()>();
- //~^ ERROR the trait bound `(): ~const Tr` is not satisfied
+ //~^ ERROR the trait bound `(): [const] Tr` is not satisfied
}
}
diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr
index b301752..2e236ce 100644
--- a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr
+++ b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+error[E0277]: the trait bound `(): [const] Tr` is not satisfied
--> $DIR/default-method-body-is-const-body-checking.rs:12:15
|
LL | foo::<()>();
@@ -7,8 +7,8 @@
note: required by a bound in `foo`
--> $DIR/default-method-body-is-const-body-checking.rs:7:28
|
-LL | const fn foo<T>() where T: ~const Tr {}
- | ^^^^^^^^^ required by this bound in `foo`
+LL | const fn foo<T>() where T: [const] Tr {}
+ | ^^^^^^^^^^ required by this bound in `foo`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs
index b3beba0..eb2c472 100644
--- a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs
+++ b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs
@@ -7,7 +7,7 @@ fn a(&self) {}
fn b(&self) {
().a()
- //~^ ERROR the trait bound `(): ~const Tr` is not satisfied
+ //~^ ERROR the trait bound `(): [const] Tr` is not satisfied
}
}
diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
index 2bd71c9..2dc2d48 100644
--- a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
+++ b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+error[E0277]: the trait bound `(): [const] Tr` is not satisfied
--> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
diff --git a/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs b/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs
index 2295c2c..d39e661 100644
--- a/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs
+++ b/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs
@@ -13,7 +13,7 @@ trait Trait {
type Assoc: const Trait;
}
-const fn needs_trait<T: ~const Trait>() {}
+const fn needs_trait<T: [const] Trait>() {}
fn test<T: Trait>() {
const { needs_trait::<T::Assoc>() };
diff --git a/tests/ui/traits/const-traits/dont-prefer-param-env-for-infer-self-ty.rs b/tests/ui/traits/const-traits/dont-prefer-param-env-for-infer-self-ty.rs
index 08dcd7d..f1fc98d 100644
--- a/tests/ui/traits/const-traits/dont-prefer-param-env-for-infer-self-ty.rs
+++ b/tests/ui/traits/const-traits/dont-prefer-param-env-for-infer-self-ty.rs
@@ -5,11 +5,11 @@
#[const_trait]
trait Foo {}
-impl<T> const Foo for (T,) where T: ~const Foo {}
+impl<T> const Foo for (T,) where T: [const] Foo {}
-const fn needs_const_foo(_: impl ~const Foo + Copy) {}
+const fn needs_const_foo(_: impl [const] Foo + Copy) {}
-const fn test<T: ~const Foo + Copy>(t: T) {
+const fn test<T: [const] Foo + Copy>(t: T) {
needs_const_foo((t,));
}
diff --git a/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs
index f4b01ef..414b80c 100644
--- a/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs
+++ b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs
@@ -7,7 +7,7 @@ trait Trait {
type Out;
}
-const fn needs_const<T: ~const Trait>(_: &T) {}
+const fn needs_const<T: [const] Trait>(_: &T) {}
const IN_CONST: () = {
needs_const(&());
diff --git a/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr
index cd68cda..740a05b 100644
--- a/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr
+++ b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr
@@ -14,8 +14,8 @@
note: required by a bound in `needs_const`
--> $DIR/double-error-for-unimplemented-trait.rs:10:25
|
-LL | const fn needs_const<T: ~const Trait>(_: &T) {}
- | ^^^^^^^^^^^^ required by this bound in `needs_const`
+LL | const fn needs_const<T: [const] Trait>(_: &T) {}
+ | ^^^^^^^^^^^^^ required by this bound in `needs_const`
error[E0277]: the trait bound `(): Trait` is not satisfied
--> $DIR/double-error-for-unimplemented-trait.rs:18:15
@@ -33,8 +33,8 @@
note: required by a bound in `needs_const`
--> $DIR/double-error-for-unimplemented-trait.rs:10:25
|
-LL | const fn needs_const<T: ~const Trait>(_: &T) {}
- | ^^^^^^^^^^^^ required by this bound in `needs_const`
+LL | const fn needs_const<T: [const] Trait>(_: &T) {}
+ | ^^^^^^^^^^^^^ required by this bound in `needs_const`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/duplicate-constness.rs b/tests/ui/traits/const-traits/duplicate-constness.rs
new file mode 100644
index 0000000..4b13abe
--- /dev/null
+++ b/tests/ui/traits/const-traits/duplicate-constness.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -Z parse-crate-root-only
+
+#![feature(const_trait_impl)]
+
+struct S<T: [const] [const] Tr>;
+//~^ ERROR expected identifier, found `]`
diff --git a/tests/ui/traits/const-traits/duplicate-constness.stderr b/tests/ui/traits/const-traits/duplicate-constness.stderr
new file mode 100644
index 0000000..27f69cd
--- /dev/null
+++ b/tests/ui/traits/const-traits/duplicate-constness.stderr
@@ -0,0 +1,8 @@
+error: expected identifier, found `]`
+ --> $DIR/duplicate-constness.rs:5:27
+ |
+LL | struct S<T: [const] [const] Tr>;
+ | ^ expected identifier
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/const-traits/eval-bad-signature.rs b/tests/ui/traits/const-traits/eval-bad-signature.rs
index 97c573e..66e296d 100644
--- a/tests/ui/traits/const-traits/eval-bad-signature.rs
+++ b/tests/ui/traits/const-traits/eval-bad-signature.rs
@@ -7,7 +7,7 @@ trait Value {
fn value() -> u32;
}
-const fn get_value<T: ~const Value>() -> u32 {
+const fn get_value<T: [const] Value>() -> u32 {
T::value()
}
diff --git a/tests/ui/traits/const-traits/feature-gate.rs b/tests/ui/traits/const-traits/feature-gate.rs
index 921dfb0..5ad56dd 100644
--- a/tests/ui/traits/const-traits/feature-gate.rs
+++ b/tests/ui/traits/const-traits/feature-gate.rs
@@ -10,12 +10,12 @@ trait T {}
impl const T for S {}
//[stock]~^ ERROR const trait impls are experimental
-const fn f<A: ~const T>() {} //[stock]~ ERROR const trait impls are experimental
+const fn f<A: [const] T>() {} //[stock]~ ERROR const trait impls are experimental
fn g<A: const T>() {} //[stock]~ ERROR const trait impls are experimental
macro_rules! discard { ($ty:ty) => {} }
-discard! { impl ~const T } //[stock]~ ERROR const trait impls are experimental
+discard! { impl [const] T } //[stock]~ ERROR const trait impls are experimental
discard! { impl const T } //[stock]~ ERROR const trait impls are experimental
fn main() {}
diff --git a/tests/ui/traits/const-traits/feature-gate.stock.stderr b/tests/ui/traits/const-traits/feature-gate.stock.stderr
index 78157d5..f9d966f 100644
--- a/tests/ui/traits/const-traits/feature-gate.stock.stderr
+++ b/tests/ui/traits/const-traits/feature-gate.stock.stderr
@@ -11,8 +11,8 @@
error[E0658]: const trait impls are experimental
--> $DIR/feature-gate.rs:13:15
|
-LL | const fn f<A: ~const T>() {}
- | ^^^^^^
+LL | const fn f<A: [const] T>() {}
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
@@ -31,8 +31,8 @@
error[E0658]: const trait impls are experimental
--> $DIR/feature-gate.rs:18:17
|
-LL | discard! { impl ~const T }
- | ^^^^^^
+LL | discard! { impl [const] T }
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
diff --git a/tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs b/tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs
index 61826e9..8acd195 100644
--- a/tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs
+++ b/tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs
@@ -6,7 +6,7 @@ pub trait Test {}
impl Test for () {}
-pub const fn test<T: ~const Test>() {}
+pub const fn test<T: [const] Test>() {}
pub const fn min_by_i32() -> fn() {
test::<()>
diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs
index 4312d29..026f2c0 100644
--- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs
@@ -1,9 +1,9 @@
#![feature(const_trait_impl)]
-const fn test() -> impl ~const Fn() {
- //~^ ERROR `~const` can only be applied to `#[const_trait]` traits
- //~| ERROR `~const` can only be applied to `#[const_trait]` traits
- //~| ERROR `~const` can only be applied to `#[const_trait]` traits
+const fn test() -> impl [const] Fn() {
+ //~^ ERROR `[const]` can only be applied to `#[const_trait]` traits
+ //~| ERROR `[const]` can only be applied to `#[const_trait]` traits
+ //~| ERROR `[const]` can only be applied to `#[const_trait]` traits
const move || { //~ ERROR const closures are experimental
let sl: &[u8] = b"foo";
diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr
index f06bacd..78d7b96 100644
--- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr
@@ -8,32 +8,32 @@
= help: add `#![feature(const_closures)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/ice-112822-expected-type-for-param.rs:3:25
|
-LL | const fn test() -> impl ~const Fn() {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn test() -> impl [const] Fn() {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/ice-112822-expected-type-for-param.rs:3:25
|
-LL | const fn test() -> impl ~const Fn() {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn test() -> impl [const] Fn() {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/ice-112822-expected-type-for-param.rs:3:25
|
-LL | const fn test() -> impl ~const Fn() {
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn test() -> impl [const] Fn() {
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
index fadcaa39..f1dbd94 100644
--- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
@@ -1,8 +1,8 @@
#![allow(incomplete_features)]
#![feature(generic_const_exprs, const_trait_impl)]
-const fn with_positive<F: ~const Fn()>() {}
-//~^ ERROR `~const` can only be applied to `#[const_trait]` traits
-//~| ERROR `~const` can only be applied to `#[const_trait]` traits
+const fn with_positive<F: [const] Fn()>() {}
+//~^ ERROR `[const]` can only be applied to `#[const_trait]` traits
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
pub fn main() {}
diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
index 821b257..1eccb16 100644
--- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/ice-123664-unexpected-bound-var.rs:4:27
|
-LL | const fn with_positive<F: ~const Fn()>() {}
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn with_positive<F: [const] Fn()>() {}
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/ice-123664-unexpected-bound-var.rs:4:27
|
-LL | const fn with_positive<F: ~const Fn()>() {}
- | ^^^^^^ can't be applied to `Fn`
+LL | const fn with_positive<F: [const] Fn()>() {}
+ | ^^^^^^^ can't be applied to `Fn`
|
-note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs
index d6df171..ea4db05 100644
--- a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs
+++ b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs
@@ -7,7 +7,7 @@ trait Foo {}
impl const Foo for i32 {}
-impl<T> const Foo for T where T: ~const Foo {}
+impl<T> const Foo for T where T: [const] Foo {}
//~^ ERROR conflicting implementations of trait `Foo` for type `i32`
fn main() {}
diff --git a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
index 183c2c2..5b417dc 100644
--- a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
+++ b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
@@ -4,8 +4,8 @@
LL | impl const Foo for i32 {}
| ---------------------- first implementation here
LL |
-LL | impl<T> const Foo for T where T: ~const Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
+LL | impl<T> const Foo for T where T: [const] Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/impl-conditionally-const-trait.rs b/tests/ui/traits/const-traits/impl-conditionally-const-trait.rs
new file mode 100644
index 0000000..f3783c9
--- /dev/null
+++ b/tests/ui/traits/const-traits/impl-conditionally-const-trait.rs
@@ -0,0 +1,12 @@
+//! This test ensures that we can only implement `const Trait` for a type
+//! and not have the conditionally const syntax in that position.
+
+#![feature(const_trait_impl)]
+
+struct S;
+trait T {}
+
+impl [const] T for S {}
+//~^ ERROR expected identifier, found `]`
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/impl-conditionally-const-trait.stderr b/tests/ui/traits/const-traits/impl-conditionally-const-trait.stderr
new file mode 100644
index 0000000..fc8db61
--- /dev/null
+++ b/tests/ui/traits/const-traits/impl-conditionally-const-trait.stderr
@@ -0,0 +1,8 @@
+error: expected identifier, found `]`
+ --> $DIR/impl-conditionally-const-trait.rs:9:12
+ |
+LL | impl [const] T for S {}
+ | ^ expected identifier
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/const-traits/impl-tilde-const-trait.rs b/tests/ui/traits/const-traits/impl-tilde-const-trait.rs
deleted file mode 100644
index 05b2646..0000000
--- a/tests/ui/traits/const-traits/impl-tilde-const-trait.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(const_trait_impl)]
-
-struct S;
-trait T {}
-
-impl ~const T for S {}
-//~^ ERROR expected a trait, found type
-
-fn main() {}
diff --git a/tests/ui/traits/const-traits/impl-tilde-const-trait.stderr b/tests/ui/traits/const-traits/impl-tilde-const-trait.stderr
deleted file mode 100644
index 4695728..0000000
--- a/tests/ui/traits/const-traits/impl-tilde-const-trait.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected a trait, found type
- --> $DIR/impl-tilde-const-trait.rs:6:6
- |
-LL | impl ~const T for S {}
- | ^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/const-traits/inherent-impl-const-bounds.rs b/tests/ui/traits/const-traits/inherent-impl-const-bounds.rs
index 5ead135..941f054 100644
--- a/tests/ui/traits/const-traits/inherent-impl-const-bounds.rs
+++ b/tests/ui/traits/const-traits/inherent-impl-const-bounds.rs
@@ -12,7 +12,7 @@ impl const A for S {}
impl const B for S {}
impl S {
- const fn a<T: ~const A>() where T: ~const B {
+ const fn a<T: [const] A>() where T: [const] B {
}
}
diff --git a/tests/ui/traits/const-traits/issue-100222.rs b/tests/ui/traits/const-traits/issue-100222.rs
index 55722d3..4c93272 100644
--- a/tests/ui/traits/const-traits/issue-100222.rs
+++ b/tests/ui/traits/const-traits/issue-100222.rs
@@ -11,21 +11,28 @@ pub trait Index {
}
#[cfg_attr(any(ny, yy), const_trait)]
-pub trait IndexMut where Self: Index {
+pub trait IndexMut
+where
+ Self: Index,
+{
const C: <Self as Index>::Output;
type Assoc = <Self as Index>::Output;
fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output;
}
-impl Index for () { type Output = (); }
+impl Index for () {
+ type Output = ();
+}
#[cfg(not(any(nn, yn)))]
impl const IndexMut for <() as Index>::Output {
const C: <Self as Index>::Output = ();
type Assoc = <Self as Index>::Output;
fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
- where <Self as Index>::Output:,
- {}
+ where
+ <Self as Index>::Output:,
+ {
+ }
}
#[cfg(any(nn, yn))]
@@ -33,8 +40,10 @@ impl IndexMut for <() as Index>::Output {
const C: <Self as Index>::Output = ();
type Assoc = <Self as Index>::Output;
fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
- where <Self as Index>::Output:,
- {}
+ where
+ <Self as Index>::Output:,
+ {
+ }
}
const C: <() as Index>::Output = ();
diff --git a/tests/ui/traits/const-traits/issue-92111.rs b/tests/ui/traits/const-traits/issue-92111.rs
index c8db5cc..2450136 100644
--- a/tests/ui/traits/const-traits/issue-92111.rs
+++ b/tests/ui/traits/const-traits/issue-92111.rs
@@ -14,7 +14,7 @@ impl<T: Drop> Tr for T {}
impl Tr for S {}
-const fn a<T: ~const Destruct>(t: T) {}
+const fn a<T: [const] Destruct>(t: T) {}
fn main() {
a(S(0));
diff --git a/tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs b/tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
index a3edc5f..0eb7f54 100644
--- a/tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
+++ b/tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
@@ -10,7 +10,7 @@ pub trait Super {}
#[const_trait]
pub trait Sub: Super {}
-impl<A> const Super for &A where A: ~const Super {}
-impl<A> const Sub for &A where A: ~const Sub {}
+impl<A> const Super for &A where A: [const] Super {}
+impl<A> const Sub for &A where A: [const] Sub {}
fn main() {}
diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.rs b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs
index f4bfcbd..029597e 100644
--- a/tests/ui/traits/const-traits/item-bound-entailment-fails.rs
+++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs
@@ -2,27 +2,27 @@
#![feature(const_trait_impl)]
#[const_trait] trait Foo {
- type Assoc<T>: ~const Bar
+ type Assoc<T>: [const] Bar
where
- T: ~const Bar;
+ T: [const] Bar;
}
#[const_trait] trait Bar {}
struct N<T>(T);
impl<T> Bar for N<T> where T: Bar {}
struct C<T>(T);
-impl<T> const Bar for C<T> where T: ~const Bar {}
+impl<T> const Bar for C<T> where T: [const] Bar {}
impl const Foo for u32 {
type Assoc<T> = N<T>
- //~^ ERROR the trait bound `N<T>: ~const Bar` is not satisfied
+ //~^ ERROR the trait bound `N<T>: [const] Bar` is not satisfied
where
- T: ~const Bar;
+ T: [const] Bar;
}
impl const Foo for i32 {
type Assoc<T> = C<T>
- //~^ ERROR the trait bound `T: ~const Bar` is not satisfied
+ //~^ ERROR the trait bound `T: [const] Bar` is not satisfied
where
T: Bar;
}
diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
index 7e72dc9..8e5894a 100644
--- a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
+++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `N<T>: ~const Bar` is not satisfied
+error[E0277]: the trait bound `N<T>: [const] Bar` is not satisfied
--> $DIR/item-bound-entailment-fails.rs:17:21
|
LL | type Assoc<T> = N<T>
@@ -7,25 +7,25 @@
note: required by a bound in `Foo::Assoc`
--> $DIR/item-bound-entailment-fails.rs:5:20
|
-LL | type Assoc<T>: ~const Bar
- | ^^^^^^^^^^ required by this bound in `Foo::Assoc`
+LL | type Assoc<T>: [const] Bar
+ | ^^^^^^^^^^^ required by this bound in `Foo::Assoc`
-error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+error[E0277]: the trait bound `T: [const] Bar` is not satisfied
--> $DIR/item-bound-entailment-fails.rs:24:21
|
LL | type Assoc<T> = C<T>
| ^^^^
|
-note: required for `C<T>` to implement `~const Bar`
+note: required for `C<T>` to implement `[const] Bar`
--> $DIR/item-bound-entailment-fails.rs:14:15
|
-LL | impl<T> const Bar for C<T> where T: ~const Bar {}
- | ^^^ ^^^^ ---------- unsatisfied trait bound introduced here
+LL | impl<T> const Bar for C<T> where T: [const] Bar {}
+ | ^^^ ^^^^ ----------- unsatisfied trait bound introduced here
note: required by a bound in `Foo::Assoc`
--> $DIR/item-bound-entailment-fails.rs:5:20
|
-LL | type Assoc<T>: ~const Bar
- | ^^^^^^^^^^ required by this bound in `Foo::Assoc`
+LL | type Assoc<T>: [const] Bar
+ | ^^^^^^^^^^^ required by this bound in `Foo::Assoc`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/item-bound-entailment.rs b/tests/ui/traits/const-traits/item-bound-entailment.rs
index 11db57b..6e053ad 100644
--- a/tests/ui/traits/const-traits/item-bound-entailment.rs
+++ b/tests/ui/traits/const-traits/item-bound-entailment.rs
@@ -4,16 +4,16 @@
#![feature(const_trait_impl)]
#[const_trait] trait Foo {
- type Assoc<T>: ~const Bar
+ type Assoc<T>: [const] Bar
where
- T: ~const Bar;
+ T: [const] Bar;
}
#[const_trait] trait Bar {}
struct N<T>(T);
impl<T> Bar for N<T> where T: Bar {}
struct C<T>(T);
-impl<T> const Bar for C<T> where T: ~const Bar {}
+impl<T> const Bar for C<T> where T: [const] Bar {}
impl Foo for u32 {
type Assoc<T> = N<T>
@@ -24,7 +24,7 @@ impl Foo for u32 {
impl const Foo for i32 {
type Assoc<T> = C<T>
where
- T: ~const Bar;
+ T: [const] Bar;
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs
index 820d3d6..a5f6ae1 100644
--- a/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs
+++ b/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs
@@ -1,20 +1,24 @@
-// Ensure that we don't consider `const Trait` and `~const Trait` to
+// Ensure that we don't consider `const Trait` to
// match the macro fragment specifier `ty` as that would be a breaking
// change theoretically speaking. Syntactically trait object types can
// be "bare", i.e., lack the prefix `dyn`.
// By contrast, `?Trait` *does* match `ty` and therefore an arm like
// `?$Trait:path` would never be reached.
// See `parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs`.
-
-//@ check-pass
+// `[const] Trait` is already an error for a `ty` fragment,
+// so we do not need to prevent that.
macro_rules! check {
- ($Type:ty) => { compile_error!("ty"); };
+ ($Type:ty) => {
+ compile_error!("ty");
+ };
(const $Trait:path) => {};
- (~const $Trait:path) => {};
+ ([const] $Trait:path) => {};
}
check! { const Trait }
-check! { ~const Trait }
+check! { [const] Trait }
+//~^ ERROR: expected identifier, found `]`
+//~| ERROR: const trait impls are experimental
fn main() {}
diff --git a/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.stderr b/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.stderr
new file mode 100644
index 0000000..56dad53
--- /dev/null
+++ b/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.stderr
@@ -0,0 +1,22 @@
+error: expected identifier, found `]`
+ --> $DIR/mbe-bare-trait-objects-const-trait-bounds.rs:20:16
+ |
+LL | ($Type:ty) => {
+ | -------- while parsing argument for this `ty` macro fragment
+...
+LL | check! { [const] Trait }
+ | ^ expected identifier
+
+error[E0658]: const trait impls are experimental
+ --> $DIR/mbe-bare-trait-objects-const-trait-bounds.rs:20:11
+ |
+LL | check! { [const] Trait }
+ | ^^^^^
+ |
+ = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+ = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/const-traits/minicore-deref-fail.rs b/tests/ui/traits/const-traits/minicore-deref-fail.rs
index f4a7678..d9b33fa 100644
--- a/tests/ui/traits/const-traits/minicore-deref-fail.rs
+++ b/tests/ui/traits/const-traits/minicore-deref-fail.rs
@@ -11,10 +11,12 @@
struct Ty;
impl Deref for Ty {
type Target = ();
- fn deref(&self) -> &Self::Target { &() }
+ fn deref(&self) -> &Self::Target {
+ &()
+ }
}
const fn foo() {
*Ty;
- //~^ ERROR the trait bound `Ty: ~const minicore::Deref` is not satisfied
+ //~^ ERROR the trait bound `Ty: [const] minicore::Deref` is not satisfied
}
diff --git a/tests/ui/traits/const-traits/minicore-deref-fail.stderr b/tests/ui/traits/const-traits/minicore-deref-fail.stderr
index a1f8401..4329b23 100644
--- a/tests/ui/traits/const-traits/minicore-deref-fail.stderr
+++ b/tests/ui/traits/const-traits/minicore-deref-fail.stderr
@@ -1,5 +1,5 @@
-error[E0277]: the trait bound `Ty: ~const minicore::Deref` is not satisfied
- --> $DIR/minicore-deref-fail.rs:18:5
+error[E0277]: the trait bound `Ty: [const] minicore::Deref` is not satisfied
+ --> $DIR/minicore-deref-fail.rs:20:5
|
LL | *Ty;
| ^^^
diff --git a/tests/ui/traits/const-traits/minicore-drop-fail.rs b/tests/ui/traits/const-traits/minicore-drop-fail.rs
index 274e5db..f3e7c7d 100644
--- a/tests/ui/traits/const-traits/minicore-drop-fail.rs
+++ b/tests/ui/traits/const-traits/minicore-drop-fail.rs
@@ -19,7 +19,7 @@ fn drop(&mut self) {}
impl Foo for () {}
struct Conditional<T: Foo>(T);
-impl<T> const Drop for Conditional<T> where T: ~const Foo {
+impl<T> const Drop for Conditional<T> where T: [const] Foo {
fn drop(&mut self) {}
}
diff --git a/tests/ui/traits/const-traits/minicore-fn-fail.rs b/tests/ui/traits/const-traits/minicore-fn-fail.rs
index ae1cbc6..d4cd41a 100644
--- a/tests/ui/traits/const-traits/minicore-fn-fail.rs
+++ b/tests/ui/traits/const-traits/minicore-fn-fail.rs
@@ -8,14 +8,14 @@
extern crate minicore;
use minicore::*;
-const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
+const fn call_indirect<T: [const] Fn()>(t: &T) { t() }
#[const_trait]
trait Foo {}
impl Foo for () {}
-const fn foo<T: ~const Foo>() {}
+const fn foo<T: [const] Foo>() {}
const fn test() {
call_indirect(&foo::<()>);
- //~^ ERROR the trait bound `(): ~const Foo` is not satisfied
+ //~^ ERROR the trait bound `(): [const] Foo` is not satisfied
}
diff --git a/tests/ui/traits/const-traits/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/minicore-fn-fail.stderr
index 03c7ade..c02a067 100644
--- a/tests/ui/traits/const-traits/minicore-fn-fail.stderr
+++ b/tests/ui/traits/const-traits/minicore-fn-fail.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `(): ~const Foo` is not satisfied
+error[E0277]: the trait bound `(): [const] Foo` is not satisfied
--> $DIR/minicore-fn-fail.rs:19:19
|
LL | call_indirect(&foo::<()>);
@@ -9,8 +9,8 @@
note: required by a bound in `call_indirect`
--> $DIR/minicore-fn-fail.rs:11:27
|
-LL | const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
- | ^^^^^^^^^^^ required by this bound in `call_indirect`
+LL | const fn call_indirect<T: [const] Fn()>(t: &T) { t() }
+ | ^^^^^^^^^^^^ required by this bound in `call_indirect`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/minicore-works.rs b/tests/ui/traits/const-traits/minicore-works.rs
index c79b4fc..ef08e84 100644
--- a/tests/ui/traits/const-traits/minicore-works.rs
+++ b/tests/ui/traits/const-traits/minicore-works.rs
@@ -21,7 +21,9 @@ const fn test_op() {
let _y = Custom + Custom;
}
-const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
+const fn call_indirect<T: [const] Fn()>(t: &T) {
+ t()
+}
const fn call() {
call_indirect(&call);
diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
index aaab8e8..5f47778 100644
--- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
+++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
@@ -1,13 +1,13 @@
#![feature(const_trait_impl)]
-const fn maybe_const_maybe<T: ~const ?Sized>() {}
-//~^ ERROR `~const` trait not allowed with `?` trait polarity modifier
+const fn maybe_const_maybe<T: [const] ?Sized>() {}
+//~^ ERROR `[const]` trait not allowed with `?` trait polarity modifier
fn const_maybe<T: const ?Sized>() {}
//~^ ERROR `const` trait not allowed with `?` trait polarity modifier
-const fn maybe_const_negative<T: ~const !Trait>() {}
-//~^ ERROR `~const` trait not allowed with `!` trait polarity modifier
+const fn maybe_const_negative<T: [const] !Trait>() {}
+//~^ ERROR `[const]` trait not allowed with `!` trait polarity modifier
//~| ERROR negative bounds are not supported
fn const_negative<T: const !Trait>() {}
diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
index 18e4d16..429131f 100644
--- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
+++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
@@ -1,10 +1,10 @@
-error: `~const` trait not allowed with `?` trait polarity modifier
- --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:38
+error: `[const]` trait not allowed with `?` trait polarity modifier
+ --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:39
|
-LL | const fn maybe_const_maybe<T: ~const ?Sized>() {}
- | ------ ^
+LL | const fn maybe_const_maybe<T: [const] ?Sized>() {}
+ | ------- ^
| |
- | there is not a well-defined meaning for a `~const ?` trait
+ | there is not a well-defined meaning for a `[const] ?` trait
error: `const` trait not allowed with `?` trait polarity modifier
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25
@@ -14,13 +14,13 @@
| |
| there is not a well-defined meaning for a `const ?` trait
-error: `~const` trait not allowed with `!` trait polarity modifier
- --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41
+error: `[const]` trait not allowed with `!` trait polarity modifier
+ --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42
|
-LL | const fn maybe_const_negative<T: ~const !Trait>() {}
- | ------ ^
+LL | const fn maybe_const_negative<T: [const] !Trait>() {}
+ | ------- ^
| |
- | there is not a well-defined meaning for a `~const !` trait
+ | there is not a well-defined meaning for a `[const] !` trait
error: `const` trait not allowed with `!` trait polarity modifier
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
@@ -31,10 +31,10 @@
| there is not a well-defined meaning for a `const !` trait
error: negative bounds are not supported
- --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41
+ --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42
|
-LL | const fn maybe_const_negative<T: ~const !Trait>() {}
- | ^
+LL | const fn maybe_const_negative<T: [const] !Trait>() {}
+ | ^
error: negative bounds are not supported
--> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs
index 8f11c8a..86e3e5f 100644
--- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs
+++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs
@@ -7,7 +7,7 @@ trait Convert<T> {
fn to(self) -> T;
}
-impl<A, B> const Convert<B> for A where B: ~const From<A> {
+impl<A, B> const Convert<B> for A where B: [const] From<A> {
fn to(self) -> B {
B::from(self)
}
diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
index 190af5e..e7f10e7 100644
--- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/non-const-op-in-closure-in-const.rs:10:44
|
-LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
- | ^^^^^^ can't be applied to `From`
+LL | impl<A, B> const Convert<B> for A where B: [const] From<A> {
+ | ^^^^^^^ can't be applied to `From`
|
-note: `From` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `From` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/non-const-op-in-closure-in-const.rs:10:44
|
-LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
- | ^^^^^^ can't be applied to `From`
+LL | impl<A, B> const Convert<B> for A where B: [const] From<A> {
+ | ^^^^^^^ can't be applied to `From`
|
-note: `From` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+note: `From` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr
index bd82297..ed671be 100644
--- a/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr
+++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr
@@ -3,8 +3,8 @@
|
LL | / impl<T> const Foo for T
LL | | where
-LL | | T: ~const Bar,
- | |__________________- first implementation here
+LL | | T: [const] Bar,
+ | |___________________- first implementation here
...
LL | impl<T> Foo for (T,) {
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)`
diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs
index eb66d03..f45690b 100644
--- a/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs
+++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs
@@ -15,7 +15,7 @@ trait Foo {
}
impl<T> const Foo for T
where
- T: ~const Bar,
+ T: [const] Bar,
{
default fn method(&self) {}
}
@@ -27,7 +27,7 @@ fn method(&self) {
}
}
-const fn dispatch<T: ~const Bar + Copy>(t: T) {
+const fn dispatch<T: [const] Bar + Copy>(t: T) {
t.method();
}
diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr
index cbdcb45..35f4d91 100644
--- a/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr
+++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr
@@ -13,8 +13,8 @@
|
LL | / impl<T> const Foo for T
LL | | where
-LL | | T: ~const Bar,
- | |__________________- first implementation here
+LL | | T: [const] Bar,
+ | |___________________- first implementation here
...
LL | impl<T> Foo for (T,) {
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)`
diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.rs b/tests/ui/traits/const-traits/predicate-entailment-fails.rs
index 266a49f..0e6c277 100644
--- a/tests/ui/traits/const-traits/predicate-entailment-fails.rs
+++ b/tests/ui/traits/const-traits/predicate-entailment-fails.rs
@@ -6,9 +6,9 @@ impl const Bar for () {}
#[const_trait] trait TildeConst {
- type Bar<T> where T: ~const Bar;
+ type Bar<T> where T: [const] Bar;
- fn foo<T>() where T: ~const Bar;
+ fn foo<T>() where T: [const] Bar;
}
impl TildeConst for () {
type Bar<T> = () where T: const Bar;
@@ -32,10 +32,10 @@ fn foo<T>() where T: const Bar {}
//~^ ERROR impl has stricter requirements than trait
}
impl const NeverConst for u32 {
- type Bar<T> = () where T: ~const Bar;
+ type Bar<T> = () where T: [const] Bar;
//~^ ERROR impl has stricter requirements than trait
- fn foo<T>() where T: ~const Bar {}
+ fn foo<T>() where T: [const] Bar {}
//~^ ERROR impl has stricter requirements than trait
}
diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
index dfdc4d2..cba7c97 100644
--- a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
+++ b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
@@ -1,7 +1,7 @@
error[E0276]: impl has stricter requirements than trait
--> $DIR/predicate-entailment-fails.rs:14:31
|
-LL | type Bar<T> where T: ~const Bar;
+LL | type Bar<T> where T: [const] Bar;
| ----------- definition of `Bar` from trait
...
LL | type Bar<T> = () where T: const Bar;
@@ -10,8 +10,8 @@
error[E0276]: impl has stricter requirements than trait
--> $DIR/predicate-entailment-fails.rs:17:26
|
-LL | fn foo<T>() where T: ~const Bar;
- | -------------------------------- definition of `foo` from trait
+LL | fn foo<T>() where T: [const] Bar;
+ | --------------------------------- definition of `foo` from trait
...
LL | fn foo<T>() where T: const Bar {}
| ^^^^^^^^^ impl has extra requirement `T: const Bar`
@@ -40,8 +40,8 @@
LL | type Bar<T> where T: Bar;
| ----------- definition of `Bar` from trait
...
-LL | type Bar<T> = () where T: ~const Bar;
- | ^^^^^^^^^^ impl has extra requirement `T: ~const Bar`
+LL | type Bar<T> = () where T: [const] Bar;
+ | ^^^^^^^^^^^ impl has extra requirement `T: [const] Bar`
error[E0276]: impl has stricter requirements than trait
--> $DIR/predicate-entailment-fails.rs:38:26
@@ -49,8 +49,8 @@
LL | fn foo<T>() where T: Bar;
| ------------------------- definition of `foo` from trait
...
-LL | fn foo<T>() where T: ~const Bar {}
- | ^^^^^^^^^^ impl has extra requirement `T: ~const Bar`
+LL | fn foo<T>() where T: [const] Bar {}
+ | ^^^^^^^^^^^ impl has extra requirement `T: [const] Bar`
error: aborting due to 6 previous errors
diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.rs b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
index 28ae218..fe87148 100644
--- a/tests/ui/traits/const-traits/predicate-entailment-passes.rs
+++ b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
@@ -7,7 +7,7 @@
impl const Bar for () {}
#[const_trait] trait TildeConst {
- fn foo<T>() where T: ~const Bar;
+ fn foo<T>() where T: [const] Bar;
}
impl TildeConst for () {
fn foo<T>() where T: Bar {}
@@ -21,7 +21,7 @@ impl AlwaysConst for i32 {
fn foo<T>() where T: Bar {}
}
impl const AlwaysConst for u32 {
- fn foo<T>() where T: ~const Bar {}
+ fn foo<T>() where T: [const] Bar {}
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs
index 5af9ee8..212d869 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs
+++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs
@@ -1,5 +1,5 @@
-// Tests that trait bounds on specializing trait impls must be `~const` if the
-// same bound is present on the default impl and is `~const` there.
+// Tests that trait bounds on specializing trait impls must be `[const]` if the
+// same bound is present on the default impl and is `[const]` there.
//@ known-bug: #110395
// FIXME(const_trait_impl) ^ should error
@@ -20,14 +20,14 @@ trait Bar {
impl<T> const Bar for T
where
- T: ~const Foo,
+ T: [const] Foo,
{
default fn bar() {}
}
impl<T> Bar for T
where
- T: Foo, //FIXME ~ ERROR missing `~const` qualifier
+ T: Foo, //FIXME ~ ERROR missing `[const]` qualifier
T: Specialize,
{
fn bar() {}
@@ -40,7 +40,7 @@ trait Baz {
impl<T> const Baz for T
where
- T: ~const Foo,
+ T: [const] Foo,
{
default fn baz() {}
}
diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
index 9166b8c..074e623 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
+++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
@@ -3,12 +3,12 @@
|
LL | / impl<T> const Bar for T
LL | | where
-LL | | T: ~const Foo,
- | |__________________- first implementation here
+LL | | T: [const] Foo,
+ | |___________________- first implementation here
...
LL | / impl<T> Bar for T
LL | | where
-LL | | T: Foo, //FIXME ~ ERROR missing `~const` qualifier
+LL | | T: Foo, //FIXME ~ ERROR missing `[const]` qualifier
LL | | T: Specialize,
| |__________________^ conflicting implementation
@@ -17,8 +17,8 @@
|
LL | / impl<T> const Baz for T
LL | | where
-LL | | T: ~const Foo,
- | |__________________- first implementation here
+LL | | T: [const] Foo,
+ | |___________________- first implementation here
...
LL | / impl<T> const Baz for T //FIXME ~ ERROR conflicting implementations of trait `Baz`
LL | | where
diff --git a/tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs
index 89ad61c..6991b7d 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs
+++ b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs
@@ -11,7 +11,7 @@ trait Value {
fn value() -> u32;
}
-const fn get_value<T: ~const Value>() -> u32 {
+const fn get_value<T: [const] Value>() -> u32 {
T::value()
}
diff --git a/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
index d97469e..754f1c6 100644
--- a/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
+++ b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
@@ -1,4 +1,4 @@
-// Tests that `T: ~const Foo` in a specializing impl is treated as equivalent to
+// Tests that `T: [const] Foo` in a specializing impl is treated as equivalent to
// `T: Foo` in the default impl for the purposes of specialization (i.e., it
// does not think that the user is attempting to specialize on trait `Foo`).
@@ -28,7 +28,7 @@ impl<T> Bar for T
impl<T> const Bar for T
where
- T: ~const Foo,
+ T: [const] Foo,
T: Specialize,
{
fn bar() {}
@@ -48,7 +48,7 @@ impl<T> const Baz for T
impl<T> const Baz for T
where
- T: ~const Foo,
+ T: [const] Foo,
T: Specialize,
{
fn baz() {}
diff --git a/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs
index e9b494b..b1a1b4a 100644
--- a/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs
+++ b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs
@@ -11,7 +11,7 @@ trait Value {
fn value() -> u32;
}
-const fn get_value<T: ~const Value>() -> u32 {
+const fn get_value<T: [const] Value>() -> u32 {
T::value()
}
diff --git a/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/traits/const-traits/specialization/specialize-on-conditionally-const.rs
similarity index 71%
rename from tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
rename to tests/ui/traits/const-traits/specialization/specialize-on-conditionally-const.rs
index d80370a..0106bb1 100644
--- a/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
+++ b/tests/ui/traits/const-traits/specialization/specialize-on-conditionally-const.rs
@@ -1,4 +1,5 @@
-// Tests that `~const` trait bounds can be used to specialize const trait impls.
+// Tests that `[const]` trait bounds can be used to specialize const trait impls.
+// cc #95186
//@ check-pass
@@ -21,7 +22,7 @@ impl<T> const Foo for T {
impl<T> const Foo for T
where
- T: ~const Specialize,
+ T: [const] Specialize,
{
fn foo() {}
}
@@ -33,15 +34,15 @@ fn bar() {}
impl<T> const Bar for T
where
- T: ~const Foo,
+ T: [const] Foo,
{
default fn bar() {}
}
impl<T> const Bar for T
where
- T: ~const Foo,
- T: ~const Specialize,
+ T: [const] Foo,
+ T: [const] Specialize,
{
fn bar() {}
}
diff --git a/tests/ui/traits/const-traits/specializing-constness-2.rs b/tests/ui/traits/const-traits/specializing-constness-2.rs
index c1fe42b..86c2cee 100644
--- a/tests/ui/traits/const-traits/specializing-constness-2.rs
+++ b/tests/ui/traits/const-traits/specializing-constness-2.rs
@@ -17,7 +17,7 @@ impl<T: Default> A for T {
}
}
-impl<T: Default + ~const Sup> const A for T {
+impl<T: Default + [const] Sup> const A for T {
fn a() -> u32 {
3
}
@@ -25,7 +25,7 @@ fn a() -> u32 {
const fn generic<T: Default>() {
<T as A>::a();
- //FIXME ~^ ERROR: the trait bound `T: ~const Sup` is not satisfied
+ //FIXME ~^ ERROR: the trait bound `T: [const] Sup` is not satisfied
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specializing-constness-2.stderr
index edba836..850e693 100644
--- a/tests/ui/traits/const-traits/specializing-constness-2.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness-2.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `T: ~const A` is not satisfied
+error[E0277]: the trait bound `T: [const] A` is not satisfied
--> $DIR/specializing-constness-2.rs:27:6
|
LL | <T as A>::a();
diff --git a/tests/ui/traits/const-traits/specializing-constness.rs b/tests/ui/traits/const-traits/specializing-constness.rs
index 94b6da7..b64d8b2 100644
--- a/tests/ui/traits/const-traits/specializing-constness.rs
+++ b/tests/ui/traits/const-traits/specializing-constness.rs
@@ -14,7 +14,7 @@ pub trait A {
#[const_trait]
pub trait Spec {}
-impl<T: ~const Spec> const A for T {
+impl<T: [const] Spec> const A for T {
default fn a() -> u32 {
2
}
diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr
index 2ca70b5..f411ebc 100644
--- a/tests/ui/traits/const-traits/specializing-constness.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness.stderr
@@ -1,8 +1,8 @@
error[E0119]: conflicting implementations of trait `A`
--> $DIR/specializing-constness.rs:23:1
|
-LL | impl<T: ~const Spec> const A for T {
- | ---------------------------------- first implementation here
+LL | impl<T: [const] Spec> const A for T {
+ | ----------------------------------- first implementation here
...
LL | impl<T: Spec + Sup> A for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs
index bf09a5f..d24b26b 100644
--- a/tests/ui/traits/const-traits/staged-api.rs
+++ b/tests/ui/traits/const-traits/staged-api.rs
@@ -23,7 +23,7 @@ fn func() {}
}
#[rustc_allow_const_fn_unstable(const_trait_impl, unstable)]
-const fn conditionally_const<T: ~const MyTrait>() {
+const fn conditionally_const<T: [const] MyTrait>() {
T::func();
}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
index 8f88e3a..19f072b 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
@@ -1,31 +1,31 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> $DIR/super-traits-fail-2.rs:11:1
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
|
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -33,11 +33,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
index 087e80d..4921f78 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
|
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -21,11 +21,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -33,11 +33,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -45,11 +45,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs
index 6cc9d73..781dacb 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs
@@ -8,17 +8,17 @@ trait Foo {
}
#[cfg_attr(any(yy, ny), const_trait)]
-trait Bar: ~const Foo {}
-//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here
+trait Bar: [const] Foo {}
+//[ny,nn]~^ ERROR: `[const]` can only be applied to `#[const_trait]`
+//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[yn,nn]~^^^^^^ ERROR: `[const]` is not allowed here
const fn foo<T: Bar>(x: &T) {
x.a();
- //[yy,yn]~^ ERROR the trait bound `T: ~const Foo`
+ //[yy,yn]~^ ERROR the trait bound `T: [const] Foo`
//[nn,ny]~^^ ERROR cannot call non-const method `<T as Foo>::a` in constant functions
}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
index ee49810..a151349 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
@@ -1,16 +1,16 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/super-traits-fail-2.rs:11:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> $DIR/super-traits-fail-2.rs:11:1
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0277]: the trait bound `T: ~const Foo` is not satisfied
+error[E0277]: the trait bound `T: [const] Foo` is not satisfied
--> $DIR/super-traits-fail-2.rs:20:7
|
LL | x.a();
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
index a213273c..4ae4bbd 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `T: ~const Foo` is not satisfied
+error[E0277]: the trait bound `T: [const] Foo` is not satisfied
--> $DIR/super-traits-fail-2.rs:20:7
|
LL | x.a();
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
index a5ef716..eb1beb4 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
@@ -1,20 +1,20 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> $DIR/super-traits-fail-3.rs:23:1
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
@@ -23,29 +23,29 @@
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
|
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -53,11 +53,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -65,27 +65,27 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
error[E0015]: cannot call non-const method `<T as Foo>::a` in constant functions
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
index a5ef716..eb1beb4 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
@@ -1,20 +1,20 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> $DIR/super-traits-fail-3.rs:23:1
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
@@ -23,29 +23,29 @@
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
|
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -53,11 +53,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -65,27 +65,27 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
error[E0015]: cannot call non-const method `<T as Foo>::a` in constant functions
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
index 024db4b..7c46573 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
@@ -1,8 +1,8 @@
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
@@ -11,8 +11,8 @@
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
index 024db4b..7c46573 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
@@ -1,8 +1,8 @@
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
@@ -11,8 +11,8 @@
error[E0658]: const trait impls are experimental
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs
index d7e0cdc..5370f60 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs
@@ -20,21 +20,21 @@ trait Foo {
#[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)]
//[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future
-trait Bar: ~const Foo {}
-//[yny,ynn,nny,nnn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
-//[yny,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yny,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yny]~^^^^ ERROR: `~const` can only be applied to `#[const_trait]`
-//[yny]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `~const` is not allowed here
+trait Bar: [const] Foo {}
+//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]`
+//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[yny]~^^^^ ERROR: `[const]` can only be applied to `#[const_trait]`
+//[yny]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `[const]` is not allowed here
//[nyy,nyn,nny,nnn]~^^^^^^^ ERROR: const trait impls are experimental
-const fn foo<T: ~const Bar>(x: &T) {
- //[yyn,ynn,nny,nnn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
- //[yyn,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]`
+const fn foo<T: [const] Bar>(x: &T) {
+ //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]`
+ //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
//[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental
x.a();
- //[yyn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied
+ //[yyn]~^ ERROR: the trait bound `T: [const] Foo` is not satisfied
//[ynn,yny,nny,nnn]~^^ ERROR: cannot call non-const method `<T as Foo>::a` in constant functions
//[nyy,nyn]~^^^ ERROR: cannot call conditionally-const method `<T as Foo>::a` in constant functions
}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
index f22bdd4..89e090b 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
@@ -1,31 +1,31 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> $DIR/super-traits-fail-3.rs:23:1
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
|
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -33,11 +33,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -45,27 +45,27 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
error[E0015]: cannot call non-const method `<T as Foo>::a` in constant functions
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
index 14b5081..683eeb7 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
@@ -1,19 +1,19 @@
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
|
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -21,11 +21,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -33,11 +33,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
@@ -45,11 +45,11 @@
LL | #[const_trait] trait Foo {
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^ can't be applied to `Foo`
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^ can't be applied to `Foo`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
index 3270611..39cfdfe 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
@@ -1,39 +1,39 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/super-traits-fail-3.rs:23:12
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^
|
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
--> $DIR/super-traits-fail-3.rs:23:1
|
-LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Bar: [const] Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
-error: `~const` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/super-traits-fail-3.rs:32:17
|
-LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^ can't be applied to `Bar`
+LL | const fn foo<T: [const] Bar>(x: &T) {
+ | ^^^^^^^ can't be applied to `Bar`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
|
-LL | #[const_trait] trait Bar: ~const Foo {}
+LL | #[const_trait] trait Bar: [const] Foo {}
| ++++++++++++++
-error[E0277]: the trait bound `T: ~const Foo` is not satisfied
+error[E0277]: the trait bound `T: [const] Foo` is not satisfied
--> $DIR/super-traits-fail-3.rs:36:7
|
LL | x.a();
diff --git a/tests/ui/traits/const-traits/super-traits-fail.rs b/tests/ui/traits/const-traits/super-traits-fail.rs
index 9fd6263..15e05be 100644
--- a/tests/ui/traits/const-traits/super-traits-fail.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail.rs
@@ -7,7 +7,7 @@ trait Foo {
fn a(&self);
}
#[const_trait]
-trait Bar: ~const Foo {}
+trait Bar: [const] Foo {}
struct S;
impl Foo for S {
diff --git a/tests/ui/traits/const-traits/super-traits-fail.stderr b/tests/ui/traits/const-traits/super-traits-fail.stderr
index 1f453ed..e19aa30 100644
--- a/tests/ui/traits/const-traits/super-traits-fail.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `S: ~const Foo` is not satisfied
+error[E0277]: the trait bound `S: [const] Foo` is not satisfied
--> $DIR/super-traits-fail.rs:17:20
|
LL | impl const Bar for S {}
diff --git a/tests/ui/traits/const-traits/super-traits.rs b/tests/ui/traits/const-traits/super-traits.rs
index 73ddc03..b5fd985 100644
--- a/tests/ui/traits/const-traits/super-traits.rs
+++ b/tests/ui/traits/const-traits/super-traits.rs
@@ -8,7 +8,7 @@ trait Foo {
}
#[const_trait]
-trait Bar: ~const Foo {}
+trait Bar: [const] Foo {}
struct S;
impl const Foo for S {
@@ -17,7 +17,7 @@ fn a(&self) {}
impl const Bar for S {}
-const fn foo<T: ~const Bar>(t: &T) {
+const fn foo<T: [const] Bar>(t: &T) {
t.a();
}
diff --git a/tests/ui/traits/const-traits/syntactical-unstable.rs b/tests/ui/traits/const-traits/syntactical-unstable.rs
index e192e80..5c542d3 100644
--- a/tests/ui/traits/const-traits/syntactical-unstable.rs
+++ b/tests/ui/traits/const-traits/syntactical-unstable.rs
@@ -1,6 +1,6 @@
//@ aux-build:staged-api.rs
-// Ensure that we enforce const stability of traits in `~const`/`const` bounds.
+// Ensure that we enforce const stability of traits in `[const]`/`const` bounds.
#![feature(const_trait_impl)]
@@ -10,19 +10,19 @@
use staged_api::MyTrait;
#[const_trait]
-trait Foo: ~const MyTrait {
+trait Foo: [const] MyTrait {
//~^ ERROR use of unstable const library feature `unstable`
- type Item: ~const MyTrait;
+ type Item: [const] MyTrait;
//~^ ERROR use of unstable const library feature `unstable`
}
-const fn where_clause<T>() where T: ~const MyTrait {}
+const fn where_clause<T>() where T: [const] MyTrait {}
//~^ ERROR use of unstable const library feature `unstable`
-const fn nested<T>() where T: Deref<Target: ~const MyTrait> {}
+const fn nested<T>() where T: Deref<Target: [const] MyTrait> {}
//~^ ERROR use of unstable const library feature `unstable`
-const fn rpit() -> impl ~const MyTrait { Local }
+const fn rpit() -> impl [const] MyTrait { Local }
//~^ ERROR use of unstable const library feature `unstable`
struct Local;
diff --git a/tests/ui/traits/const-traits/syntactical-unstable.stderr b/tests/ui/traits/const-traits/syntactical-unstable.stderr
index a2ce2f2..b8cc8e6 100644
--- a/tests/ui/traits/const-traits/syntactical-unstable.stderr
+++ b/tests/ui/traits/const-traits/syntactical-unstable.stderr
@@ -1,8 +1,8 @@
error[E0658]: use of unstable const library feature `unstable`
- --> $DIR/syntactical-unstable.rs:13:19
+ --> $DIR/syntactical-unstable.rs:13:20
|
-LL | trait Foo: ~const MyTrait {
- | ------ ^^^^^^^
+LL | trait Foo: [const] MyTrait {
+ | ------- ^^^^^^^
| |
| trait is not stable as const yet
|
@@ -10,10 +10,10 @@
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable const library feature `unstable`
- --> $DIR/syntactical-unstable.rs:19:44
+ --> $DIR/syntactical-unstable.rs:19:45
|
-LL | const fn where_clause<T>() where T: ~const MyTrait {}
- | ------ ^^^^^^^
+LL | const fn where_clause<T>() where T: [const] MyTrait {}
+ | ------- ^^^^^^^
| |
| trait is not stable as const yet
|
@@ -21,10 +21,10 @@
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable const library feature `unstable`
- --> $DIR/syntactical-unstable.rs:22:52
+ --> $DIR/syntactical-unstable.rs:22:53
|
-LL | const fn nested<T>() where T: Deref<Target: ~const MyTrait> {}
- | ------ ^^^^^^^
+LL | const fn nested<T>() where T: Deref<Target: [const] MyTrait> {}
+ | ------- ^^^^^^^
| |
| trait is not stable as const yet
|
@@ -32,10 +32,10 @@
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable const library feature `unstable`
- --> $DIR/syntactical-unstable.rs:25:32
+ --> $DIR/syntactical-unstable.rs:25:33
|
-LL | const fn rpit() -> impl ~const MyTrait { Local }
- | ------ ^^^^^^^
+LL | const fn rpit() -> impl [const] MyTrait { Local }
+ | ------- ^^^^^^^
| |
| trait is not stable as const yet
|
@@ -52,10 +52,10 @@
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable const library feature `unstable`
- --> $DIR/syntactical-unstable.rs:15:23
+ --> $DIR/syntactical-unstable.rs:15:24
|
-LL | type Item: ~const MyTrait;
- | ------ ^^^^^^^
+LL | type Item: [const] MyTrait;
+ | ------- ^^^^^^^
| |
| trait is not stable as const yet
|
diff --git a/tests/ui/traits/const-traits/syntax.rs b/tests/ui/traits/const-traits/syntax.rs
index cfac6e0..b8e0f46 100644
--- a/tests/ui/traits/const-traits/syntax.rs
+++ b/tests/ui/traits/const-traits/syntax.rs
@@ -1,8 +1,9 @@
//@ compile-flags: -Z parse-crate-root-only
-//@ check-pass
-#![feature(const_trait_bound_opt_out)]
#![feature(const_trait_impl)]
-// For now, this parses since an error does not occur until AST lowering.
-impl ~const T {}
+// This is going down the slice/array parsing route
+impl [const] T {}
+//~^ ERROR: expected identifier, found `]`
+
+impl const T {}
diff --git a/tests/ui/traits/const-traits/syntax.stderr b/tests/ui/traits/const-traits/syntax.stderr
new file mode 100644
index 0000000..2e98078
--- /dev/null
+++ b/tests/ui/traits/const-traits/syntax.stderr
@@ -0,0 +1,8 @@
+error: expected identifier, found `]`
+ --> $DIR/syntax.rs:6:12
+ |
+LL | impl [const] T {}
+ | ^ expected identifier
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
deleted file mode 100644
index 95e684b..0000000
--- a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error: `~const` is not allowed here
- --> $DIR/tilde-const-and-const-params.rs:8:15
- |
-LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
- | ^^^^^^
- |
-note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-and-const-params.rs:8:8
- |
-LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
- | ^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-and-const-params.rs:26:11
- |
-LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
- | ^^^^^^
- |
-note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-and-const-params.rs:26:4
- |
-LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
- | ^^^
-
-error[E0277]: the trait bound `A: const Add42` is not satisfied
- --> $DIR/tilde-const-and-const-params.rs:26:61
- |
-LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
- | ^
-
-error[E0277]: the trait bound `A: const Add42` is not satisfied
- --> $DIR/tilde-const-and-const-params.rs:8:44
- |
-LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
- | ^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/tilde-const-invalid-places.rs b/tests/ui/traits/const-traits/tilde-const-invalid-places.rs
deleted file mode 100644
index 9d22068..0000000
--- a/tests/ui/traits/const-traits/tilde-const-invalid-places.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#![feature(const_trait_impl)]
-
-#[const_trait]
-trait Trait {}
-
-// Regression test for issue #90052.
-fn non_const_function<T: ~const Trait>() {} //~ ERROR `~const` is not allowed
-
-struct Struct<T: ~const Trait> { field: T } //~ ERROR `~const` is not allowed here
-struct TupleStruct<T: ~const Trait>(T); //~ ERROR `~const` is not allowed here
-struct UnitStruct<T: ~const Trait>; //~ ERROR `~const` is not allowed here
-//~^ ERROR parameter `T` is never used
-
-enum Enum<T: ~const Trait> { Variant(T) } //~ ERROR `~const` is not allowed here
-
-union Union<T: ~const Trait> { field: T } //~ ERROR `~const` is not allowed here
-//~^ ERROR field must implement `Copy`
-
-type Type<T: ~const Trait> = T; //~ ERROR `~const` is not allowed here
-
-const CONSTANT<T: ~const Trait>: () = (); //~ ERROR `~const` is not allowed here
-//~^ ERROR generic const items are experimental
-
-trait NonConstTrait {
- type Type<T: ~const Trait>: ~const Trait;
- //~^ ERROR `~const` is not allowed
- //~| ERROR `~const` is not allowed
- fn non_const_function<T: ~const Trait>(); //~ ERROR `~const` is not allowed
- const CONSTANT<T: ~const Trait>: (); //~ ERROR `~const` is not allowed
- //~^ ERROR generic const items are experimental
-}
-
-impl NonConstTrait for () {
- type Type<T: ~const Trait> = (); //~ ERROR `~const` is not allowed
- //~^ ERROR overflow evaluating the requirement `(): Trait`
- fn non_const_function<T: ~const Trait>() {} //~ ERROR `~const` is not allowed
- const CONSTANT<T: ~const Trait>: () = (); //~ ERROR `~const` is not allowed
- //~^ ERROR generic const items are experimental
-}
-
-struct Implementor;
-
-impl Implementor {
- type Type<T: ~const Trait> = (); //~ ERROR `~const` is not allowed
- //~^ ERROR inherent associated types are unstable
- fn non_const_function<T: ~const Trait>() {} //~ ERROR `~const` is not allowed
- const CONSTANT<T: ~const Trait>: () = (); //~ ERROR `~const` is not allowed
- //~^ ERROR generic const items are experimental
-}
-
-// non-const traits
-trait Child0: ~const Trait {} //~ ERROR `~const` is not allowed
-trait Child1 where Self: ~const Trait {} //~ ERROR `~const` is not allowed
-
-// non-const impl
-impl<T: ~const Trait> Trait for T {} //~ ERROR `~const` is not allowed
-
-// inherent impl (regression test for issue #117004)
-impl<T: ~const Trait> Struct<T> {} //~ ERROR `~const` is not allowed
-
-fn main() {}
diff --git a/tests/ui/traits/const-traits/tilde-const-invalid-places.stderr b/tests/ui/traits/const-traits/tilde-const-invalid-places.stderr
deleted file mode 100644
index 8151b9a..0000000
--- a/tests/ui/traits/const-traits/tilde-const-invalid-places.stderr
+++ /dev/null
@@ -1,310 +0,0 @@
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:7:26
- |
-LL | fn non_const_function<T: ~const Trait>() {}
- | ^^^^^^
- |
-note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:7:4
- |
-LL | fn non_const_function<T: ~const Trait>() {}
- | ^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:9:18
- |
-LL | struct Struct<T: ~const Trait> { field: T }
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:10:23
- |
-LL | struct TupleStruct<T: ~const Trait>(T);
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:11:22
- |
-LL | struct UnitStruct<T: ~const Trait>;
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:14:14
- |
-LL | enum Enum<T: ~const Trait> { Variant(T) }
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:16:16
- |
-LL | union Union<T: ~const Trait> { field: T }
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:19:14
- |
-LL | type Type<T: ~const Trait> = T;
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:21:19
- |
-LL | const CONSTANT<T: ~const Trait>: () = ();
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:25:18
- |
-LL | type Type<T: ~const Trait>: ~const Trait;
- | ^^^^^^
- |
-note: associated types in non-`#[const_trait]` traits cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:25:5
- |
-LL | type Type<T: ~const Trait>: ~const Trait;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:25:33
- |
-LL | type Type<T: ~const Trait>: ~const Trait;
- | ^^^^^^
- |
-note: associated types in non-`#[const_trait]` traits cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:25:5
- |
-LL | type Type<T: ~const Trait>: ~const Trait;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:28:30
- |
-LL | fn non_const_function<T: ~const Trait>();
- | ^^^^^^
- |
-note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:28:8
- |
-LL | fn non_const_function<T: ~const Trait>();
- | ^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:29:23
- |
-LL | const CONSTANT<T: ~const Trait>: ();
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:34:18
- |
-LL | type Type<T: ~const Trait> = ();
- | ^^^^^^
- |
-note: associated types in non-const impls cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:34:5
- |
-LL | type Type<T: ~const Trait> = ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:36:30
- |
-LL | fn non_const_function<T: ~const Trait>() {}
- | ^^^^^^
- |
-note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:36:8
- |
-LL | fn non_const_function<T: ~const Trait>() {}
- | ^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:37:23
- |
-LL | const CONSTANT<T: ~const Trait>: () = ();
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:44:18
- |
-LL | type Type<T: ~const Trait> = ();
- | ^^^^^^
- |
-note: inherent associated types cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:44:5
- |
-LL | type Type<T: ~const Trait> = ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:46:30
- |
-LL | fn non_const_function<T: ~const Trait>() {}
- | ^^^^^^
- |
-note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:46:8
- |
-LL | fn non_const_function<T: ~const Trait>() {}
- | ^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:47:23
- |
-LL | const CONSTANT<T: ~const Trait>: () = ();
- | ^^^^^^
- |
- = note: this item cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:52:15
- |
-LL | trait Child0: ~const Trait {}
- | ^^^^^^
- |
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:52:1
- |
-LL | trait Child0: ~const Trait {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:53:26
- |
-LL | trait Child1 where Self: ~const Trait {}
- | ^^^^^^
- |
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:53:1
- |
-LL | trait Child1 where Self: ~const Trait {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:56:9
- |
-LL | impl<T: ~const Trait> Trait for T {}
- | ^^^^^^
- |
-note: this impl is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:56:1
- |
-LL | impl<T: ~const Trait> Trait for T {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:59:9
- |
-LL | impl<T: ~const Trait> Struct<T> {}
- | ^^^^^^
- |
-note: inherent impls cannot have `~const` trait bounds
- --> $DIR/tilde-const-invalid-places.rs:59:1
- |
-LL | impl<T: ~const Trait> Struct<T> {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0658]: generic const items are experimental
- --> $DIR/tilde-const-invalid-places.rs:21:15
- |
-LL | const CONSTANT<T: ~const Trait>: () = ();
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
- = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: generic const items are experimental
- --> $DIR/tilde-const-invalid-places.rs:29:19
- |
-LL | const CONSTANT<T: ~const Trait>: ();
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
- = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: generic const items are experimental
- --> $DIR/tilde-const-invalid-places.rs:37:19
- |
-LL | const CONSTANT<T: ~const Trait>: () = ();
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
- = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: generic const items are experimental
- --> $DIR/tilde-const-invalid-places.rs:47:19
- |
-LL | const CONSTANT<T: ~const Trait>: () = ();
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
- = help: add `#![feature(generic_const_items)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0392]: type parameter `T` is never used
- --> $DIR/tilde-const-invalid-places.rs:11:19
- |
-LL | struct UnitStruct<T: ~const Trait>;
- | ^ unused type parameter
- |
- = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
- --> $DIR/tilde-const-invalid-places.rs:16:32
- |
-LL | union Union<T: ~const Trait> { field: T }
- | ^^^^^^^^
- |
- = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
-help: wrap the field type in `ManuallyDrop<...>`
- |
-LL | union Union<T: ~const Trait> { field: std::mem::ManuallyDrop<T> }
- | +++++++++++++++++++++++ +
-
-error[E0275]: overflow evaluating the requirement `(): Trait`
- --> $DIR/tilde-const-invalid-places.rs:34:34
- |
-LL | type Type<T: ~const Trait> = ();
- | ^^
- |
-note: required by a bound in `NonConstTrait::Type`
- --> $DIR/tilde-const-invalid-places.rs:25:33
- |
-LL | type Type<T: ~const Trait>: ~const Trait;
- | ^^^^^^^^^^^^ required by this bound in `NonConstTrait::Type`
-
-error[E0658]: inherent associated types are unstable
- --> $DIR/tilde-const-invalid-places.rs:44:5
- |
-LL | type Type<T: ~const Trait> = ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
- = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 30 previous errors
-
-Some errors have detailed explanations: E0275, E0392, E0658, E0740.
-For more information about an error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/const-traits/tilde-const-syntax.rs b/tests/ui/traits/const-traits/tilde-const-syntax.rs
deleted file mode 100644
index f9944c42..0000000
--- a/tests/ui/traits/const-traits/tilde-const-syntax.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ compile-flags: -Z parse-crate-root-only
-//@ check-pass
-
-#![feature(const_trait_impl)]
-
-struct S<
- T: for<'a> ~const Tr<'a> + 'static + ~const std::ops::Add,
- T: for<'a: 'b> ~const m::Trait<'a>,
->;
diff --git a/tests/ui/traits/const-traits/tilde-twice.rs b/tests/ui/traits/const-traits/tilde-twice.rs
deleted file mode 100644
index d341513..0000000
--- a/tests/ui/traits/const-traits/tilde-twice.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ compile-flags: -Z parse-crate-root-only
-
-#![feature(const_trait_impl)]
-
-struct S<T: ~const ~const Tr>;
-//~^ ERROR expected identifier, found `~`
diff --git a/tests/ui/traits/const-traits/tilde-twice.stderr b/tests/ui/traits/const-traits/tilde-twice.stderr
deleted file mode 100644
index a809736..0000000
--- a/tests/ui/traits/const-traits/tilde-twice.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected identifier, found `~`
- --> $DIR/tilde-twice.rs:5:20
- |
-LL | struct S<T: ~const ~const Tr>;
- | ^ expected identifier
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/const-traits/trait-where-clause-const.rs b/tests/ui/traits/const-traits/trait-where-clause-const.rs
index 6f281ca..ccb5140 100644
--- a/tests/ui/traits/const-traits/trait-where-clause-const.rs
+++ b/tests/ui/traits/const-traits/trait-where-clause-const.rs
@@ -12,11 +12,11 @@ trait Bar {}
#[const_trait]
trait Foo {
fn a();
- fn b() where Self: ~const Bar;
- fn c<T: ~const Bar>();
+ fn b() where Self: [const] Bar;
+ fn c<T: [const] Bar>();
}
-const fn test1<T: ~const Foo + Bar>() {
+const fn test1<T: [const] Foo + Bar>() {
T::a();
T::b();
//~^ ERROR the trait bound
@@ -24,7 +24,7 @@ const fn test1<T: ~const Foo + Bar>() {
//~^ ERROR the trait bound
}
-const fn test2<T: ~const Foo + ~const Bar>() {
+const fn test2<T: [const] Foo + [const] Bar>() {
T::a();
T::b();
T::c::<T>();
diff --git a/tests/ui/traits/const-traits/trait-where-clause-const.stderr b/tests/ui/traits/const-traits/trait-where-clause-const.stderr
index 4ebd7b9..71f9bdf 100644
--- a/tests/ui/traits/const-traits/trait-where-clause-const.stderr
+++ b/tests/ui/traits/const-traits/trait-where-clause-const.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+error[E0277]: the trait bound `T: [const] Bar` is not satisfied
--> $DIR/trait-where-clause-const.rs:21:5
|
LL | T::b();
@@ -7,10 +7,10 @@
note: required by a bound in `Foo::b`
--> $DIR/trait-where-clause-const.rs:15:24
|
-LL | fn b() where Self: ~const Bar;
- | ^^^^^^^^^^ required by this bound in `Foo::b`
+LL | fn b() where Self: [const] Bar;
+ | ^^^^^^^^^^^ required by this bound in `Foo::b`
-error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+error[E0277]: the trait bound `T: [const] Bar` is not satisfied
--> $DIR/trait-where-clause-const.rs:23:12
|
LL | T::c::<T>();
@@ -19,8 +19,8 @@
note: required by a bound in `Foo::c`
--> $DIR/trait-where-clause-const.rs:16:13
|
-LL | fn c<T: ~const Bar>();
- | ^^^^^^^^^^ required by this bound in `Foo::c`
+LL | fn c<T: [const] Bar>();
+ | ^^^^^^^^^^^ required by this bound in `Foo::c`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/trait-where-clause-run.rs b/tests/ui/traits/const-traits/trait-where-clause-run.rs
index 2582a69..c40f071 100644
--- a/tests/ui/traits/const-traits/trait-where-clause-run.rs
+++ b/tests/ui/traits/const-traits/trait-where-clause-run.rs
@@ -10,7 +10,7 @@ trait Bar {
#[const_trait]
trait Foo {
- fn foo() -> u8 where Self: ~const Bar {
+ fn foo() -> u8 where Self: [const] Bar {
<Self as Bar>::bar() * 6
}
}
diff --git a/tests/ui/traits/const-traits/trait-where-clause-self-referential.rs b/tests/ui/traits/const-traits/trait-where-clause-self-referential.rs
index b6ac574..3a5350c 100644
--- a/tests/ui/traits/const-traits/trait-where-clause-self-referential.rs
+++ b/tests/ui/traits/const-traits/trait-where-clause-self-referential.rs
@@ -4,7 +4,7 @@
#[const_trait]
trait Foo {
- fn bar() where Self: ~const Foo;
+ fn bar() where Self: [const] Foo;
}
struct S;
@@ -17,7 +17,7 @@ fn baz<T: Foo>() {
T::bar();
}
-const fn qux<T: ~const Foo>() {
+const fn qux<T: [const] Foo>() {
T::bar();
}
diff --git a/tests/ui/traits/const-traits/trait-where-clause.rs b/tests/ui/traits/const-traits/trait-where-clause.rs
index 11f353f..6aebab7 100644
--- a/tests/ui/traits/const-traits/trait-where-clause.rs
+++ b/tests/ui/traits/const-traits/trait-where-clause.rs
@@ -5,10 +5,10 @@ trait Bar {}
trait Foo {
fn a();
- fn b() where Self: ~const Bar;
- //~^ ERROR `~const` is not allowed here
- fn c<T: ~const Bar>();
- //~^ ERROR `~const` is not allowed here
+ fn b() where Self: [const] Bar;
+ //~^ ERROR `[const]` is not allowed here
+ fn c<T: [const] Bar>();
+ //~^ ERROR `[const]` is not allowed here
}
fn test1<T: Foo>() {
diff --git a/tests/ui/traits/const-traits/trait-where-clause.stderr b/tests/ui/traits/const-traits/trait-where-clause.stderr
index 3a15cc6..dda91e6 100644
--- a/tests/ui/traits/const-traits/trait-where-clause.stderr
+++ b/tests/ui/traits/const-traits/trait-where-clause.stderr
@@ -1,25 +1,25 @@
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/trait-where-clause.rs:8:24
|
-LL | fn b() where Self: ~const Bar;
- | ^^^^^^
+LL | fn b() where Self: [const] Bar;
+ | ^^^^^^^
|
-note: this function is not `const`, so it cannot have `~const` trait bounds
+note: this function is not `const`, so it cannot have `[const]` trait bounds
--> $DIR/trait-where-clause.rs:8:8
|
-LL | fn b() where Self: ~const Bar;
+LL | fn b() where Self: [const] Bar;
| ^
-error: `~const` is not allowed here
+error: `[const]` is not allowed here
--> $DIR/trait-where-clause.rs:10:13
|
-LL | fn c<T: ~const Bar>();
- | ^^^^^^
+LL | fn c<T: [const] Bar>();
+ | ^^^^^^^
|
-note: this function is not `const`, so it cannot have `~const` trait bounds
+note: this function is not `const`, so it cannot have `[const]` trait bounds
--> $DIR/trait-where-clause.rs:10:8
|
-LL | fn c<T: ~const Bar>();
+LL | fn c<T: [const] Bar>();
| ^
error[E0277]: the trait bound `T: Bar` is not satisfied
@@ -31,8 +31,8 @@
note: required by a bound in `Foo::b`
--> $DIR/trait-where-clause.rs:8:24
|
-LL | fn b() where Self: ~const Bar;
- | ^^^^^^^^^^ required by this bound in `Foo::b`
+LL | fn b() where Self: [const] Bar;
+ | ^^^^^^^^^^^ required by this bound in `Foo::b`
help: consider further restricting type parameter `T` with trait `Bar`
|
LL | fn test1<T: Foo + Bar>() {
@@ -47,8 +47,8 @@
note: required by a bound in `Foo::c`
--> $DIR/trait-where-clause.rs:10:13
|
-LL | fn c<T: ~const Bar>();
- | ^^^^^^^^^^ required by this bound in `Foo::c`
+LL | fn c<T: [const] Bar>();
+ | ^^^^^^^^^^^ required by this bound in `Foo::c`
help: consider further restricting type parameter `T` with trait `Bar`
|
LL | fn test1<T: Foo + Bar>() {
diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs
index 6d19ef7..c82b442 100644
--- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs
+++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs
@@ -29,5 +29,5 @@ fn main() {
fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
// FIXME(const_trait_impl): Instead of suggesting `+ const Trait`, suggest
-// changing `~const Trait` to `const Trait`.
-const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+// changing `[const] Trait` to `const Trait`.
+const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
index f5cadc9..3ed6dc6 100644
--- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
+++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
@@ -71,67 +71,67 @@
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
|
note: ...which requires elaborating drops for `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires borrow-checking `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires const checking `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires building MIR for `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires building an abstract representation for `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires building THIR for `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires type-checking `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires evaluating type-level constant...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `accept1::{constant#0}`...
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
= note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle
note: cycle used when const-evaluating + checking `accept1::{constant#0}`
- --> $DIR/unsatisfied-const-trait-bound.rs:33:48
+ --> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^^^^^
+LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
+ | ^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: aborting due to 3 previous errors
diff --git a/tests/ui/traits/constrained-type-params-trait-impl.rs b/tests/ui/traits/constrained-type-params-trait-impl.rs
new file mode 100644
index 0000000..301bbdb
--- /dev/null
+++ b/tests/ui/traits/constrained-type-params-trait-impl.rs
@@ -0,0 +1,75 @@
+//! Comprehensive test for type parameter constraints in trait implementations
+//!
+//! This tests various scenarios of type parameter usage in trait implementations:
+//! - Properly constrained parameters through trait bounds
+//! - Unconstrained parameters that should cause compilation errors
+//! - Complex constraint scenarios with `where` clauses and associated types
+//! - Conflicting implementations detection
+
+trait Foo<A> {
+ fn get(&self, A: &A) {}
+}
+
+trait Bar {
+ type Out;
+}
+
+impl<T> Foo<T> for [isize; 0] {
+ // OK: T is used in the trait bound `Foo<T>`
+}
+
+impl<T, U> Foo<T> for [isize; 1] {
+ //~^ ERROR the type parameter `U` is not constrained
+ // T is constrained by `Foo<T>`, but U is completely unused
+}
+
+impl<T, U> Foo<T> for [isize; 2]
+where
+ T: Bar<Out = U>,
+{
+ // OK: T is constrained by `Foo<T>`, U is constrained by the where clause
+}
+
+impl<T: Bar<Out = U>, U> Foo<T> for [isize; 3] {
+ // OK: Same as above but using bound syntax instead of where clause
+}
+
+impl<T, U> Foo<T> for U {
+ //~^ ERROR conflicting implementations of trait `Foo<_>` for type `[isize; 0]`
+ // This conflicts with the first impl when U = [isize; 0]
+}
+
+impl<T, U> Bar for T {
+ //~^ ERROR the type parameter `U` is not constrained
+ type Out = U;
+ // Using U only in associated type definition is insufficient for constraint
+}
+
+impl<T, U> Bar for T
+where
+ T: Bar<Out = U>,
+{
+ //~^^^^ ERROR the type parameter `U` is not constrained by the impl trait, self type, or predicates
+ //~| ERROR conflicting implementations of trait `Bar`
+ // Self-referential constraint doesn't properly constrain U
+}
+
+impl<T, U, V> Foo<T> for T
+where
+ (T, U): Bar<Out = V>,
+{
+ //~^^^^ ERROR the type parameter `U` is not constrained
+ //~| ERROR the type parameter `V` is not constrained
+ //~| ERROR conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]`
+ // V is bound through output type, but U and V are not properly constrained as inputs
+}
+
+impl<T, U, V> Foo<(T, U)> for T
+where
+ (T, U): Bar<Out = V>,
+{
+ //~^^^^ ERROR conflicting implementations of trait `Foo<([isize; 0], _)>` for type `[isize; 0]`
+ // Both T and U are constrained through `Foo<(T, U)>`, but creates conflicting impl
+}
+
+fn main() {}
diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/traits/constrained-type-params-trait-impl.stderr
similarity index 82%
rename from tests/ui/impl-unused-tps.stderr
rename to tests/ui/traits/constrained-type-params-trait-impl.stderr
index eff5fff..2175129 100644
--- a/tests/ui/impl-unused-tps.stderr
+++ b/tests/ui/traits/constrained-type-params-trait-impl.stderr
@@ -1,5 +1,5 @@
error[E0119]: conflicting implementations of trait `Foo<_>` for type `[isize; 0]`
- --> $DIR/impl-unused-tps.rs:28:1
+ --> $DIR/constrained-type-params-trait-impl.rs:37:1
|
LL | impl<T> Foo<T> for [isize; 0] {
| ----------------------------- first implementation here
@@ -8,7 +8,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]`
- --> $DIR/impl-unused-tps.rs:49:1
+ --> $DIR/constrained-type-params-trait-impl.rs:57:1
|
LL | impl<T> Foo<T> for [isize; 0] {
| ----------------------------- first implementation here
@@ -19,7 +19,7 @@
| |_________________________^ conflicting implementation for `[isize; 0]`
error[E0119]: conflicting implementations of trait `Foo<([isize; 0], _)>` for type `[isize; 0]`
- --> $DIR/impl-unused-tps.rs:61:1
+ --> $DIR/constrained-type-params-trait-impl.rs:67:1
|
LL | impl<T> Foo<T> for [isize; 0] {
| ----------------------------- first implementation here
@@ -30,37 +30,37 @@
| |_________________________^ conflicting implementation for `[isize; 0]`
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps.rs:13:9
+ --> $DIR/constrained-type-params-trait-impl.rs:21:9
|
LL | impl<T, U> Foo<T> for [isize; 1] {
| ^ unconstrained type parameter
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps.rs:32:9
+ --> $DIR/constrained-type-params-trait-impl.rs:42:9
|
LL | impl<T, U> Bar for T {
| ^ unconstrained type parameter
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps.rs:40:9
+ --> $DIR/constrained-type-params-trait-impl.rs:48:9
|
LL | impl<T, U> Bar for T
| ^ unconstrained type parameter
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps.rs:49:9
+ --> $DIR/constrained-type-params-trait-impl.rs:57:9
|
LL | impl<T, U, V> Foo<T> for T
| ^ unconstrained type parameter
error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps.rs:49:12
+ --> $DIR/constrained-type-params-trait-impl.rs:57:12
|
LL | impl<T, U, V> Foo<T> for T
| ^ unconstrained type parameter
error[E0119]: conflicting implementations of trait `Bar`
- --> $DIR/impl-unused-tps.rs:40:1
+ --> $DIR/constrained-type-params-trait-impl.rs:48:1
|
LL | impl<T, U> Bar for T {
| -------------------- first implementation here
diff --git a/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs b/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs
new file mode 100644
index 0000000..f5f66ca6
--- /dev/null
+++ b/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs
@@ -0,0 +1,71 @@
+//! Test various invalid implementations of DispatchFromDyn trait.
+//!
+//! DispatchFromDyn is a special trait used by the compiler for dyn-compatible dynamic dispatch.
+//! This checks that the compiler correctly rejects invalid implementations:
+//! - Structs with extra non-coercible fields
+//! - Structs with multiple pointer fields
+//! - Structs with no coercible fields
+//! - Structs with repr(C) or other incompatible representations
+//! - Structs with over-aligned fields
+
+#![feature(unsize, dispatch_from_dyn)]
+
+use std::marker::{PhantomData, Unsize};
+use std::ops::DispatchFromDyn;
+
+// Extra field prevents DispatchFromDyn
+struct WrapperWithExtraField<T>(T, i32);
+
+impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+//~^ ERROR [E0378]
+where
+ T: DispatchFromDyn<U>
+{
+}
+
+// Multiple pointer fields create ambiguous coercion
+struct MultiplePointers<T: ?Sized> {
+ ptr1: *const T,
+ ptr2: *const T,
+}
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
+where
+ T: Unsize<U>
+{
+}
+
+// No coercible fields (only PhantomData)
+struct NothingToCoerce<T: ?Sized> {
+ data: PhantomData<T>,
+}
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
+//~^ ERROR implementing `DispatchFromDyn` requires a field to be coerced
+
+// repr(C) is incompatible with DispatchFromDyn
+#[repr(C)]
+struct HasReprC<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+//~^ ERROR [E0378]
+where
+ T: Unsize<U>
+{
+}
+
+// Over-aligned fields are incompatible
+#[repr(align(64))]
+struct OverAlignedZst;
+
+struct OverAligned<T: ?Sized>(Box<T>, OverAlignedZst);
+
+impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
+//~^ ERROR [E0378]
+where
+ T: Unsize<U>
+{
+}
+
+fn main() {}
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.stderr b/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr
similarity index 76%
rename from tests/ui/invalid_dispatch_from_dyn_impls.stderr
rename to tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr
index 93ec6bb..676da0c 100644
--- a/tests/ui/invalid_dispatch_from_dyn_impls.stderr
+++ b/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr
@@ -1,25 +1,25 @@
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
- --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
+ --> $DIR/dispatch-from-dyn-invalid-impls.rs:19:1
|
LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
LL | |
LL | | where
-LL | | T: DispatchFromDyn<U>,
- | |__________________________^
+LL | | T: DispatchFromDyn<U>
+ | |_________________________^
|
= note: extra field `1` of type `i32` is not allowed
error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
- --> $DIR/invalid_dispatch_from_dyn_impls.rs:22:1
+ --> $DIR/dispatch-from-dyn-invalid-impls.rs:32:1
|
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
LL | |
LL | | where
-LL | | T: Unsize<U>,
- | |_________________^
+LL | | T: Unsize<U>
+ | |________________^
|
note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
- --> $DIR/invalid_dispatch_from_dyn_impls.rs:18:5
+ --> $DIR/dispatch-from-dyn-invalid-impls.rs:28:5
|
LL | ptr1: *const T,
| ^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@
| ^^^^^^^^^^^^^^
error[E0374]: implementing `DispatchFromDyn` requires a field to be coerced
- --> $DIR/invalid_dispatch_from_dyn_impls.rs:33:1
+ --> $DIR/dispatch-from-dyn-invalid-impls.rs:44:1
|
LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -35,22 +35,22 @@
= note: expected a single field to be coerced, none found
error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
- --> $DIR/invalid_dispatch_from_dyn_impls.rs:39:1
+ --> $DIR/dispatch-from-dyn-invalid-impls.rs:51:1
|
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
LL | |
LL | | where
-LL | | T: Unsize<U>,
- | |_________________^
+LL | | T: Unsize<U>
+ | |________________^
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
- --> $DIR/invalid_dispatch_from_dyn_impls.rs:49:1
+ --> $DIR/dispatch-from-dyn-invalid-impls.rs:64:1
|
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
LL | |
-LL | | where
-LL | | T: Unsize<U>,
- | |_____________________^
+LL | | where
+LL | | T: Unsize<U>
+ | |________________^
|
= note: extra field `1` of type `OverAlignedZst` is not allowed
diff --git a/tests/ui/issue-11881.rs b/tests/ui/traits/encoder-trait-bounds-regression.rs
similarity index 76%
rename from tests/ui/issue-11881.rs
rename to tests/ui/traits/encoder-trait-bounds-regression.rs
index 1abe079..292b921 100644
--- a/tests/ui/issue-11881.rs
+++ b/tests/ui/traits/encoder-trait-bounds-regression.rs
@@ -1,14 +1,23 @@
+//! Regression test for issue #11881
+//!
+//! Originally, the compiler would ICE when trying to parameterize on certain encoder types
+//! due to issues with higher-ranked trait bounds and lifetime inference. This test checks
+//! that various encoder patterns work correctly:
+//! - Generic encoders with associated error types
+//! - Higher-ranked trait bounds (for<'r> Encodable<JsonEncoder<'r>>)
+//! - Multiple encoder implementations for the same type
+//! - Polymorphic encoding functions
+
//@ run-pass
#![allow(unused_must_use)]
#![allow(dead_code)]
#![allow(unused_imports)]
-use std::fmt;
-use std::io::prelude::*;
use std::io::Cursor;
-use std::slice;
+use std::io::prelude::*;
use std::marker::PhantomData;
+use std::{fmt, slice};
trait Encoder {
type Error;
@@ -45,7 +54,6 @@ impl Encoder for OpaqueEncoder {
type Error = ();
}
-
struct Foo {
baz: bool,
}
@@ -69,7 +77,6 @@ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
enum WireProtocol {
JSON,
Opaque,
- // ...
}
fn encode_json<T: for<'a> Encodable<JsonEncoder<'a>>>(val: &T, wr: &mut Cursor<Vec<u8>>) {
diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.rs b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.rs
index ff577da..3fd22c7 100644
--- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.rs
+++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.rs
@@ -1,15 +1,17 @@
//@ compile-flags: -Znext-solver=coherence
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
#![recursion_limit = "10"]
trait Trait {}
-struct W<T: ?Sized>(*const T);
+struct W<T>(*const T);
trait TwoW {}
-impl<T: ?Sized + TwoW> TwoW for W<W<T>> {}
+impl<T: TwoW> TwoW for W<W<T>> {}
-impl<T: ?Sized + TwoW> Trait for W<T> {}
-impl<T: ?Sized + TwoW> Trait for T {}
+impl<T: TwoW> Trait for W<T> {}
+impl<T: TwoW> Trait for T {}
//~^ ERROR conflicting implementations of trait `Trait` for type `W
fn main() {}
diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
index 7d39c82..1827533a 100644
--- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
+++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
@@ -1,10 +1,10 @@
error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
- --> $DIR/coherence-fulfill-overflow.rs:12:1
+ --> $DIR/coherence-fulfill-overflow.rs:14:1
|
-LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
- | ------------------------------------- first implementation here
-LL | impl<T: ?Sized + TwoW> Trait for T {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
+LL | impl<T: TwoW> Trait for W<T> {}
+ | ---------------------------- first implementation here
+LL | impl<T: TwoW> Trait for T {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
index 920f8ad..9da79f7 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
@@ -1,6 +1,7 @@
//@ revisions: with without
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
// This test is incredibly subtle. At its core the goal is to get a coinductive cycle,
// which, depending on its root goal, either holds or errors. We achieve this by getting
@@ -17,20 +18,20 @@
// test for that.
#[rustc_coinductive]
-trait Trait<T: ?Sized, V: ?Sized, D: ?Sized> {}
-struct A<T: ?Sized>(*const T);
-struct B<T: ?Sized>(*const T);
+trait Trait<T, V, D> {}
+struct A<T>(*const T);
+struct B<T>(*const T);
-trait IncompleteGuidance<T: ?Sized, V: ?Sized> {}
-impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, u8> for T {}
-impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i8> for T {}
-impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i16> for T {}
+trait IncompleteGuidance<T, V> {}
+impl<T, U: 'static> IncompleteGuidance<U, u8> for T {}
+impl<T, U: 'static> IncompleteGuidance<U, i8> for T {}
+impl<T, U: 'static> IncompleteGuidance<U, i16> for T {}
-trait ImplGuidance<T: ?Sized, V: ?Sized> {}
-impl<T: ?Sized> ImplGuidance<u32, u8> for T {}
-impl<T: ?Sized> ImplGuidance<i32, i8> for T {}
+trait ImplGuidance<T, V> {}
+impl<T> ImplGuidance<u32, u8> for T {}
+impl<T> ImplGuidance<i32, i8> for T {}
-impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
+impl<T, U, V, D> Trait<U, V, D> for A<T>
where
T: IncompleteGuidance<U, V>,
A<T>: Trait<U, D, V>,
@@ -39,17 +40,17 @@ impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
{
}
-trait ToU8<T: ?Sized> {}
+trait ToU8<T> {}
impl ToU8<u8> for () {}
-impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for B<T>
+impl<T, U, V, D> Trait<U, V, D> for B<T>
where
T: ImplGuidance<U, V>,
A<T>: Trait<U, V, D>,
{
}
-fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
+fn impls_trait<T: Trait<U, V, D>, U, V, D>() {}
fn with_bound<X>()
where
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
index 9114bca..d27104d 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
@@ -1,25 +1,25 @@
error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
- --> $DIR/incompleteness-unstable-result.rs:65:19
+ --> $DIR/incompleteness-unstable-result.rs:66:19
|
LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`
|
= help: the trait `Trait<U, V, D>` is implemented for `A<T>`
note: required for `A<X>` to implement `Trait<_, _, _>`
- --> $DIR/incompleteness-unstable-result.rs:33:50
+ --> $DIR/incompleteness-unstable-result.rs:34:18
|
-LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
- | ^^^^^^^^^^^^^^ ^^^^
+LL | impl<T, U, V, D> Trait<U, V, D> for A<T>
+ | ^^^^^^^^^^^^^^ ^^^^
...
LL | A<T>: Trait<U, D, V>,
| -------------- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<_, _, _>`
note: required by a bound in `impls_trait`
- --> $DIR/incompleteness-unstable-result.rs:52:28
+ --> $DIR/incompleteness-unstable-result.rs:53:19
|
-LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
- | ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+LL | fn impls_trait<T: Trait<U, V, D>, U, V, D>() {}
+ | ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
index 9114bca..d27104d 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
@@ -1,25 +1,25 @@
error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
- --> $DIR/incompleteness-unstable-result.rs:65:19
+ --> $DIR/incompleteness-unstable-result.rs:66:19
|
LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`
|
= help: the trait `Trait<U, V, D>` is implemented for `A<T>`
note: required for `A<X>` to implement `Trait<_, _, _>`
- --> $DIR/incompleteness-unstable-result.rs:33:50
+ --> $DIR/incompleteness-unstable-result.rs:34:18
|
-LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
- | ^^^^^^^^^^^^^^ ^^^^
+LL | impl<T, U, V, D> Trait<U, V, D> for A<T>
+ | ^^^^^^^^^^^^^^ ^^^^
...
LL | A<T>: Trait<U, D, V>,
| -------------- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<_, _, _>`
note: required by a bound in `impls_trait`
- --> $DIR/incompleteness-unstable-result.rs:52:28
+ --> $DIR/incompleteness-unstable-result.rs:53:19
|
-LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
- | ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+LL | fn impls_trait<T: Trait<U, V, D>, U, V, D>() {}
+ | ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
index f7ed0e1..326d888 100644
--- a/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
+++ b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
@@ -1,23 +1,24 @@
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
// Check that we correctly rerun the trait solver for heads of cycles,
// even if they are not the root.
-struct A<T: ?Sized>(*const T);
-struct B<T: ?Sized>(*const T);
-struct C<T: ?Sized>(*const T);
+struct A<T>(*const T);
+struct B<T>(*const T);
+struct C<T>(*const T);
#[rustc_coinductive]
trait Trait<'a, 'b> {}
trait NotImplemented {}
-impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for A<T> where B<T>: Trait<'a, 'b> {}
+impl<'a, 'b, T> Trait<'a, 'b> for A<T> where B<T>: Trait<'a, 'b> {}
// With this the root of `B<T>` is `A<T>`, even if the other impl does
// not have a cycle with `A<T>`. This candidate never applies because of
// the `A<T>: NotImplemented` bound.
-impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for B<T>
+impl<'a, 'b, T> Trait<'a, 'b> for B<T>
where
A<T>: Trait<'a, 'b>,
A<T>: NotImplemented,
@@ -31,7 +32,7 @@ impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for B<T>
// use the impl itself to prove that adds region constraints as we uniquified the
// regions in the `A<T>: Trait<'a, 'b>` where-bound. As both the impl above
// and the impl below now apply with some constraints, we failed with ambiguity.
-impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for B<T>
+impl<'a, 'b, T> Trait<'a, 'b> for B<T>
where
A<T>: NotImplemented,
{}
@@ -40,7 +41,7 @@ impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for B<T>
//
// Because of the coinductive cycle through `C<T>` it also requires
// 'a to be 'static.
-impl<'a, T: ?Sized> Trait<'a, 'static> for B<T>
+impl<'a, T> Trait<'a, 'static> for B<T>
where
C<T>: Trait<'a, 'a>,
{}
@@ -48,14 +49,14 @@ impl<'a, T: ?Sized> Trait<'a, 'static> for B<T>
// In the first iteration of `B<T>: Trait<'a, 'b>` we don't add any
// constraints here, only after setting the provisional result to require
// `'b == 'static` do we also add that constraint for `'a`.
-impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for C<T>
+impl<'a, 'b, T> Trait<'a, 'b> for C<T>
where
B<T>: Trait<'a, 'b>,
{}
-fn impls_trait<'a, 'b, T: Trait<'a, 'b> + ?Sized>() {}
+fn impls_trait<'a, 'b, T: Trait<'a, 'b>>() {}
-fn check<'a, T: ?Sized>() {
+fn check<'a, T>() {
impls_trait::<'a, 'static, A<T>>();
//~^ ERROR lifetime may not live long enough
}
diff --git a/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr
index 0cbd965..c880817 100644
--- a/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr
+++ b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr
@@ -1,7 +1,7 @@
error: lifetime may not live long enough
- --> $DIR/fixpoint-rerun-all-cycle-heads.rs:59:5
+ --> $DIR/fixpoint-rerun-all-cycle-heads.rs:60:5
|
-LL | fn check<'a, T: ?Sized>() {
+LL | fn check<'a, T>() {
| -- lifetime `'a` defined here
LL | impls_trait::<'a, 'static, A<T>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs
index 9cbcc5a..12feb1e 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs
+++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs
@@ -1,4 +1,6 @@
//@ compile-flags: -Znext-solver
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
// This currently hangs if we do not erase constraints from
// overflow.
@@ -17,9 +19,9 @@
// the solver to hang without hitting the recursion limit.
trait Trait {}
-struct W<T: ?Sized>(*const T);
+struct W<T>(*const T);
-impl<T: ?Sized> Trait for W<W<T>>
+impl<T> Trait for W<W<T>>
where
W<T>: Trait,
W<T>: Trait,
diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
index a2a5c02..5ba3c51 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
@@ -1,11 +1,11 @@
error[E0275]: overflow evaluating the requirement `W<_>: Trait`
- --> $DIR/inductive-fixpoint-hang.rs:31:19
+ --> $DIR/inductive-fixpoint-hang.rs:33:19
|
LL | impls_trait::<W<_>>();
| ^^^^
|
note: required by a bound in `impls_trait`
- --> $DIR/inductive-fixpoint-hang.rs:28:19
+ --> $DIR/inductive-fixpoint-hang.rs:30:19
|
LL | fn impls_trait<T: Trait>() {}
| ^^^^^ required by this bound in `impls_trait`
diff --git a/tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs b/tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs
index b005b90..88a1196 100644
--- a/tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs
+++ b/tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs
@@ -1,6 +1,7 @@
//@ compile-flags: -Znext-solver
//@ check-pass
#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
// A test showcasing that using a provisional cache can differ
// from only tracking stack entries.
@@ -59,9 +60,9 @@ trait B {}
#[rustc_coinductive]
trait C {}
-impl<T: ?Sized + B + C> A for T {}
-impl<T: ?Sized + A + C> B for T {}
-impl<T: ?Sized + B> C for T {}
+impl<T: B + C> A for T {}
+impl<T: A + C> B for T {}
+impl<T: B> C for T {}
fn impls_a<T: A>() {}
diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
index 57f814b..a2ed73b 100644
--- a/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
+++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
@@ -1,4 +1,6 @@
//@ compile-flags: -Znext-solver
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
trait Tr<'a> {}
@@ -16,9 +18,9 @@ trait Tr<'a> {}
// Then, when we recompute the goal `W<?0>: Constrain<'error>`, when
// collecting ambiguities and overflows, we end up assembling a default
// error candidate w/o ambiguity, which causes the goal to pass, and ICE.
-impl<'a, A: ?Sized> Tr<'a> for W<A> {}
-struct W<A: ?Sized>(A);
-impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {}
+impl<'a, A> Tr<'a> for W<A> {}
+struct W<A>(A);
+impl<'a, A> Tr<'a> for A where A: Constrain<'a> {}
//~^ ERROR conflicting implementations of trait `Tr<'_>` for type `W<_>`
trait Constrain<'a> {}
diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr
index 989ee1c..867efd4 100644
--- a/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr
+++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr
@@ -1,5 +1,5 @@
error[E0261]: use of undeclared lifetime name `'missing`
- --> $DIR/dont-canonicalize-re-error.rs:25:26
+ --> $DIR/dont-canonicalize-re-error.rs:27:26
|
LL | impl<A: Sized> Constrain<'missing> for W<A> {}
| ^^^^^^^^ undeclared lifetime
@@ -10,13 +10,13 @@
| +++++++++
error[E0119]: conflicting implementations of trait `Tr<'_>` for type `W<_>`
- --> $DIR/dont-canonicalize-re-error.rs:21:1
+ --> $DIR/dont-canonicalize-re-error.rs:23:1
|
-LL | impl<'a, A: ?Sized> Tr<'a> for W<A> {}
- | ----------------------------------- first implementation here
-LL | struct W<A: ?Sized>(A);
-LL | impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+LL | impl<'a, A> Tr<'a> for W<A> {}
+ | --------------------------- first implementation here
+LL | struct W<A>(A);
+LL | impl<'a, A> Tr<'a> for A where A: Constrain<'a> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/next-solver/normalize/normalize-region-obligations.rs b/tests/ui/traits/next-solver/normalize/normalize-region-obligations.rs
index c4c2e69..e1ffa4e 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-region-obligations.rs
+++ b/tests/ui/traits/next-solver/normalize/normalize-region-obligations.rs
@@ -1,6 +1,8 @@
//@ revisions: normalize_param_env normalize_obligation hrtb
//@ check-pass
//@ compile-flags: -Znext-solver
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
trait Foo {
#[cfg(normalize_param_env)]
@@ -11,11 +13,11 @@ trait Foo {
type Gat<'b> where for<'a> <Self as MirrorRegion<'a>>::Assoc: 'b;
}
-trait Mirror { type Assoc: ?Sized; }
-impl<T: ?Sized> Mirror for T { type Assoc = T; }
+trait Mirror { type Assoc; }
+impl<T> Mirror for T { type Assoc = T; }
-trait MirrorRegion<'a> { type Assoc: ?Sized; }
-impl<'a, T: ?Sized> MirrorRegion<'a> for T { type Assoc = T; }
+trait MirrorRegion<'a> { type Assoc; }
+impl<'a, T> MirrorRegion<'a> for T { type Assoc = T; }
impl<T> Foo for T {
#[cfg(normalize_param_env)]
diff --git a/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs b/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs
index f88f746..4874e2e 100644
--- a/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs
+++ b/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs
@@ -4,16 +4,18 @@
// Regression test for nalgebra hang <https://github.com/rust-lang/rust/issues/130056>.
#![feature(lazy_type_alias)]
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
#![allow(incomplete_features)]
-type Id<T: ?Sized> = T;
+type Id<T> = T;
trait NotImplemented {}
-struct W<T: ?Sized, U: ?Sized>(*const T, *const U);
+struct W<T, U>(*const T, *const U);
trait Trait {
- type Assoc: ?Sized;
+ type Assoc;
}
-impl<T: ?Sized + Trait> Trait for W<T, T> {
+impl<T: Trait> Trait for W<T, T> {
#[cfg(ai)]
type Assoc = W<T::Assoc, Id<T::Assoc>>;
#[cfg(ia)]
@@ -22,8 +24,8 @@ impl<T: ?Sized + Trait> Trait for W<T, T> {
type Assoc = W<Id<T::Assoc>, Id<T::Assoc>>;
}
-trait Overlap<T: ?Sized> {}
-impl<T: ?Sized> Overlap<T> for W<T, T> {}
-impl<T: ?Sized + Trait + NotImplemented> Overlap<T::Assoc> for T {}
+trait Overlap<T> {}
+impl<T> Overlap<T> for W<T, T> {}
+impl<T: Trait + NotImplemented> Overlap<T::Assoc> for T {}
fn main() {}
diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs b/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs
index dee5500..e5a57a4 100644
--- a/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs
+++ b/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs
@@ -1,5 +1,7 @@
//@ compile-flags: -Znext-solver=coherence
//@ check-pass
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
// A regression test for trait-system-refactor-initiative#70.
@@ -7,8 +9,8 @@ trait Trait {
type Assoc;
}
-struct W<T: ?Sized>(*mut T);
-impl<T: ?Sized> Trait for W<W<T>>
+struct W<T>(*mut T);
+impl<T> Trait for W<W<T>>
where
W<T>: Trait,
{
@@ -20,6 +22,6 @@ impl<T: Trait<Assoc = u32>> NoOverlap for T {}
// `Projection(<W<_> as Trait>::Assoc, u32)` should result in error even
// though applying the impl results in overflow. This is necessary to match
// the behavior of the old solver.
-impl<T: ?Sized> NoOverlap for W<T> {}
+impl<T> NoOverlap for W<T> {}
fn main() {}
diff --git a/tests/ui/traits/next-solver/supertrait-alias-1.rs b/tests/ui/traits/next-solver/supertrait-alias-1.rs
index 579a446..2671eed 100644
--- a/tests/ui/traits/next-solver/supertrait-alias-1.rs
+++ b/tests/ui/traits/next-solver/supertrait-alias-1.rs
@@ -1,5 +1,7 @@
//@ compile-flags: -Znext-solver
//@ check-pass
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/171>.
// Tests that we don't try to replace `<V as Super>::Output` when replacing projections in the
@@ -13,9 +15,9 @@ pub trait Super {
type Output;
}
-fn bound<T: Trait + ?Sized>() {}
+fn bound<T: Trait>() {}
-fn visit_simd_operator<V: Super + ?Sized>() {
+fn visit_simd_operator<V: Super>() {
bound::<dyn Trait<Output = <V as Super>::Output>>();
}
diff --git a/tests/ui/traits/overflow-computing-ambiguity.rs b/tests/ui/traits/overflow-computing-ambiguity.rs
index b8f11ef..88eeca5 100644
--- a/tests/ui/traits/overflow-computing-ambiguity.rs
+++ b/tests/ui/traits/overflow-computing-ambiguity.rs
@@ -1,12 +1,15 @@
+#![feature(rustc_attrs)]
+#![rustc_no_implicit_bounds]
+
trait Hello {}
-struct Foo<'a, T: ?Sized>(&'a T);
+struct Foo<'a, T>(&'a T);
-impl<'a, T: ?Sized> Hello for Foo<'a, &'a T> where Foo<'a, T>: Hello {}
+impl<'a, T> Hello for Foo<'a, &'a T> where Foo<'a, T>: Hello {}
impl Hello for Foo<'static, i32> {}
-fn hello<T: ?Sized + Hello>() {}
+fn hello<T: Hello>() {}
fn main() {
hello();
diff --git a/tests/ui/traits/overflow-computing-ambiguity.stderr b/tests/ui/traits/overflow-computing-ambiguity.stderr
index a2e2558..f3e91a2 100644
--- a/tests/ui/traits/overflow-computing-ambiguity.stderr
+++ b/tests/ui/traits/overflow-computing-ambiguity.stderr
@@ -1,5 +1,5 @@
error[E0283]: type annotations needed
- --> $DIR/overflow-computing-ambiguity.rs:12:5
+ --> $DIR/overflow-computing-ambiguity.rs:15:5
|
LL | hello();
| ^^^^^ cannot infer type of the type parameter `T` declared on the function `hello`
@@ -9,10 +9,10 @@
Foo<'a, &'a T>
Foo<'static, i32>
note: required by a bound in `hello`
- --> $DIR/overflow-computing-ambiguity.rs:9:22
+ --> $DIR/overflow-computing-ambiguity.rs:12:13
|
-LL | fn hello<T: ?Sized + Hello>() {}
- | ^^^^^ required by this bound in `hello`
+LL | fn hello<T: Hello>() {}
+ | ^^^^^ required by this bound in `hello`
help: consider specifying the generic argument
|
LL | hello::<T>();
diff --git a/tests/ui/transmute/diverging-fn-transmute.rs b/tests/ui/transmute/diverging-fn-transmute.rs
new file mode 100644
index 0000000..aca8203
--- /dev/null
+++ b/tests/ui/transmute/diverging-fn-transmute.rs
@@ -0,0 +1,10 @@
+//! Regression test for issue #35849: transmute with panic in diverging function
+
+fn assert_sizeof() -> ! {
+ unsafe {
+ ::std::mem::transmute::<f64, [u8; 8]>(panic!())
+ //~^ ERROR mismatched types
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/diverging-fn-tail-35849.stderr b/tests/ui/transmute/diverging-fn-transmute.stderr
similarity index 91%
rename from tests/ui/diverging-fn-tail-35849.stderr
rename to tests/ui/transmute/diverging-fn-transmute.stderr
index 614f9b9..b9aeae7 100644
--- a/tests/ui/diverging-fn-tail-35849.stderr
+++ b/tests/ui/transmute/diverging-fn-transmute.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/diverging-fn-tail-35849.rs:3:9
+ --> $DIR/diverging-fn-transmute.rs:5:9
|
LL | fn assert_sizeof() -> ! {
| - expected `!` because of return type
diff --git a/tests/ui/typeck/issue-74086.rs b/tests/ui/typeck/issue-74086.rs
index 9b7c0d7..1993cc7 100644
--- a/tests/ui/typeck/issue-74086.rs
+++ b/tests/ui/typeck/issue-74086.rs
@@ -1,5 +1,4 @@
fn main() {
static BUG: fn(_) -> u8 = |_| 8;
- //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions [E0121]
- //~| ERROR the placeholder `_` is not allowed within types on item signatures for static items
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static items
}
diff --git a/tests/ui/typeck/issue-74086.stderr b/tests/ui/typeck/issue-74086.stderr
index 95ebf9a..25f454a 100644
--- a/tests/ui/typeck/issue-74086.stderr
+++ b/tests/ui/typeck/issue-74086.stderr
@@ -1,15 +1,9 @@
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/issue-74086.rs:2:20
- |
-LL | static BUG: fn(_) -> u8 = |_| 8;
- | ^ not allowed in type signatures
-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static items
--> $DIR/issue-74086.rs:2:20
|
LL | static BUG: fn(_) -> u8 = |_| 8;
| ^ not allowed in type signatures
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/typeck/issue-81885.rs b/tests/ui/typeck/issue-81885.rs
index fb39494..d73c77b 100644
--- a/tests/ui/typeck/issue-81885.rs
+++ b/tests/ui/typeck/issue-81885.rs
@@ -1,9 +1,7 @@
const TEST4: fn() -> _ = 42;
- //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
- //~| ERROR the placeholder `_` is not allowed within types on item signatures for constant items
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constant items
fn main() {
const TEST5: fn() -> _ = 42;
- //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
- //~| ERROR the placeholder `_` is not allowed within types on item signatures for constant items
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constant items
}
diff --git a/tests/ui/typeck/issue-81885.stderr b/tests/ui/typeck/issue-81885.stderr
index 91c08bd..25a6bb6 100644
--- a/tests/ui/typeck/issue-81885.stderr
+++ b/tests/ui/typeck/issue-81885.stderr
@@ -1,27 +1,15 @@
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/issue-81885.rs:1:22
- |
-LL | const TEST4: fn() -> _ = 42;
- | ^ not allowed in type signatures
-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constant items
--> $DIR/issue-81885.rs:1:22
|
LL | const TEST4: fn() -> _ = 42;
| ^ not allowed in type signatures
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/issue-81885.rs:6:26
- |
-LL | const TEST5: fn() -> _ = 42;
- | ^ not allowed in type signatures
-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constant items
- --> $DIR/issue-81885.rs:6:26
+ --> $DIR/issue-81885.rs:5:26
|
LL | const TEST5: fn() -> _ = 42;
| ^ not allowed in type signatures
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/typeck/type-placeholder-fn-in-const.rs b/tests/ui/typeck/type-placeholder-fn-in-const.rs
index bbb95a5..1600534 100644
--- a/tests/ui/typeck/type-placeholder-fn-in-const.rs
+++ b/tests/ui/typeck/type-placeholder-fn-in-const.rs
@@ -2,14 +2,12 @@
trait Test {
const TEST: fn() -> _;
- //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121]
- //~| ERROR: the placeholder `_` is not allowed within types on item signatures for associated constants [E0121]
+ //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for associated constants [E0121]
}
impl Test for MyStruct {
const TEST: fn() -> _ = 42;
- //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121]
- //~| ERROR: the placeholder `_` is not allowed within types on item signatures for associated constants [E0121]
+ //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for associated constants [E0121]
}
fn main() {}
diff --git a/tests/ui/typeck/type-placeholder-fn-in-const.stderr b/tests/ui/typeck/type-placeholder-fn-in-const.stderr
index 92b47bd..a297529 100644
--- a/tests/ui/typeck/type-placeholder-fn-in-const.stderr
+++ b/tests/ui/typeck/type-placeholder-fn-in-const.stderr
@@ -1,17 +1,5 @@
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/type-placeholder-fn-in-const.rs:10:25
- |
-LL | const TEST: fn() -> _ = 42;
- | ^ not allowed in type signatures
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/type-placeholder-fn-in-const.rs:4:25
- |
-LL | const TEST: fn() -> _;
- | ^ not allowed in type signatures
-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
- --> $DIR/type-placeholder-fn-in-const.rs:10:25
+ --> $DIR/type-placeholder-fn-in-const.rs:9:25
|
LL | const TEST: fn() -> _ = 42;
| ^ not allowed in type signatures
@@ -22,6 +10,6 @@
LL | const TEST: fn() -> _;
| ^ not allowed in type signatures
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs
index d7351f2..dc79036 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item.rs
@@ -33,7 +33,6 @@ fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
fn test8(_f: fn() -> _) { }
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
-//~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
struct Test9;
@@ -67,6 +66,8 @@ struct Test10 {
a: _,
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
b: (_, _),
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
}
pub fn main() {
@@ -99,7 +100,6 @@ fn fn_test6(_: _) { }
fn fn_test8(_f: fn() -> _) { }
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
- //~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
struct FnTest9;
@@ -123,6 +123,8 @@ struct FnTest10 {
a: _,
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
b: (_, _),
+ //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
}
fn fn_test11(_: _) -> (_, _) { panic!() }
@@ -141,12 +143,14 @@ trait T {
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn method_test2(&self, x: _) -> _;
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn method_test3(&self) -> _;
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn assoc_fn_test1(x: _);
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn assoc_fn_test2(x: _) -> _;
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn assoc_fn_test3() -> _;
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
}
@@ -158,9 +162,11 @@ trait BadTrait<_> {}
//~^ ERROR expected identifier, found reserved identifier `_`
impl BadTrait<_> for BadStruct<_> {}
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for implementations
fn impl_trait() -> impl BadTrait<_> {
-//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
unimplemented!()
}
@@ -180,7 +186,8 @@ fn impl_trait() -> impl BadTrait<_> {
trait Trait<T> {}
impl Trait<usize> for Struct {}
type Y = impl Trait<_>;
-//~^ ERROR the placeholder `_` is not allowed within types on item signatures for type aliases
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
#[define_opaque(Y)]
fn foo() -> Y {
Struct
@@ -197,6 +204,7 @@ trait Qux {
// type E: _; // FIXME: make the parser propagate the existence of `B`
type F: std::ops::Fn(_);
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+ //~| ERROR the placeholder `_` is not allowed within types on item signatures for associated types
}
impl Qux for Struct {
//~^ ERROR not all trait items implemented, missing: `F`
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index 7184244..53476f6 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -1,35 +1,35 @@
error: expected identifier, found reserved identifier `_`
- --> $DIR/typeck_type_placeholder_item.rs:154:18
+ --> $DIR/typeck_type_placeholder_item.rs:158:18
|
LL | struct BadStruct<_>(_);
| ^ expected identifier, found reserved identifier
error: expected identifier, found reserved identifier `_`
- --> $DIR/typeck_type_placeholder_item.rs:157:16
+ --> $DIR/typeck_type_placeholder_item.rs:161:16
|
LL | trait BadTrait<_> {}
| ^ expected identifier, found reserved identifier
error: expected identifier, found reserved identifier `_`
- --> $DIR/typeck_type_placeholder_item.rs:167:19
+ --> $DIR/typeck_type_placeholder_item.rs:173:19
|
LL | struct BadStruct1<_, _>(_);
| ^ expected identifier, found reserved identifier
error: expected identifier, found reserved identifier `_`
- --> $DIR/typeck_type_placeholder_item.rs:167:22
+ --> $DIR/typeck_type_placeholder_item.rs:173:22
|
LL | struct BadStruct1<_, _>(_);
| ^ expected identifier, found reserved identifier
error: expected identifier, found reserved identifier `_`
- --> $DIR/typeck_type_placeholder_item.rs:172:19
+ --> $DIR/typeck_type_placeholder_item.rs:178:19
|
LL | struct BadStruct2<_, T>(_, T);
| ^ expected identifier, found reserved identifier
error: associated constant in `impl` without body
- --> $DIR/typeck_type_placeholder_item.rs:207:5
+ --> $DIR/typeck_type_placeholder_item.rs:215:5
|
LL | const C: _;
| ^^^^^^^^^^-
@@ -37,7 +37,7 @@
| help: provide a definition for the constant: `= <expr>;`
error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters
- --> $DIR/typeck_type_placeholder_item.rs:167:22
+ --> $DIR/typeck_type_placeholder_item.rs:173:22
|
LL | struct BadStruct1<_, _>(_);
| - ^ already used
@@ -106,72 +106,87 @@
|
LL | fn test6(_: _) { }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn test6(_: _) { }
-LL + fn test6<T>(_: T) { }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:25:18
|
LL | fn test6_b<T>(_: _, _: T) { }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn test6_b<T>(_: _, _: T) { }
-LL + fn test6_b<T, U>(_: U, _: T) { }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:28:30
|
LL | fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
-LL + fn test6_c<T, K, L, A, B, U>(_: U, _: (T, K, L, A, B)) { }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:31:13
|
LL | fn test7(x: _) { let _x: usize = x; }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn test7(x: _) { let _x: usize = x; }
-LL + fn test7<T>(x: T) { let _x: usize = x; }
- |
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:34:22
- |
-LL | fn test8(_f: fn() -> _) { }
- | ^
- | |
- | not allowed in type signatures
- | help: use type parameters instead: `T`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:34:22
|
LL | fn test8(_f: fn() -> _) { }
| ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:66:8
|
-help: use type parameters instead
+LL | a: _,
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:68:9
|
-LL - fn test8(_f: fn() -> _) { }
-LL + fn test8<T>(_f: fn() -> T) { }
+LL | b: (_, _),
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:68:12
|
+LL | b: (_, _),
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:123:12
+ |
+LL | a: _,
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:125:13
+ |
+LL | b: (_, _),
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:125:16
+ |
+LL | b: (_, _),
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:158:21
+ |
+LL | struct BadStruct<_>(_);
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:173:25
+ |
+LL | struct BadStruct1<_, _>(_);
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+ --> $DIR/typeck_type_placeholder_item.rs:178:25
+ |
+LL | struct BadStruct2<_, T>(_, T);
+ | ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:48:26
+ --> $DIR/typeck_type_placeholder_item.rs:47:26
|
LL | fn test11(x: &usize) -> &_ {
| -^
@@ -180,7 +195,7 @@
| help: replace with the correct return type: `&&usize`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:53:52
+ --> $DIR/typeck_type_placeholder_item.rs:52:52
|
LL | unsafe fn test12(x: *const usize) -> *const *const _ {
| --------------^
@@ -189,7 +204,7 @@
| help: replace with the correct return type: `*const *const usize`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:59:24
+ --> $DIR/typeck_type_placeholder_item.rs:58:24
|
LL | fn clone(&self) -> _ { Test9 }
| ^ not allowed in type signatures
@@ -201,7 +216,7 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:62:37
+ --> $DIR/typeck_type_placeholder_item.rs:61:37
|
LL | fn clone_from(&mut self, other: _) { *self = Test9; }
| ^ not allowed in type signatures
@@ -212,33 +227,14 @@
LL + fn clone_from(&mut self, other: &Test9) { *self = Test9; }
|
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/typeck_type_placeholder_item.rs:67:8
- |
-LL | a: _,
- | ^ not allowed in type signatures
-LL |
-LL | b: (_, _),
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL ~ struct Test10<T> {
-LL ~ a: T,
-LL |
-LL ~ b: (T, T),
- |
-
error: missing type for `static` item
- --> $DIR/typeck_type_placeholder_item.rs:73:13
+ --> $DIR/typeck_type_placeholder_item.rs:74:13
|
LL | static A = 42;
| ^ help: provide a type for the static variable: `: i32`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
- --> $DIR/typeck_type_placeholder_item.rs:75:15
+ --> $DIR/typeck_type_placeholder_item.rs:76:15
|
LL | static B: _ = 42;
| ^ not allowed in type signatures
@@ -250,7 +246,7 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
- --> $DIR/typeck_type_placeholder_item.rs:77:22
+ --> $DIR/typeck_type_placeholder_item.rs:78:22
|
LL | static C: Option<_> = Some(42);
| ^ not allowed in type signatures
@@ -262,7 +258,7 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:79:21
+ --> $DIR/typeck_type_placeholder_item.rs:80:21
|
LL | fn fn_test() -> _ { 5 }
| ^
@@ -271,7 +267,7 @@
| help: replace with the correct return type: `i32`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:82:23
+ --> $DIR/typeck_type_placeholder_item.rs:83:23
|
LL | fn fn_test2() -> (_, _) { (5, 5) }
| -^--^-
@@ -281,7 +277,7 @@
| help: replace with the correct return type: `(i32, i32)`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
- --> $DIR/typeck_type_placeholder_item.rs:85:22
+ --> $DIR/typeck_type_placeholder_item.rs:86:22
|
LL | static FN_TEST3: _ = "test";
| ^ not allowed in type signatures
@@ -293,7 +289,7 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
- --> $DIR/typeck_type_placeholder_item.rs:88:22
+ --> $DIR/typeck_type_placeholder_item.rs:89:22
|
LL | static FN_TEST4: _ = 145;
| ^ not allowed in type signatures
@@ -305,7 +301,7 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
- --> $DIR/typeck_type_placeholder_item.rs:91:23
+ --> $DIR/typeck_type_placeholder_item.rs:92:23
|
LL | static FN_TEST5: (_, _) = (1, 2);
| ^ ^ not allowed in type signatures
@@ -319,49 +315,22 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:94:20
+ --> $DIR/typeck_type_placeholder_item.rs:95:20
|
LL | fn fn_test6(_: _) { }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn fn_test6(_: _) { }
-LL + fn fn_test6<T>(_: T) { }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:97:20
+ --> $DIR/typeck_type_placeholder_item.rs:98:20
|
LL | fn fn_test7(x: _) { let _x: usize = x; }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn fn_test7(x: _) { let _x: usize = x; }
-LL + fn fn_test7<T>(x: T) { let _x: usize = x; }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:100:29
- |
-LL | fn fn_test8(_f: fn() -> _) { }
- | ^
- | |
- | not allowed in type signatures
- | help: use type parameters instead: `T`
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:100:29
+ --> $DIR/typeck_type_placeholder_item.rs:101:29
|
LL | fn fn_test8(_f: fn() -> _) { }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn fn_test8(_f: fn() -> _) { }
-LL + fn fn_test8<T>(_f: fn() -> T) { }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:115:28
@@ -387,33 +356,14 @@
LL + fn clone_from(&mut self, other: &FnTest9) { *self = FnTest9; }
|
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/typeck_type_placeholder_item.rs:123:12
- |
-LL | a: _,
- | ^ not allowed in type signatures
-LL |
-LL | b: (_, _),
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL ~ struct FnTest10<T> {
-LL ~ a: T,
-LL |
-LL ~ b: (T, T),
- |
-
error[E0282]: type annotations needed
- --> $DIR/typeck_type_placeholder_item.rs:128:21
+ --> $DIR/typeck_type_placeholder_item.rs:130:21
|
LL | fn fn_test11(_: _) -> (_, _) { panic!() }
| ^ cannot infer type
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:128:28
+ --> $DIR/typeck_type_placeholder_item.rs:130:28
|
LL | fn fn_test11(_: _) -> (_, _) { panic!() }
| ^ ^ not allowed in type signatures
@@ -421,7 +371,7 @@
| not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:132:30
+ --> $DIR/typeck_type_placeholder_item.rs:134:30
|
LL | fn fn_test12(x: i32) -> (_, _) { (x, x) }
| -^--^-
@@ -431,7 +381,7 @@
| help: replace with the correct return type: `(i32, i32)`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:135:33
+ --> $DIR/typeck_type_placeholder_item.rs:137:33
|
LL | fn fn_test13(x: _) -> (i32, _) { (x, x) }
| ------^-
@@ -439,152 +389,116 @@
| | not allowed in type signatures
| help: replace with the correct return type: `(i32, i32)`
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/typeck_type_placeholder_item.rs:154:21
- |
-LL | struct BadStruct<_>(_);
- | ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - struct BadStruct<_>(_);
-LL + struct BadStruct<T>(T);
- |
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:140:31
- |
-LL | fn method_test1(&self, x: _);
- | ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn method_test1(&self, x: _);
-LL + fn method_test1<T>(&self, x: T);
- |
-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:142:31
|
-LL | fn method_test2(&self, x: _) -> _;
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn method_test2(&self, x: _) -> _;
-LL + fn method_test2<T>(&self, x: T) -> T;
- |
+LL | fn method_test1(&self, x: _);
+ | ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/typeck_type_placeholder_item.rs:144:31
|
-LL | fn method_test3(&self) -> _;
+LL | fn method_test2(&self, x: _) -> _;
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn method_test3(&self) -> _;
-LL + fn method_test3<T>(&self) -> T;
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:146:26
+ --> $DIR/typeck_type_placeholder_item.rs:144:37
+ |
+LL | fn method_test2(&self, x: _) -> _;
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/typeck_type_placeholder_item.rs:147:31
+ |
+LL | fn method_test3(&self) -> _;
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/typeck_type_placeholder_item.rs:149:26
|
LL | fn assoc_fn_test1(x: _);
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn assoc_fn_test1(x: _);
-LL + fn assoc_fn_test1<T>(x: T);
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:148:26
+ --> $DIR/typeck_type_placeholder_item.rs:151:26
|
LL | fn assoc_fn_test2(x: _) -> _;
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn assoc_fn_test2(x: _) -> _;
-LL + fn assoc_fn_test2<T>(x: T) -> T;
- |
+ | ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:150:28
+ --> $DIR/typeck_type_placeholder_item.rs:151:32
+ |
+LL | fn assoc_fn_test2(x: _) -> _;
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+ --> $DIR/typeck_type_placeholder_item.rs:154:28
|
LL | fn assoc_fn_test3() -> _;
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn assoc_fn_test3() -> _;
-LL + fn assoc_fn_test3<T>() -> T;
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations
- --> $DIR/typeck_type_placeholder_item.rs:159:15
+ --> $DIR/typeck_type_placeholder_item.rs:163:32
|
LL | impl BadTrait<_> for BadStruct<_> {}
- | ^ ^ not allowed in type signatures
- | |
- | not allowed in type signatures
+ | ^ not allowed in type signatures
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:162:34
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations
+ --> $DIR/typeck_type_placeholder_item.rs:163:15
+ |
+LL | impl BadTrait<_> for BadStruct<_> {}
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+ --> $DIR/typeck_type_placeholder_item.rs:167:34
|
LL | fn impl_trait() -> impl BadTrait<_> {
| ^ not allowed in type signatures
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/typeck_type_placeholder_item.rs:167:25
- |
-LL | struct BadStruct1<_, _>(_);
- | ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - struct BadStruct1<_, _>(_);
-LL + struct BadStruct1<T, _>(T);
- |
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/typeck_type_placeholder_item.rs:172:25
- |
-LL | struct BadStruct2<_, T>(_, T);
- | ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - struct BadStruct2<_, T>(_, T);
-LL + struct BadStruct2<U, T>(U, T);
- |
-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
- --> $DIR/typeck_type_placeholder_item.rs:176:14
+ --> $DIR/typeck_type_placeholder_item.rs:182:14
|
LL | type X = Box<_>;
| ^ not allowed in type signatures
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
- --> $DIR/typeck_type_placeholder_item.rs:182:21
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+ --> $DIR/typeck_type_placeholder_item.rs:188:21
|
LL | type Y = impl Trait<_>;
| ^ not allowed in type signatures
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+ --> $DIR/typeck_type_placeholder_item.rs:198:14
+ |
+LL | type B = _;
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+ --> $DIR/typeck_type_placeholder_item.rs:211:14
+ |
+LL | type A = _;
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+ --> $DIR/typeck_type_placeholder_item.rs:213:14
+ |
+LL | type B = _;
+ | ^ not allowed in type signatures
+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
- --> $DIR/typeck_type_placeholder_item.rs:207:14
+ --> $DIR/typeck_type_placeholder_item.rs:200:14
|
LL | const C: _;
| ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
- --> $DIR/typeck_type_placeholder_item.rs:195:14
+ --> $DIR/typeck_type_placeholder_item.rs:215:14
+ |
+LL | const C: _;
+ | ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
+ --> $DIR/typeck_type_placeholder_item.rs:202:14
|
LL | const D: _ = 42;
| ^ not allowed in type signatures
@@ -596,13 +510,13 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
- --> $DIR/typeck_type_placeholder_item.rs:210:14
+ --> $DIR/typeck_type_placeholder_item.rs:218:14
|
LL | const D: _ = 42;
| ^ not allowed in type signatures
error[E0046]: not all trait items implemented, missing: `F`
- --> $DIR/typeck_type_placeholder_item.rs:201:1
+ --> $DIR/typeck_type_placeholder_item.rs:209:1
|
LL | type F: std::ops::Fn(_);
| ----------------------- `F` from trait
@@ -611,7 +525,7 @@
| ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:218:31
+ --> $DIR/typeck_type_placeholder_item.rs:226:31
|
LL | fn value() -> Option<&'static _> {
| ----------------^-
@@ -620,7 +534,7 @@
| help: replace with the correct return type: `Option<&'static u8>`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
- --> $DIR/typeck_type_placeholder_item.rs:223:17
+ --> $DIR/typeck_type_placeholder_item.rs:231:17
|
LL | const _: Option<_> = map(value);
| ^ not allowed in type signatures
@@ -632,7 +546,7 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:227:31
+ --> $DIR/typeck_type_placeholder_item.rs:235:31
|
LL | fn evens_squared(n: usize) -> _ {
| ^
@@ -641,19 +555,19 @@
| help: replace with an appropriate return type: `impl Iterator<Item = usize>`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
- --> $DIR/typeck_type_placeholder_item.rs:232:10
+ --> $DIR/typeck_type_placeholder_item.rs:240:10
|
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
| ^ not allowed in type signatures
|
-note: however, the inferred type `Map<Filter<Range<i32>, {closure@typeck_type_placeholder_item.rs:232:29}>, {closure@typeck_type_placeholder_item.rs:232:49}>` cannot be named
- --> $DIR/typeck_type_placeholder_item.rs:232:14
+note: however, the inferred type `Map<Filter<Range<i32>, {closure@typeck_type_placeholder_item.rs:240:29}>, {closure@typeck_type_placeholder_item.rs:240:49}>` cannot be named
+ --> $DIR/typeck_type_placeholder_item.rs:240:14
|
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/typeck_type_placeholder_item.rs:41:24
+ --> $DIR/typeck_type_placeholder_item.rs:40:24
|
LL | fn test9(&self) -> _ { () }
| ^
@@ -662,16 +576,10 @@
| help: replace with the correct return type: `()`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item.rs:44:27
+ --> $DIR/typeck_type_placeholder_item.rs:43:27
|
LL | fn test10(&self, _x : _) { }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn test10(&self, _x : _) { }
-LL + fn test10<T>(&self, _x : T) { }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
--> $DIR/typeck_type_placeholder_item.rs:107:31
@@ -687,68 +595,62 @@
|
LL | fn fn_test10(&self, _x : _) { }
| ^ not allowed in type signatures
- |
-help: use type parameters instead
- |
-LL - fn fn_test10(&self, _x : _) { }
-LL + fn fn_test10<T>(&self, _x : T) { }
- |
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
- --> $DIR/typeck_type_placeholder_item.rs:203:14
- |
-LL | type A = _;
- | ^ not allowed in type signatures
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
- --> $DIR/typeck_type_placeholder_item.rs:205:14
- |
-LL | type B = _;
- | ^ not allowed in type signatures
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
- --> $DIR/typeck_type_placeholder_item.rs:191:14
- |
-LL | type B = _;
- | ^ not allowed in type signatures
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
- --> $DIR/typeck_type_placeholder_item.rs:193:14
- |
-LL | const C: _;
- | ^ not allowed in type signatures
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
- --> $DIR/typeck_type_placeholder_item.rs:198:26
+ --> $DIR/typeck_type_placeholder_item.rs:205:26
|
LL | type F: std::ops::Fn(_);
| ^ not allowed in type signatures
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+ --> $DIR/typeck_type_placeholder_item.rs:205:26
+ |
+LL | type F: std::ops::Fn(_);
+ | ^ not allowed in type signatures
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+ --> $DIR/typeck_type_placeholder_item.rs:167:34
+ |
+LL | fn impl_trait() -> impl BadTrait<_> {
+ | ^ not allowed in type signatures
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+ --> $DIR/typeck_type_placeholder_item.rs:188:21
+ |
+LL | type Y = impl Trait<_>;
+ | ^ not allowed in type signatures
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
error[E0015]: cannot call non-const function `map::<u8>` in constants
- --> $DIR/typeck_type_placeholder_item.rs:223:22
+ --> $DIR/typeck_type_placeholder_item.rs:231:22
|
LL | const _: Option<_> = map(value);
| ^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-error[E0015]: cannot call non-const method `<std::ops::Range<i32> as Iterator>::filter::<{closure@$DIR/typeck_type_placeholder_item.rs:232:29: 232:32}>` in constants
- --> $DIR/typeck_type_placeholder_item.rs:232:22
+error[E0015]: cannot call non-const method `<std::ops::Range<i32> as Iterator>::filter::<{closure@$DIR/typeck_type_placeholder_item.rs:240:29: 240:32}>` in constants
+ --> $DIR/typeck_type_placeholder_item.rs:240:22
|
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-error[E0015]: cannot call non-const method `<Filter<std::ops::Range<i32>, {closure@$DIR/typeck_type_placeholder_item.rs:232:29: 232:32}> as Iterator>::map::<i32, {closure@$DIR/typeck_type_placeholder_item.rs:232:49: 232:52}>` in constants
- --> $DIR/typeck_type_placeholder_item.rs:232:45
+error[E0015]: cannot call non-const method `<Filter<std::ops::Range<i32>, {closure@$DIR/typeck_type_placeholder_item.rs:240:29: 240:32}> as Iterator>::map::<i32, {closure@$DIR/typeck_type_placeholder_item.rs:240:49: 240:52}>` in constants
+ --> $DIR/typeck_type_placeholder_item.rs:240:45
|
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
| ^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-error: aborting due to 75 previous errors
+error: aborting due to 83 previous errors
Some errors have detailed explanations: E0015, E0046, E0121, E0282, E0403.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/typeck/typeck_type_placeholder_item_help.rs b/tests/ui/typeck/typeck_type_placeholder_item_help.rs
index ff61825..ab433aa 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item_help.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item_help.rs
@@ -11,8 +11,7 @@ fn test1() -> _ { Some(42) }
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
const TEST4: fn() -> _ = 42;
-//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
-//~| ERROR the placeholder `_` is not allowed within types on item signatures for constant items
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constant items
trait Test5 {
const TEST5: _ = 42;
diff --git a/tests/ui/typeck/typeck_type_placeholder_item_help.stderr b/tests/ui/typeck/typeck_type_placeholder_item_help.stderr
index afdd58e..5066e2e 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item_help.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item_help.stderr
@@ -31,12 +31,6 @@
LL + const TEST3: Option<i32> = Some(42);
|
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/typeck_type_placeholder_item_help.rs:13:22
- |
-LL | const TEST4: fn() -> _ = 42;
- | ^ not allowed in type signatures
-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constant items
--> $DIR/typeck_type_placeholder_item_help.rs:13:22
|
@@ -44,7 +38,7 @@
| ^ not allowed in type signatures
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
- --> $DIR/typeck_type_placeholder_item_help.rs:25:18
+ --> $DIR/typeck_type_placeholder_item_help.rs:24:18
|
LL | const TEST6: _ = 13;
| ^ not allowed in type signatures
@@ -56,7 +50,7 @@
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
- --> $DIR/typeck_type_placeholder_item_help.rs:18:18
+ --> $DIR/typeck_type_placeholder_item_help.rs:17:18
|
LL | const TEST5: _ = 42;
| ^ not allowed in type signatures
@@ -68,7 +62,7 @@
|
error[E0308]: mismatched types
- --> $DIR/typeck_type_placeholder_item_help.rs:30:28
+ --> $DIR/typeck_type_placeholder_item_help.rs:29:28
|
LL | let _: Option<usize> = test1();
| ------------- ^^^^^^^ expected `Option<usize>`, found `Option<i32>`
@@ -79,7 +73,7 @@
found enum `Option<i32>`
error[E0308]: mismatched types
- --> $DIR/typeck_type_placeholder_item_help.rs:31:18
+ --> $DIR/typeck_type_placeholder_item_help.rs:30:18
|
LL | let _: f64 = test1();
| --- ^^^^^^^ expected `f64`, found `Option<i32>`
@@ -89,7 +83,7 @@
= note: expected type `f64`
found enum `Option<i32>`
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
Some errors have detailed explanations: E0121, E0308.
For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/unpretty/ast-const-trait-bound.rs b/tests/ui/unpretty/ast-const-trait-bound.rs
index f4de86b..761bff8 100644
--- a/tests/ui/unpretty/ast-const-trait-bound.rs
+++ b/tests/ui/unpretty/ast-const-trait-bound.rs
@@ -1,4 +1,4 @@
//@ compile-flags: -Zunpretty=normal
//@ check-pass
-fn foo() where T: ~const Bar {}
+fn foo() where T: [const] Bar {}
diff --git a/tests/ui/unpretty/ast-const-trait-bound.stdout b/tests/ui/unpretty/ast-const-trait-bound.stdout
index f4de86b..761bff8 100644
--- a/tests/ui/unpretty/ast-const-trait-bound.stdout
+++ b/tests/ui/unpretty/ast-const-trait-bound.stdout
@@ -1,4 +1,4 @@
//@ compile-flags: -Zunpretty=normal
//@ check-pass
-fn foo() where T: ~const Bar {}
+fn foo() where T: [const] Bar {}
diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout
index ae44d12..9df027b 100644
--- a/tests/ui/unpretty/exhaustive.expanded.stdout
+++ b/tests/ui/unpretty/exhaustive.expanded.stdout
@@ -604,7 +604,7 @@
let _: impl Send + 'static;
let _: impl 'static + Send;
let _: impl ?Sized;
- let _: impl ~const Clone;
+ let _: impl [const] Clone;
let _: impl for<'a> Send;
}
/// TyKind::Paren
diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr
index 1c78cf9..ac8079a 100644
--- a/tests/ui/unpretty/exhaustive.hir.stderr
+++ b/tests/ui/unpretty/exhaustive.hir.stderr
@@ -147,8 +147,8 @@
error[E0562]: `impl Trait` is not allowed in the type of variable bindings
--> $DIR/exhaustive.rs:812:16
|
-LL | let _: impl ~const Clone;
- | ^^^^^^^^^^^^^^^^^
+LL | let _: impl [const] Clone;
+ | ^^^^^^^^^^^^^^^^^^
|
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
= note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs
index ccf907a..5bf1118 100644
--- a/tests/ui/unpretty/exhaustive.rs
+++ b/tests/ui/unpretty/exhaustive.rs
@@ -809,7 +809,7 @@ const fn ty_impl_trait() {
let _: impl Send + 'static; //[hir]~ ERROR `impl Trait` is not allowed
let _: impl 'static + Send; //[hir]~ ERROR `impl Trait` is not allowed
let _: impl ?Sized; //[hir]~ ERROR `impl Trait` is not allowed
- let _: impl ~const Clone; //[hir]~ ERROR `impl Trait` is not allowed
+ let _: impl [const] Clone; //[hir]~ ERROR `impl Trait` is not allowed
let _: impl for<'a> Send; //[hir]~ ERROR `impl Trait` is not allowed
}