Rollup merge of #142416 - Kobzol:bootstrap-cleanup-2, r=jieyouxu Assorted bootstrap cleanups (step 2) Very small improvements designed towards making bootstrap tests less hacky/special, and towards making it possible to run bootstrap tests in parallel. Best reviewed commit by commit. r? ``@jieyouxu``
diff --git a/.mailmap b/.mailmap index 3b57f88..b9fb7be 100644 --- a/.mailmap +++ b/.mailmap
@@ -34,10 +34,13 @@ Alona Enraght-Moony <code@alona.page> <contact@alona.page> Amanda Stjerna <mail@amandastjerna.se> <albin.stjerna@gmail.com> Amanda Stjerna <mail@amandastjerna.se> <amanda.stjerna@it.uu.se> +Amanieu d'Antras <amanieu@gmail.com> <amanieu.dantras@huawei.com> Amos Onn <amosonn@gmail.com> Ana-Maria Mihalache <mihalacheana.maria@yahoo.com> Anatoly Ikorsky <aikorsky@gmail.com> Andre Bogus <bogusandre@gmail.com> +Andre Bogus <bogusandre@gmail.com> <andre.bogus@aleph-alpha.de> +Andre Bogus <bogusandre@gmail.com> <andre.bogus@ankordata.de> Andrea Ciliberti <meziu210@icloud.com> Andreas Gal <gal@mozilla.com> <andreas.gal@gmail.com> Andreas Jonson <andjo403@users.noreply.github.com> @@ -116,6 +119,7 @@ Chandler Deng <chandde@microsoft.com> Charles Lew <crlf0710@gmail.com> CrLF0710 <crlf0710@gmail.com> Chris C Cerami <chrisccerami@users.noreply.github.com> Chris C Cerami <chrisccerami@gmail.com> +Chris Denton <chris@chrisdenton.dev> <christophersdenton@gmail.com> Chris Denton <chris@chrisdenton.dev> Chris Denton <ChrisDenton@users.noreply.github.com> Chris Gregory <czipperz@gmail.com> Chris Pardy <chrispardy36@gmail.com> @@ -403,6 +407,8 @@ Lucy <luxx4x@protonmail.com> Lukas H. <lukaramu@users.noreply.github.com> Lukas Lueg <lukas.lueg@gmail.com> +Lukas Wirth <lukastw97@gmail.com> <lukas.wirth@ferrous-systems.com> +Lukas Wirth <lukastw97@gmail.com> <me@lukaswirth.dev> Luke Metz <luke.metz@students.olin.edu> Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca> Luqman Aden <me@luqman.ca> <laden@mozilla.com> @@ -493,6 +499,7 @@ Nicole Mazzuca <npmazzuca@gmail.com> Niko Matsakis <rust@nikomatsakis.com> Niko Matsakis <rust@nikomatsakis.com> <niko@alum.mit.edu> +Niko Matsakis <rust@nikomatsakis.com> <nikomat@amazon.com> Noratrieb <48135649+Noratrieb@users.noreply.github.com> Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com> Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nilstrieb@gmail.com>
diff --git a/Cargo.lock b/Cargo.lock index 21ec1fb..df2842b 100644 --- a/Cargo.lock +++ b/Cargo.lock
@@ -3234,9 +3234,9 @@ [[package]] name = "rustc_apfloat" -version = "0.2.2+llvm-462a31f5a5ab" +version = "0.2.3+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" +checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad" dependencies = [ "bitflags", "smallvec", @@ -3793,6 +3793,7 @@ "rustc_arena", "rustc_ast", "rustc_attr_data_structures", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -4617,7 +4618,7 @@ "derive-where", "ena", "indexmap", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "rustc_ast_ir", "rustc_data_structures", "rustc_index",
diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 1371fd6..19cf360 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml
@@ -381,6 +381,15 @@ # "miri", "cargo-miri" # for dev/nightly channels #] +# Specify build configuration specific for some tool, such as enabled features. +# This option has no effect on which tools are enabled: refer to the `tools` option for that. +# +# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]` +# +# The default value for the `features` array is `[]`. However, please note that other flags in +# `bootstrap.toml` might influence the features enabled for some tools. +#tool.TOOL_NAME.features = [FEATURE1, FEATURE2] + # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation #verbose = 0
diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 03eeb64..7c020be 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs
@@ -28,6 +28,9 @@ pub enum CanonAbi { Rust, RustCold, + /// An ABI that rustc does not know how to call or define. + Custom, + /// ABIs relevant to 32-bit Arm targets Arm(ArmCall), /// ABI relevant to GPUs: the entry point for a GPU kernel @@ -57,6 +60,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { CanonAbi::C => ExternAbi::C { unwind: false }, CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, + CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 0bc1c8a..7457ae1 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs
@@ -40,6 +40,11 @@ pub enum ExternAbi { /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, + /// An ABI that rustc does not know how to call or define. Functions with this ABI can + /// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only + /// be called from inline assembly. + Custom, + /// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias /// and only valid on platforms that have a UEFI standard EfiApi, @@ -141,6 +146,7 @@ fn from_str(s: &str) -> Result<$e_name, Self::Err> { AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt", Cdecl { unwind: false } =><= "cdecl", Cdecl { unwind: true } =><= "cdecl-unwind", + Custom =><= "custom", EfiApi =><= "efiapi", Fastcall { unwind: false } =><= "fastcall", Fastcall { unwind: true } =><= "fastcall-unwind",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cf40c3f..4489a42 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs
@@ -97,12 +97,12 @@ pub struct Path { pub tokens: Option<LazyAttrTokenStream>, } +// Succeeds if the path has a single segment that is arg-free and matches the given symbol. impl PartialEq<Symbol> for Path { #[inline] fn eq(&self, name: &Symbol) -> bool { if let [segment] = self.segments.as_ref() - && segment.args.is_none() - && segment.ident.name == *name + && segment == name { true } else { @@ -111,6 +111,15 @@ fn eq(&self, name: &Symbol) -> bool { } } +// Succeeds if the path has segments that are arg-free and match the given symbols. +impl PartialEq<&[Symbol]> for Path { + #[inline] + fn eq(&self, names: &&[Symbol]) -> bool { + self.segments.len() == names.len() + && self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2) + } +} + impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { self.segments.len().hash_stable(hcx, hasher); @@ -166,6 +175,14 @@ pub struct PathSegment { pub args: Option<P<GenericArgs>>, } +// Succeeds if the path segment is arg-free and matches the given symbol. +impl PartialEq<Symbol> for PathSegment { + #[inline] + fn eq(&self, name: &Symbol) -> bool { + self.args.is_none() && self.ident.name == *name + } +} + impl PathSegment { pub fn from_ident(ident: Ident) -> Self { PathSegment { ident, id: DUMMY_NODE_ID, args: None } @@ -1433,19 +1450,32 @@ pub fn to_ty(&self) -> Option<P<Ty>> { } pub fn precedence(&self) -> ExprPrecedence { + fn prefix_attrs_precedence(attrs: &AttrVec) -> ExprPrecedence { + for attr in attrs { + if let AttrStyle::Outer = attr.style { + return ExprPrecedence::Prefix; + } + } + ExprPrecedence::Unambiguous + } + match &self.kind { ExprKind::Closure(closure) => { match closure.fn_decl.output { FnRetTy::Default(_) => ExprPrecedence::Jump, - FnRetTy::Ty(_) => ExprPrecedence::Unambiguous, + FnRetTy::Ty(_) => prefix_attrs_precedence(&self.attrs), } } - ExprKind::Break(..) - | ExprKind::Ret(..) - | ExprKind::Yield(..) - | ExprKind::Yeet(..) - | ExprKind::Become(..) => ExprPrecedence::Jump, + ExprKind::Break(_ /*label*/, value) + | ExprKind::Ret(value) + | ExprKind::Yield(YieldKind::Prefix(value)) + | ExprKind::Yeet(value) => match value { + Some(_) => ExprPrecedence::Jump, + None => prefix_attrs_precedence(&self.attrs), + }, + + ExprKind::Become(_) => ExprPrecedence::Jump, // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence @@ -1469,7 +1499,7 @@ pub fn precedence(&self) -> ExprPrecedence { | ExprKind::Let(..) | ExprKind::Unary(..) => ExprPrecedence::Prefix, - // Never need parens + // Need parens if and only if there are prefix attributes. ExprKind::Array(_) | ExprKind::Await(..) | ExprKind::Use(..) @@ -1502,8 +1532,9 @@ pub fn precedence(&self) -> ExprPrecedence { | ExprKind::Underscore | ExprKind::UnsafeBinderCast(..) | ExprKind::While(..) + | ExprKind::Yield(YieldKind::Postfix(..)) | ExprKind::Err(_) - | ExprKind::Dummy => ExprPrecedence::Unambiguous, + | ExprKind::Dummy => prefix_attrs_precedence(&self.attrs), } } @@ -3520,6 +3551,38 @@ pub fn has_qualifiers(&self) -> bool { || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } + + /// Return a span encompassing the header, or none if all options are default. + pub fn span(&self) -> Option<Span> { + fn append(a: &mut Option<Span>, b: Span) { + *a = match a { + None => Some(b), + Some(x) => Some(x.to(b)), + } + } + + let mut full_span = None; + + match self.safety { + Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span), + Safety::Default => {} + }; + + if let Some(coroutine_kind) = self.coroutine_kind { + append(&mut full_span, coroutine_kind.span()); + } + + if let Const::Yes(span) = self.constness { + append(&mut full_span, span); + } + + match self.ext { + Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span), + Extern::None => {} + } + + full_span + } } impl Default for FnHeader {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index c88aa5c..1449a4a 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs
@@ -1700,7 +1700,8 @@ fn visit_nested_use_tree<'a, V: Visitor<'a>>( } pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result { - let Stmt { id: _, kind, span: _ } = statement; + let Stmt { id, kind, span: _ } = statement; + try_visit!(visit_id(visitor, id)); match kind { StmtKind::Let(local) => try_visit!(visitor.visit_local(local)), StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 537d4a2..718edad 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -73,16 +73,15 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { // Merge attributes into the inner expression. if !e.attrs.is_empty() { let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); - let attrs = &*self.arena.alloc_from_iter( - self.lower_attrs_vec(&e.attrs, e.span) - .into_iter() - .chain(old_attrs.iter().cloned()), - ); - if attrs.is_empty() { + let new_attrs = self + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id) + .into_iter() + .chain(old_attrs.iter().cloned()); + let new_attrs = &*self.arena.alloc_from_iter(new_attrs); + if new_attrs.is_empty() { return ex; } - - self.attrs.insert(ex.hir_id.local_id, attrs); + self.attrs.insert(ex.hir_id.local_id, new_attrs); } return ex; } @@ -2035,7 +2034,7 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span); + self.lower_attrs(ret_expr.hir_id, &attrs, span); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr)
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d1a2ddb..49110c9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -63,7 +63,7 @@ fn with_lctx( for (def_id, info) in lctx.children { let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - debug_assert!( + assert!( matches!(owner, hir::MaybeOwner::Phantom), "duplicate copy of {def_id:?} in lctx.children" ); @@ -78,7 +78,7 @@ pub(super) fn lower_node(&mut self, def_id: LocalDefId) { match node { AstOwner::NonOwner => {} AstOwner::Crate(c) => { - debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); + assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? @@ -145,6 +145,7 @@ fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { kind, vis_span, span: self.lower_span(i.span), + has_delayed_lints: !self.delayed_lints.is_empty(), }; self.arena.alloc(item) } @@ -599,6 +600,7 @@ fn lower_use_tree( kind, vis_span, span: this.lower_span(use_tree.span), + has_delayed_lints: !this.delayed_lints.is_empty(), }; hir::OwnerNode::Item(this.arena.alloc(item)) }); @@ -697,6 +699,7 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir kind, vis_span: self.lower_span(i.vis.span), span: self.lower_span(i.span), + has_delayed_lints: !self.delayed_lints.is_empty(), }; self.arena.alloc(item) } @@ -941,6 +944,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { kind, span: self.lower_span(i.span), defaultness: hir::Defaultness::Default { has_value: has_default }, + has_delayed_lints: !self.delayed_lints.is_empty(), }; self.arena.alloc(item) } @@ -1100,6 +1104,7 @@ fn lower_impl_item( vis_span: self.lower_span(i.vis.span), span: self.lower_span(i.span), defaultness, + has_delayed_lints: !self.delayed_lints.is_empty(), }; self.arena.alloc(item) } @@ -1160,7 +1165,7 @@ fn record_body( ) -> hir::BodyId { let body = hir::Body { params, value: self.arena.alloc(value) }; let id = body.id(); - debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); + assert_eq!(id.hir_id.owner, self.current_hir_id_owner); self.bodies.push((id.hir_id.local_id, self.arena.alloc(body))); id } @@ -1673,8 +1678,8 @@ fn lower_generics<T>( itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { - debug_assert!(self.impl_trait_defs.is_empty()); - debug_assert!(self.impl_trait_bounds.is_empty()); + assert!(self.impl_trait_defs.is_empty()); + assert!(self.impl_trait_bounds.is_empty()); // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b99df8b..3b99a65 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -51,6 +51,7 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; +use rustc_hir::lints::DelayedLint; use rustc_hir::{ self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate, @@ -141,6 +142,8 @@ struct LoweringContext<'a, 'hir> { allow_for_await: Arc<[Symbol]>, allow_async_fn_traits: Arc<[Symbol]>, + delayed_lints: Vec<DelayedLint>, + attribute_parser: AttributeParser<'hir>, } @@ -190,6 +193,7 @@ fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), + delayed_lints: Vec::new(), } } @@ -198,6 +202,22 @@ pub(crate) fn dcx(&self) -> DiagCtxtHandle<'hir> { } } +struct SpanLowerer { + is_incremental: bool, + def_id: LocalDefId, +} + +impl SpanLowerer { + fn lower(&self, span: Span) -> Span { + if self.is_incremental { + span.with_parent(Some(self.def_id)) + } else { + // Do not make spans relative when not using incremental compilation. + span + } + } +} + #[extension(trait ResolverAstLoweringExt)] impl ResolverAstLowering { fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> { @@ -503,7 +523,7 @@ fn create_def( span: Span, ) -> LocalDefId { let parent = self.current_hir_id_owner.def_id; - debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); + assert_ne!(node_id, ast::DUMMY_NODE_ID); assert!( self.opt_local_def_id(node_id).is_none(), "adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}", @@ -573,6 +593,7 @@ fn with_hir_id_owner( std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); + let current_delayed_lints = std::mem::take(&mut self.delayed_lints); // Do not reset `next_node_id` and `node_id_to_def_id`: // we want `f` to be able to refer to the `LocalDefId`s that the caller created. @@ -586,10 +607,10 @@ fn with_hir_id_owner( } let item = f(self); - debug_assert_eq!(owner_id, item.def_id()); + assert_eq!(owner_id, item.def_id()); // `f` should have consumed all the elements in these vectors when constructing `item`. - debug_assert!(self.impl_trait_defs.is_empty()); - debug_assert!(self.impl_trait_bounds.is_empty()); + assert!(self.impl_trait_defs.is_empty()); + assert!(self.impl_trait_bounds.is_empty()); let info = self.make_owner_info(item); self.attrs = current_attrs; @@ -606,6 +627,7 @@ fn with_hir_id_owner( self.item_local_id_counter = current_local_counter; self.impl_trait_defs = current_impl_trait_defs; self.impl_trait_bounds = current_impl_trait_bounds; + self.delayed_lints = current_delayed_lints; debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id)); self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info))); @@ -616,6 +638,7 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInf let mut bodies = std::mem::take(&mut self.bodies); let define_opaque = std::mem::take(&mut self.define_opaque); let trait_map = std::mem::take(&mut self.trait_map); + let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice(); #[cfg(debug_assertions)] for (id, attrs) in attrs.iter() { @@ -629,14 +652,16 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInf let bodies = SortedMap::from_presorted_elements(bodies); // Don't hash unless necessary, because it's expensive. - let (opt_hash_including_bodies, attrs_hash) = - self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque); + let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) = + self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque }; + let delayed_lints = + hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash }; - self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) + self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints }) } /// This method allocates a new `HirId` for the given `NodeId`. @@ -759,15 +784,17 @@ fn mark_span_with_reason( }) } + fn span_lowerer(&self) -> SpanLowerer { + SpanLowerer { + is_incremental: self.tcx.sess.opts.incremental.is_some(), + def_id: self.current_hir_id_owner.def_id, + } + } + /// Intercept all spans entering HIR. /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { - if self.tcx.sess.opts.incremental.is_some() { - span.with_parent(Some(self.current_hir_id_owner.def_id)) - } else { - // Do not make spans relative when not using incremental compilation. - span - } + self.span_lowerer().lower(span) } fn lower_ident(&self, ident: Ident) -> Ident { @@ -889,9 +916,9 @@ fn lower_attrs( if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); + let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id); - debug_assert_eq!(id.owner, self.current_hir_id_owner); + assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); // this is possible if an item contained syntactical attribute, @@ -909,16 +936,30 @@ fn lower_attrs( } } - fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> { - self.attribute_parser - .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s)) + fn lower_attrs_vec( + &mut self, + attrs: &[Attribute], + target_span: Span, + target_hir_id: HirId, + ) -> Vec<hir::Attribute> { + let l = self.span_lowerer(); + self.attribute_parser.parse_attribute_list( + attrs, + target_span, + target_hir_id, + OmitDoc::Lower, + |s| l.lower(s), + |l| { + self.delayed_lints.push(DelayedLint::AttributeParsing(l)); + }, + ) } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { - debug_assert_eq!(id.owner, self.current_hir_id_owner); - debug_assert_eq!(target_id.owner, self.current_hir_id_owner); + assert_eq!(id.owner, self.current_hir_id_owner); + assert_eq!(target_id.owner, self.current_hir_id_owner); if let Some(&a) = self.attrs.get(&target_id.local_id) { - debug_assert!(!a.is_empty()); + assert!(!a.is_empty()); self.attrs.insert(id.local_id, a); } } @@ -1397,7 +1438,7 @@ fn lower_ty_direct_lifetime( let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) { - debug_assert_eq!(start.plus(1), end); + assert_eq!(start.plus(1), end); start } else { self.next_node_id() @@ -1805,16 +1846,16 @@ fn new_named_lifetime( let res = match res { LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param), LifetimeRes::Fresh { param, .. } => { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + assert_eq!(ident.name, kw::UnderscoreLifetime); let param = self.local_def_id(param); hir::LifetimeKind::Param(param) } LifetimeRes::Infer => { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + assert_eq!(ident.name, kw::UnderscoreLifetime); hir::LifetimeKind::Infer } LifetimeRes::Static { .. } => { - debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); + assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); hir::LifetimeKind::Static } LifetimeRes::Error => hir::LifetimeKind::Error, @@ -2106,7 +2147,7 @@ fn lower_const_path_to_const_arg( ty_id, &None, path, - ParamMode::Optional, + ParamMode::Explicit, AllowReturnTypeNotation::No, // FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), @@ -2178,7 +2219,7 @@ fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::Con expr.id, qself, path, - ParamMode::Optional, + ParamMode::Explicit, AllowReturnTypeNotation::No, // FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), @@ -2244,7 +2285,7 @@ fn stmt_let_pat( ) -> hir::Stmt<'hir> { let hir_id = self.next_id(); if let Some(a) = attrs { - debug_assert!(!a.is_empty()); + assert!(!a.is_empty()); self.attrs.insert(hir_id.local_id, a); } let local = hir::LetStmt {
diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index eb052ba..b8fa2dd 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs
@@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { feature: sym::cmse_nonsecure_entry, explain: GateReason::Experimental, }), + ExternAbi::Custom => { + Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental }) + } } }
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 80754a8..9a26750 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl
@@ -1,3 +1,20 @@ +ast_passes_abi_custom_coroutine = + functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}` + .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton + +ast_passes_abi_custom_invalid_signature = + invalid signature for `extern "custom"` function + .note = functions with the `"custom"` ABI cannot have any parameters or return type + .suggestion = remove the parameters and return type + +ast_passes_abi_custom_safe_foreign_function = + foreign functions with the `"custom"` ABI cannot be safe + .suggestion = remove the `safe` keyword from this definition + +ast_passes_abi_custom_safe_function = + functions with the `"custom"` ABI must be unsafe + .suggestion = add the `unsafe` keyword to this definition + ast_passes_assoc_const_without_body = associated constant in `impl` without body .suggestion = provide a definition for the constant
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6fe04d..018887d 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -18,6 +18,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; +use std::str::FromStr; use itertools::{Either, Itertools}; use rustc_abi::ExternAbi; @@ -81,6 +82,7 @@ struct AstValidator<'a> { /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option<Safety>, + extern_mod_abi: Option<ExternAbi>, lint_node_id: NodeId, @@ -121,10 +123,17 @@ fn with_in_trait( self.outer_trait_or_trait_impl = old; } - fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + fn with_in_extern_mod( + &mut self, + extern_mod_safety: Safety, + abi: Option<ExternAbi>, + f: impl FnOnce(&mut Self), + ) { + let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + let old_abi = mem::replace(&mut self.extern_mod_abi, abi); f(self); - self.extern_mod_safety = old; + self.extern_mod_safety = old_safety; + self.extern_mod_abi = old_abi; } fn with_tilde_const( @@ -370,6 +379,65 @@ fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { } } + /// An `extern "custom"` function must be unsafe, and must not have any parameters or return + /// type. + fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) { + let dcx = self.dcx(); + + // An `extern "custom"` function must be unsafe. + match sig.header.safety { + Safety::Unsafe(_) => { /* all good */ } + Safety::Safe(safe_span) => { + let safe_span = + self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span)); + dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span }); + } + Safety::Default => match ctxt { + FnCtxt::Foreign => { /* all good */ } + FnCtxt::Free | FnCtxt::Assoc(_) => { + self.dcx().emit_err(errors::AbiCustomSafeFunction { + span: sig.span, + unsafe_span: sig.span.shrink_to_lo(), + }); + } + }, + } + + // An `extern "custom"` function cannot be `async` and/or `gen`. + if let Some(coroutine_kind) = sig.header.coroutine_kind { + let coroutine_kind_span = self + .sess + .psess + .source_map() + .span_until_non_whitespace(coroutine_kind.span().to(sig.span)); + + self.dcx().emit_err(errors::AbiCustomCoroutine { + span: sig.span, + coroutine_kind_span, + coroutine_kind_str: coroutine_kind.as_str(), + }); + } + + // An `extern "custom"` function must not have any parameters or return type. + let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect(); + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output { + spans.push(ret_ty.span); + } + + if !spans.is_empty() { + let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo()); + let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span()); + let padding = if header_span.is_empty() { "" } else { " " }; + + self.dcx().emit_err(errors::AbiCustomInvalidSignature { + spans, + symbol: ident.name, + suggestion_span, + padding, + }); + } + } + /// This ensures that items can only be `unsafe` (or unmarked) outside of extern /// blocks. /// @@ -1005,7 +1073,9 @@ fn visit_item(&mut self, item: &'a Item) { if abi.is_none() { self.handle_missing_abi(*extern_span, item.id); } - self.with_in_extern_mod(*safety, |this| { + + let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok()); + self.with_in_extern_mod(*safety, extern_abi, |this| { visit::walk_item(this, item); }); self.extern_mod_span = old_item; @@ -1145,6 +1215,9 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { self.check_foreign_fn_bodyless(*ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); self.check_foreign_item_ascii_only(*ident); + if self.extern_mod_abi == Some(ExternAbi::Custom) { + self.check_custom_abi(FnCtxt::Foreign, ident, sig); + } } ForeignItemKind::TyAlias(box TyAlias { defaultness, @@ -1352,6 +1425,13 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { self.check_item_safety(span, safety); } + if let FnKind::Fn(ctxt, _, fun) = fk + && let Extern::Explicit(str_lit, _) = fun.sig.header.ext + && let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str()) + { + self.check_custom_abi(ctxt, &fun.ident, &fun.sig); + } + self.check_c_variadic_type(fk); // Functions cannot both be `const async` or `const gen` @@ -1703,6 +1783,7 @@ pub fn check_crate( outer_impl_trait_span: None, disallow_tilde_const: Some(TildeConstReason::Item), extern_mod_safety: None, + extern_mod_abi: None, lint_node_id: CRATE_NODE_ID, is_sdylib_interface, lint_buffer: lints,
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 6f9737e..c437e62 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -824,3 +824,67 @@ pub(crate) struct MissingAbi { #[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_safe_foreign_function)] +pub(crate) struct AbiCustomSafeForeignFunction { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "", + style = "verbose" + )] + pub safe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_safe_function)] +pub(crate) struct AbiCustomSafeFunction { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "unsafe ", + style = "verbose" + )] + pub unsafe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_coroutine)] +pub(crate) struct AbiCustomCoroutine { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "", + style = "verbose" + )] + pub coroutine_kind_span: Span, + pub coroutine_kind_str: &'static str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_invalid_signature)] +#[note] +pub(crate) struct AbiCustomInvalidSignature { + #[primary_span] + pub spans: Vec<Span>, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "{padding}fn {symbol}()", + style = "verbose" + )] + pub suggestion_span: Span, + pub symbol: Symbol, + pub padding: &'static str, +}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 3682d25..1ec5686 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -36,6 +36,16 @@ macro_rules! gate_alt { feature_err(&$visitor.sess, $name, $span, $explain).emit(); } }}; + ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{ + if !$has_feature && !$span.allows_unstable($name) { + #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable + let mut diag = feature_err(&$visitor.sess, $name, $span, $explain); + for note in $notes { + diag.note(*note); + } + diag.emit(); + } + }}; } /// The case involving a multispan. @@ -154,11 +164,11 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) { let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); // Check feature gates for built-in attributes. if let Some(BuiltinAttribute { - gate: AttributeGate::Gated(_, name, descr, has_feature), + gate: AttributeGate::Gated { feature, message, check, notes, .. }, .. }) = attr_info { - gate_alt!(self, has_feature(self.features), *name, attr.span, *descr); + gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes); } // Check unstable flavors of the `#[doc]` attribute. if attr.has_name(sym::doc) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index a05e2bd..a766e20 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String { State::new().item_to_string(i) } +pub fn assoc_item_to_string(i: &ast::AssocItem) -> String { + State::new().assoc_item_to_string(i) +} + +pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String { + State::new().foreign_item_to_string(i) +} + +pub fn stmt_to_string(s: &ast::Stmt) -> String { + State::new().stmt_to_string(s) +} + pub fn path_to_string(p: &ast::Path) -> String { State::new().path_to_string(p) }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0990c9b..3d738fa 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1063,6 +1063,14 @@ fn item_to_string(&self, i: &ast::Item) -> String { Self::to_string(|s| s.print_item(i)) } + fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String { + Self::to_string(|s| s.print_assoc_item(i)) + } + + fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String { + Self::to_string(|s| s.print_foreign_item(i)) + } + fn path_to_string(&self, p: &ast::Path) -> String { Self::to_string(|s| s.print_path(p, false, 0)) }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index c9a7e2a..ee49246 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -7,8 +7,8 @@ use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, ExprPrecedence, Fixity}; use rustc_ast::{ - self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, - FormatDebugHex, FormatSign, FormatTrait, YieldKind, token, + self as ast, BinOpKind, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, + FormatCount, FormatDebugHex, FormatSign, FormatTrait, YieldKind, token, }; use crate::pp::Breaks::Inconsistent; @@ -214,13 +214,6 @@ fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) { } fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) { - let needs_paren = match func.kind { - // In order to call a named field, needs parens: `(self.fun)()` - // But not for an unnamed field: `self.0()` - ast::ExprKind::Field(_, name) => !name.is_numeric(), - _ => func.precedence() < ExprPrecedence::Unambiguous, - }; - // Independent of parenthesization related to precedence, we must // parenthesize `func` if this is a statement context in which without // parentheses, a statement boundary would occur inside `func` or @@ -237,8 +230,16 @@ fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: Fi // because the latter is valid syntax but with the incorrect meaning. // It's a match-expression followed by tuple-expression, not a function // call. - self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression()); + let func_fixup = fixup.leftmost_subexpression_with_operator(true); + let needs_paren = match func.kind { + // In order to call a named field, needs parens: `(self.fun)()` + // But not for an unnamed field: `self.0()` + ast::ExprKind::Field(_, name) => !name.is_numeric(), + _ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous, + }; + + self.print_expr_cond_paren(func, needs_paren, func_fixup); self.print_call_post(args) } @@ -281,9 +282,24 @@ fn print_expr_binary( rhs: &ast::Expr, fixup: FixupContext, ) { + let operator_can_begin_expr = match op { + | BinOpKind::Sub // -x + | BinOpKind::Mul // *x + | BinOpKind::And // &&x + | BinOpKind::Or // || x + | BinOpKind::BitAnd // &x + | BinOpKind::BitOr // |x| x + | BinOpKind::Shl // <<T as Trait>::Type as Trait>::CONST + | BinOpKind::Lt // <T as Trait>::CONST + => true, + _ => false, + }; + + let left_fixup = fixup.leftmost_subexpression_with_operator(operator_can_begin_expr); + let binop_prec = op.precedence(); - let left_prec = lhs.precedence(); - let right_prec = rhs.precedence(); + let left_prec = left_fixup.precedence(lhs); + let right_prec = fixup.precedence(rhs); let (mut left_needs_paren, right_needs_paren) = match op.fixity() { Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec), @@ -312,18 +328,18 @@ fn print_expr_binary( _ => {} } - self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression()); + self.print_expr_cond_paren(lhs, left_needs_paren, left_fixup); self.space(); self.word_space(op.as_str()); - self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression()); + self.print_expr_cond_paren(rhs, right_needs_paren, fixup.rightmost_subexpression()); } fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) { self.word(op.as_str()); self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Prefix, - fixup.subsequent_subexpression(), + fixup.precedence(expr) < ExprPrecedence::Prefix, + fixup.rightmost_subexpression(), ); } @@ -344,8 +360,8 @@ fn print_expr_addr_of( } self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Prefix, - fixup.subsequent_subexpression(), + fixup.precedence(expr) < ExprPrecedence::Prefix, + fixup.rightmost_subexpression(), ); } @@ -590,8 +606,8 @@ pub(super) fn print_expr_outer_attr_style( self.word_space("="); self.print_expr_cond_paren( rhs, - rhs.precedence() < ExprPrecedence::Assign, - fixup.subsequent_subexpression(), + fixup.precedence(rhs) < ExprPrecedence::Assign, + fixup.rightmost_subexpression(), ); } ast::ExprKind::AssignOp(op, lhs, rhs) => { @@ -604,8 +620,8 @@ pub(super) fn print_expr_outer_attr_style( self.word_space(op.node.as_str()); self.print_expr_cond_paren( rhs, - rhs.precedence() < ExprPrecedence::Assign, - fixup.subsequent_subexpression(), + fixup.precedence(rhs) < ExprPrecedence::Assign, + fixup.rightmost_subexpression(), ); } ast::ExprKind::Field(expr, ident) => { @@ -618,10 +634,11 @@ pub(super) fn print_expr_outer_attr_style( self.print_ident(*ident); } ast::ExprKind::Index(expr, index, _) => { + let expr_fixup = fixup.leftmost_subexpression_with_operator(true); self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Unambiguous, - fixup.leftmost_subexpression(), + expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous, + expr_fixup, ); self.word("["); self.print_expr(index, FixupContext::default()); @@ -634,10 +651,11 @@ pub(super) fn print_expr_outer_attr_style( // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) let fake_prec = ExprPrecedence::LOr; if let Some(e) = start { + let start_fixup = fixup.leftmost_subexpression_with_operator(true); self.print_expr_cond_paren( e, - e.precedence() < fake_prec, - fixup.leftmost_subexpression(), + start_fixup.precedence(e) < fake_prec, + start_fixup, ); } match limits { @@ -647,8 +665,8 @@ pub(super) fn print_expr_outer_attr_style( if let Some(e) = end { self.print_expr_cond_paren( e, - e.precedence() < fake_prec, - fixup.subsequent_subexpression(), + fixup.precedence(e) < fake_prec, + fixup.rightmost_subexpression(), ); } } @@ -665,11 +683,10 @@ pub(super) fn print_expr_outer_attr_style( self.space(); self.print_expr_cond_paren( expr, - // Parenthesize if required by precedence, or in the - // case of `break 'inner: loop { break 'inner 1 } + 1` - expr.precedence() < ExprPrecedence::Jump - || (opt_label.is_none() && classify::leading_labeled_expr(expr)), - fixup.subsequent_subexpression(), + // Parenthesize `break 'inner: loop { break 'inner 1 } + 1` + // ^---------------------------------^ + opt_label.is_none() && classify::leading_labeled_expr(expr), + fixup.rightmost_subexpression(), ); } } @@ -684,11 +701,7 @@ pub(super) fn print_expr_outer_attr_style( self.word("return"); if let Some(expr) = result { self.word(" "); - self.print_expr_cond_paren( - expr, - expr.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(expr, fixup.rightmost_subexpression()); } } ast::ExprKind::Yeet(result) => { @@ -697,21 +710,13 @@ pub(super) fn print_expr_outer_attr_style( self.word("yeet"); if let Some(expr) = result { self.word(" "); - self.print_expr_cond_paren( - expr, - expr.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(expr, fixup.rightmost_subexpression()); } } ast::ExprKind::Become(result) => { self.word("become"); self.word(" "); - self.print_expr_cond_paren( - result, - result.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(result, fixup.rightmost_subexpression()); } ast::ExprKind::InlineAsm(a) => { // FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`. @@ -761,11 +766,7 @@ pub(super) fn print_expr_outer_attr_style( if let Some(expr) = e { self.space(); - self.print_expr_cond_paren( - expr, - expr.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(expr, fixup.rightmost_subexpression()); } } ast::ExprKind::Yield(YieldKind::Postfix(e)) => {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs index 3ef21f5..eb5ac8b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
@@ -1,5 +1,6 @@ -use rustc_ast::Expr; -use rustc_ast::util::{classify, parser}; +use rustc_ast::util::classify; +use rustc_ast::util::parser::{self, ExprPrecedence}; +use rustc_ast::{Expr, ExprKind, YieldKind}; // The default amount of fixing is minimal fixing, so all fixups are set to `false` by `Default`. // Fixups should be turned on in a targeted fashion where needed. @@ -93,6 +94,24 @@ pub(crate) struct FixupContext { /// } /// ``` parenthesize_exterior_struct_lit: bool, + + /// This is the difference between: + /// + /// ```ignore (illustrative) + /// let _ = (return) - 1; // without paren, this would return -1 + /// + /// let _ = return + 1; // no paren because '+' cannot begin expr + /// ``` + next_operator_can_begin_expr: bool, + + /// This is the difference between: + /// + /// ```ignore (illustrative) + /// let _ = 1 + return 1; // no parens if rightmost subexpression + /// + /// let _ = 1 + (return 1) + 1; // needs parens + /// ``` + next_operator_can_continue_expr: bool, } impl FixupContext { @@ -134,6 +153,8 @@ pub(crate) fn leftmost_subexpression(self) -> Self { match_arm: false, leftmost_subexpression_in_match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, + next_operator_can_begin_expr: false, + next_operator_can_continue_expr: true, ..self } } @@ -148,19 +169,34 @@ pub(crate) fn leftmost_subexpression_with_dot(self) -> Self { leftmost_subexpression_in_stmt: false, match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, leftmost_subexpression_in_match_arm: false, + next_operator_can_begin_expr: false, + next_operator_can_continue_expr: true, ..self } } - /// Transform this fixup into the one that should apply when printing any - /// subexpression that is neither a leftmost subexpression nor surrounded in - /// delimiters. + /// Transform this fixup into the one that should apply when printing a + /// leftmost subexpression followed by punctuation that is legal as the + /// first token of an expression. + pub(crate) fn leftmost_subexpression_with_operator( + self, + next_operator_can_begin_expr: bool, + ) -> Self { + FixupContext { next_operator_can_begin_expr, ..self.leftmost_subexpression() } + } + + /// Transform this fixup into the one that should apply when printing the + /// rightmost subexpression of the current expression. /// - /// This is for any subexpression that has a different first token than the - /// current expression, and is not surrounded by a paren/bracket/brace. For - /// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or - /// `$a.f($b)`. - pub(crate) fn subsequent_subexpression(self) -> Self { + /// The rightmost subexpression is any subexpression that has a different + /// first token than the current expression, but has the same last token. + /// + /// For example in `$a + $b` and `-$b`, the subexpression `$b` is a + /// rightmost subexpression. + /// + /// Not every expression has a rightmost subexpression. For example neither + /// `[$b]` nor `$a.f($b)` have one. + pub(crate) fn rightmost_subexpression(self) -> Self { FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, @@ -193,6 +229,39 @@ pub(crate) fn would_cause_statement_boundary(self, expr: &Expr) -> bool { /// "let chain". pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool { self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr) - || parser::needs_par_as_let_scrutinee(expr.precedence()) + || parser::needs_par_as_let_scrutinee(self.precedence(expr)) + } + + /// Determines the effective precedence of a subexpression. Some expressions + /// have higher or lower precedence when adjacent to particular operators. + pub(crate) fn precedence(self, expr: &Expr) -> ExprPrecedence { + if self.next_operator_can_begin_expr { + // Decrease precedence of value-less jumps when followed by an + // operator that would otherwise get interpreted as beginning a + // value for the jump. + if let ExprKind::Break(..) + | ExprKind::Ret(..) + | ExprKind::Yeet(..) + | ExprKind::Yield(YieldKind::Prefix(..)) = expr.kind + { + return ExprPrecedence::Jump; + } + } + + if !self.next_operator_can_continue_expr { + // Increase precedence of expressions that extend to the end of + // current statement or group. + if let ExprKind::Break(..) + | ExprKind::Closure(..) + | ExprKind::Ret(..) + | ExprKind::Yeet(..) + | ExprKind::Yield(YieldKind::Prefix(..)) + | ExprKind::Range(None, ..) = expr.kind + { + return ExprPrecedence::Prefix; + } + } + + expr.precedence() } }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 3638eb3..6c44255 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -28,7 +28,7 @@ fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute] } } - fn print_foreign_item(&mut self, item: &ast::ForeignItem) { + pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) { let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); @@ -548,7 +548,7 @@ pub(crate) fn print_variant(&mut self, v: &ast::Variant) { } } - fn print_assoc_item(&mut self, item: &ast::AssocItem) { + pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) { let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol();
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 845e4d5..a0a50fd 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -130,24 +130,54 @@ pub fn is_since_rustc_version(&self) -> bool { } } -/// Represent parsed, *built in*, inert attributes. +/// Represents parsed *built-in* inert attributes. /// -/// That means attributes that are not actually ever expanded. -/// For more information on this, see the module docs on the [`rustc_attr_parsing`] crate. -/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler. -/// These are kept around after the AST, into the HIR and further on. +/// ## Overview +/// These attributes are markers that guide the compilation process and are never expanded into other code. +/// They persist throughout the compilation phases, from AST to HIR and beyond. /// -/// The word "parsed" could be a little misleading here, because the parser already parses -/// attributes early on. However, the result, an [`ast::Attribute`] -/// is only parsed at a high level, still containing a token stream in many cases. That is -/// because the structure of the contents varies from attribute to attribute. -/// With a parsed attribute I mean that each attribute is processed individually into a -/// final structure, which on-site (the place where the attribute is useful for, think the -/// the place where `must_use` is checked) little to no extra parsing or validating needs to -/// happen. +/// ## Attribute Processing +/// While attributes are initially parsed by [`rustc_parse`] into [`ast::Attribute`], they still contain raw token streams +/// because different attributes have different internal structures. This enum represents the final, +/// fully parsed form of these attributes, where each variant contains contains all the information and +/// structure relevant for the specific attribute. /// -/// For more docs, look in [`rustc_attr_parsing`]. +/// Some attributes can be applied multiple times to the same item, and they are "collapsed" into a single +/// semantic attribute. For example: +/// ```rust +/// #[repr(C)] +/// #[repr(packed)] +/// struct S { } +/// ``` +/// This is equivalent to `#[repr(C, packed)]` and results in a single [`AttributeKind::Repr`] containing +/// both `C` and `packed` annotations. This collapsing happens during parsing and is reflected in the +/// data structures defined in this enum. /// +/// ## Usage +/// These parsed attributes are used throughout the compiler to: +/// - Control code generation (e.g., `#[repr]`) +/// - Mark API stability (`#[stable]`, `#[unstable]`) +/// - Provide documentation (`#[doc]`) +/// - Guide compiler behavior (e.g., `#[allow_internal_unstable]`) +/// +/// ## Note on Attribute Organization +/// Some attributes like `InlineAttr`, `OptimizeAttr`, and `InstructionSetAttr` are defined separately +/// from this enum because they are used in specific compiler phases (like code generation) and don't +/// need to persist throughout the entire compilation process. They are typically processed and +/// converted into their final form earlier in the compilation pipeline. +/// +/// For example: +/// - `InlineAttr` is used during code generation to control function inlining +/// - `OptimizeAttr` is used to control optimization levels +/// - `InstructionSetAttr` is used for target-specific code generation +/// +/// These attributes are handled by their respective compiler passes in the [`rustc_codegen_ssa`] crate +/// and don't need to be preserved in the same way as the attributes in this enum. +/// +/// For more details on attribute parsing, see the [`rustc_attr_parsing`] crate. +/// +/// [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html +/// [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html /// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub enum AttributeKind {
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index dbfc95b..f8355be 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -1,3 +1,7 @@ +//! Data structures for representing parsed attributes in the Rust compiler. +//! For detailed documentation about attribute processing, +//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html). + // tidy-alphabetical-start #![allow(internal_features)] #![doc(rust_logo)] @@ -8,6 +12,8 @@ mod stability; mod version; +pub mod lints; + use std::num::NonZero; pub use attributes::*;
diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs new file mode 100644 index 0000000..7e3664b --- /dev/null +++ b/compiler/rustc_attr_data_structures/src/lints.rs
@@ -0,0 +1,14 @@ +use rustc_macros::HashStable_Generic; +use rustc_span::Span; + +#[derive(Clone, Debug, HashStable_Generic)] +pub struct AttributeLint<Id> { + pub id: Id, + pub span: Span, + pub kind: AttributeLintKind, +} + +#[derive(Clone, Debug, HashStable_Generic)] +pub enum AttributeLintKind { + UnusedDuplicate { this: Span, other: Span, warning: bool }, +}
diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs index c0ca08a..218e771 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_attr_data_structures/src/stability.rs
@@ -132,6 +132,7 @@ pub enum StabilityLevel { /// fn foobar() {} /// ``` implied_by: Option<Symbol>, + old_name: Option<Symbol>, }, /// `#[stable]` Stable {
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 45174c9..c9443fe 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -131,7 +131,15 @@ attr_parsing_unsupported_literal_suggestion = consider removing the prefix +attr_parsing_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-passes_previously_accepted} attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here + +-attr_parsing_perviously_accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index d046554..81192f9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -4,41 +4,43 @@ use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; pub(crate) struct AllowInternalUnstableParser; -impl CombineAttributeParser for AllowInternalUnstableParser { - const PATH: &'static [Symbol] = &[sym::allow_internal_unstable]; +impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser { + const PATH: &[Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a { - parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span)) + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> { + parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0]) + .into_iter() + .zip(iter::repeat(cx.attr_span)) } } pub(crate) struct AllowConstFnUnstableParser; -impl CombineAttributeParser for AllowConstFnUnstableParser { - const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable]; +impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser { + const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a { - parse_unstable(cx, args, Self::PATH[0]) + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { + parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0]) } } -fn parse_unstable<'a>( - cx: &AcceptContext<'_>, - args: &'a ArgParser<'a>, +fn parse_unstable<S: Stage>( + cx: &AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, symbol: Symbol, ) -> impl IntoIterator<Item = Symbol> { let mut res = Vec::new();
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 6cff952..afd3c01 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -3,7 +3,7 @@ use thin_vec::ThinVec; use super::{AcceptMapping, AttributeParser}; -use crate::context::FinalizeContext; +use crate::context::{FinalizeContext, Stage}; use crate::session_diagnostics; #[derive(Default)] @@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser { first_span: Option<Span>, } -impl AttributeParser for ConfusablesParser { - const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| { +impl<S: Stage> AttributeParser<S> for ConfusablesParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| { let Some(list) = args.list() else { // FIXME(jdonszelmann): error when not a list? Bring validation code here. // NOTE: currently subsequent attributes are silently ignored using @@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser { this.first_span.get_or_insert(cx.attr_span); })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.confusables.is_empty() { return None; }
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 006c1fe..1faee41 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,17 +1,17 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_span::{Span, Symbol, sym}; -use super::SingleAttributeParser; use super::util::parse_version; -use crate::context::AcceptContext; +use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; use crate::session_diagnostics::UnsupportedLiteralReason; pub(crate) struct DeprecationParser; -fn get( - cx: &AcceptContext<'_>, +fn get<S: Stage>( + cx: &AcceptContext<'_, '_, S>, name: Symbol, param_span: Span, arg: &ArgParser<'_>, @@ -41,19 +41,12 @@ fn get( } } -impl SingleAttributeParser for DeprecationParser { - const PATH: &'static [Symbol] = &[sym::deprecated]; +impl<S: Stage> SingleAttributeParser<S> for DeprecationParser { + const PATH: &[Symbol] = &[sym::deprecated]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) { - // FIXME(jdonszelmann): merge with errors from check_attrs.rs - cx.emit_err(session_diagnostics::UnusedMultiple { - this: cx.attr_span, - other: first_span, - name: sym::deprecated, - }); - } - - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { let features = cx.features(); let mut since = None;
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs new file mode 100644 index 0000000..c7f8208 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -0,0 +1,97 @@ +// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here. +// note: need to model better how duplicate attr errors work when not using +// SingleAttributeParser which is what we have two of here. + +use rustc_attr_data_structures::lints::AttributeLintKind; +use rustc_attr_data_structures::{AttributeKind, InlineAttr}; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use super::{AcceptContext, AttributeOrder, OnDuplicate}; +use crate::attributes::SingleAttributeParser; +use crate::context::Stage; +use crate::parser::ArgParser; + +pub(crate) struct InlineParser; + +impl<S: Stage> SingleAttributeParser<S> for InlineParser { + const PATH: &'static [Symbol] = &[sym::inline]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + match args { + ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), + ArgParser::List(list) => { + let Some(l) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + + match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) { + Some(sym::always) => { + Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)) + } + Some(sym::never) => { + Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span)) + } + _ => { + cx.expected_specific_argument(l.span(), vec!["always", "never"]); + return None; + } + } + } + ArgParser::NameValue(_) => { + let suggestions = + <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline"); + cx.emit_lint( + AttributeLintKind::IllFormedAttributeInput { suggestions }, + cx.attr_span, + ); + return None; + } + } + } +} + +pub(crate) struct RustcForceInlineParser; + +impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser { + const PATH: &'static [Symbol] = &[sym::rustc_force_inline]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason"); + + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let reason = match args { + ArgParser::NoArgs => None, + ArgParser::List(list) => { + let Some(l) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + + let Some(reason) = l.lit().and_then(|i| i.kind.str()) else { + cx.expected_string_literal(l.span()); + return None; + }; + + Some(reason) + } + ArgParser::NameValue(v) => { + let Some(reason) = v.value_as_str() else { + cx.expected_string_literal(v.value_span); + return None; + }; + + Some(reason) + } + }; + + Some(AttributeKind::Inline( + InlineAttr::Force { attr_span: cx.attr_span, reason }, + cx.attr_span, + )) + } +}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 7cceca3..caf55e6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -12,16 +12,18 @@ //! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the //! contents of attributes, if an attribute appear multiple times in a list //! -//! Attributes should be added to [`ATTRIBUTE_PARSERS`](crate::context::ATTRIBUTE_PARSERS) to be parsed. +//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed. use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::lints::AttributeLintKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, FinalizeContext}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; +use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; pub(crate) mod cfg; @@ -32,8 +34,8 @@ pub(crate) mod transparency; pub(crate) mod util; -type AcceptFn<T> = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>); -type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)]; +type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); +type AcceptMapping<T, S> = &'static [(&'static [Symbol], AcceptFn<T, S>)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -54,11 +56,11 @@ /// /// For a simpler attribute parsing interface, consider using [`SingleAttributeParser`] /// or [`CombineAttributeParser`] instead. -pub(crate) trait AttributeParser: Default + 'static { +pub(crate) trait AttributeParser<S: Stage>: Default + 'static { /// The symbols for the attributes that this parser is interested in. /// /// If an attribute has this symbol, the `accept` function will be called on it. - const ATTRIBUTES: AcceptMapping<Self>; + const ATTRIBUTES: AcceptMapping<Self, S>; /// The parser has gotten a chance to accept the attributes on an item, /// here it can produce an attribute. @@ -68,7 +70,7 @@ pub(crate) trait AttributeParser: Default + 'static { /// that'd be equivalent to unconditionally applying an attribute to /// every single syntax item that could have attributes applied to it. /// Your accept mappings should determine whether this returns something. - fn finalize(self, cx: &FinalizeContext<'_>) -> Option<AttributeKind>; + fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind>; } /// Alternative to [`AttributeParser`] that automatically handles state management. @@ -80,44 +82,131 @@ pub(crate) trait AttributeParser: Default + 'static { /// /// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait SingleAttributeParser: 'static { - const PATH: &'static [Symbol]; - - /// Called when a duplicate attribute is found. - /// - /// `first_span` is the span of the first occurrence of this attribute. - // FIXME(jdonszelmann): default error - fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span); +pub(crate) trait SingleAttributeParser<S: Stage>: 'static { + const PATH: &[Symbol]; + const ATTRIBUTE_ORDER: AttributeOrder; + const ON_DUPLICATE: OnDuplicate<S>; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>; + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>; } -pub(crate) struct Single<T: SingleAttributeParser>(PhantomData<T>, Option<(AttributeKind, Span)>); +pub(crate) struct Single<T: SingleAttributeParser<S>, S: Stage>( + PhantomData<(S, T)>, + Option<(AttributeKind, Span)>, +); -impl<T: SingleAttributeParser> Default for Single<T> { +impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> { fn default() -> Self { Self(Default::default(), Default::default()) } } -impl<T: SingleAttributeParser> AttributeParser for Single<T> { - const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| { - if let Some((_, s)) = group.1 { - T::on_duplicate(cx, s); - return; - } +impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> { + const ATTRIBUTES: AcceptMapping<Self, S> = + &[(T::PATH, |group: &mut Single<T, S>, cx, args| { + if let Some(pa) = T::convert(cx, args) { + match T::ATTRIBUTE_ORDER { + // keep the first and report immediately. ignore this attribute + AttributeOrder::KeepFirst => { + if let Some((_, unused)) = group.1 { + T::ON_DUPLICATE.exec::<T>(cx, cx.attr_span, unused); + return; + } + } + // keep the new one and warn about the previous, + // then replace + AttributeOrder::KeepLast => { + if let Some((_, used)) = group.1 { + T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span); + } + } + } - if let Some(pa) = T::convert(cx, args) { - group.1 = Some((pa, cx.attr_span)); - } - })]; + group.1 = Some((pa, cx.attr_span)); + } + })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { Some(self.1?.0) } } +// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing +// them will be merged in another PR +#[allow(unused)] +pub(crate) enum OnDuplicate<S: Stage> { + /// Give a default warning + Warn, + + /// Duplicates will be a warning, with a note that this will be an error in the future. + WarnButFutureError, + + /// Give a default error + Error, + + /// Ignore duplicates + Ignore, + + /// Custom function called when a duplicate attribute is found. + /// + /// - `unused` is the span of the attribute that was unused or bad because of some + /// duplicate reason (see [`AttributeOrder`]) + /// - `used` is the span of the attribute that was used in favor of the unused attribute + Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)), +} + +impl<S: Stage> OnDuplicate<S> { + fn exec<P: SingleAttributeParser<S>>( + &self, + cx: &mut AcceptContext<'_, '_, S>, + used: Span, + unused: Span, + ) { + match self { + OnDuplicate::Warn => cx.emit_lint( + AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: false }, + unused, + ), + OnDuplicate::WarnButFutureError => cx.emit_lint( + AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: true }, + unused, + ), + OnDuplicate::Error => { + cx.emit_err(UnusedMultiple { + this: used, + other: unused, + name: Symbol::intern( + &P::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."), + ), + }); + } + OnDuplicate::Ignore => {} + OnDuplicate::Custom(f) => f(cx, used, unused), + } + } +} +// +// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing +// them will be merged in another PR +#[allow(unused)] +pub(crate) enum AttributeOrder { + /// Duplicates after the first attribute will be an error. + /// + /// This should be used where duplicates would be ignored, but carry extra + /// meaning that could cause confusion. For example, `#[stable(since="1.0")] + /// #[stable(since="2.0")]`, which version should be used for `stable`? + KeepFirst, + + /// Duplicates preceding the last instance of the attribute will be a + /// warning, with a note that this will be an error in the future. + /// + /// This is the same as `FutureWarnFollowing`, except the last attribute is + /// the one that is "used". Ideally these can eventually migrate to + /// `ErrorPreceding`. + KeepLast, +} + type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind; /// Alternative to [`AttributeParser`] that automatically handles state management. @@ -127,35 +216,35 @@ fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { /// /// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait CombineAttributeParser: 'static { - const PATH: &'static [Symbol]; +pub(crate) trait CombineAttributeParser<S: Stage>: 'static { + const PATH: &[rustc_span::Symbol]; type Item; const CONVERT: ConvertFn<Self::Item>; /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a; + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c; } -pub(crate) struct Combine<T: CombineAttributeParser>( - PhantomData<T>, - ThinVec<<T as CombineAttributeParser>::Item>, +pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>( + PhantomData<(S, T)>, + ThinVec<<T as CombineAttributeParser<S>>::Item>, ); -impl<T: CombineAttributeParser> Default for Combine<T> { +impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> { fn default() -> Self { Self(Default::default(), Default::default()) } } -impl<T: CombineAttributeParser> AttributeParser for Combine<T> { - const ATTRIBUTES: AcceptMapping<Self> = - &[(T::PATH, |group: &mut Combine<T>, cx, args| group.1.extend(T::extend(cx, args)))]; +impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> { + const ATTRIBUTES: AcceptMapping<Self, S> = + &[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } } }
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 6931654..753b236 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -4,7 +4,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; +use crate::context::{AcceptContext, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; use crate::session_diagnostics; use crate::session_diagnostics::IncorrectReprFormatGenericCause; @@ -19,15 +19,15 @@ // FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct? pub(crate) struct ReprParser; -impl CombineAttributeParser for ReprParser { +impl<S: Stage> CombineAttributeParser<S> for ReprParser { type Item = (ReprAttr, Span); - const PATH: &'static [Symbol] = &[sym::repr]; + const PATH: &[Symbol] = &[sym::repr]; const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a { + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { let mut reprs = Vec::new(); let Some(list) = args.list() else { @@ -91,7 +91,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> { } } -fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> { +fn parse_repr<S: Stage>( + cx: &AcceptContext<'_, '_, S>, + param: &MetaItemParser<'_>, +) -> Option<ReprAttr> { use ReprAttr::*; // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the @@ -180,8 +183,8 @@ enum AlignKind { Align, } -fn parse_repr_align( - cx: &AcceptContext<'_>, +fn parse_repr_align<S: Stage>( + cx: &AcceptContext<'_, '_, S>, list: &MetaItemListParser<'_>, param_span: Span, align_kind: AlignKind,
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index ce69a54..6589a51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -8,8 +8,8 @@ use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; -use super::{AcceptMapping, AttributeParser, SingleAttributeParser}; -use crate::context::{AcceptContext, FinalizeContext}; +use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -31,7 +31,7 @@ pub(crate) struct StabilityParser { impl StabilityParser { /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool { if let Some((_, _)) = self.stability { cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); true @@ -41,8 +41,8 @@ fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { } } -impl AttributeParser for StabilityParser { - const ATTRIBUTES: AcceptMapping<Self> = &[ +impl<S: Stage> AttributeParser<S> for StabilityParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[ (&[sym::stable], |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) @@ -65,7 +65,7 @@ impl AttributeParser for StabilityParser { }), ]; - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if let Some(atum) = self.allowed_through_unstable_modules { if let Some(( Stability { @@ -95,8 +95,8 @@ pub(crate) struct BodyStabilityParser { stability: Option<(DefaultBodyStability, Span)>, } -impl AttributeParser for BodyStabilityParser { - const ATTRIBUTES: AcceptMapping<Self> = +impl<S: Stage> AttributeParser<S> for BodyStabilityParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_default_body_unstable], |this, cx, args| { reject_outside_std!(cx); if this.stability.is_some() { @@ -107,7 +107,7 @@ impl AttributeParser for BodyStabilityParser { } })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { let (stability, span) = self.stability?; Some(AttributeKind::BodyStability { stability, span }) @@ -116,13 +116,12 @@ fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { pub(crate) struct ConstStabilityIndirectParser; // FIXME(jdonszelmann): single word attribute group when we have these -impl SingleAttributeParser for ConstStabilityIndirectParser { - const PATH: &'static [Symbol] = &[sym::rustc_const_stable_indirect]; +impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser { + const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; - // ignore - fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {} - - fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { Some(AttributeKind::ConstStabilityIndirect) } } @@ -135,7 +134,7 @@ pub(crate) struct ConstStabilityParser { impl ConstStabilityParser { /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool { if let Some((_, _)) = self.stability { cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); true @@ -145,8 +144,8 @@ fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { } } -impl AttributeParser for ConstStabilityParser { - const ATTRIBUTES: AcceptMapping<Self> = &[ +impl<S: Stage> AttributeParser<S> for ConstStabilityParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[ (&[sym::rustc_const_stable], |this, cx, args| { reject_outside_std!(cx); @@ -176,7 +175,7 @@ impl AttributeParser for ConstStabilityParser { }), ]; - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.promotable { if let Some((ref mut stab, _)) = self.stability { stab.promotable = true; @@ -196,8 +195,8 @@ fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> { /// /// Emits an error when either the option was already Some, or the arguments weren't of form /// `name = value` -fn insert_value_into_option_or_error( - cx: &AcceptContext<'_>, +fn insert_value_into_option_or_error<S: Stage>( + cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser<'_>, item: &mut Option<Symbol>, ) -> Option<()> { @@ -223,8 +222,8 @@ fn insert_value_into_option_or_error( /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and /// its stability information. -pub(crate) fn parse_stability( - cx: &AcceptContext<'_>, +pub(crate) fn parse_stability<S: Stage>( + cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; @@ -289,8 +288,8 @@ pub(crate) fn parse_stability( // Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` /// attribute, and return the feature name and its stability information. -pub(crate) fn parse_unstability( - cx: &AcceptContext<'_>, +pub(crate) fn parse_unstability<S: Stage>( + cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; @@ -299,6 +298,7 @@ pub(crate) fn parse_unstability( let mut issue_num = None; let mut is_soft = false; let mut implied_by = None; + let mut old_name = None; for param in args.list()?.mixed() { let Some(param) = param.meta_item() else { cx.emit_err(session_diagnostics::UnsupportedLiteral { @@ -346,11 +346,12 @@ pub(crate) fn parse_unstability( Some(sym::implied_by) => { insert_value_into_option_or_error(cx, ¶m, &mut implied_by)? } + Some(sym::old_name) => insert_value_into_option_or_error(cx, ¶m, &mut old_name)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), item: param.path().to_string(), - expected: &["feature", "reason", "issue", "soft", "implied_by"], + expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"], }); return None; } @@ -375,6 +376,7 @@ pub(crate) fn parse_unstability( issue: issue_num, is_soft, implied_by, + old_name, }; Some((feature, level)) }
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index d229fc0..16ad9d0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -1,8 +1,9 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::hygiene::Transparency; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Symbol, sym}; -use super::{AcceptContext, SingleAttributeParser}; +use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; pub(crate) struct TransparencyParser; @@ -10,14 +11,14 @@ // FIXME(jdonszelmann): make these proper diagnostics #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -impl SingleAttributeParser for TransparencyParser { - const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency]; +impl<S: Stage> SingleAttributeParser<S> for TransparencyParser { + const PATH: &[Symbol] = &[sym::rustc_macro_transparency]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| { + cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); + }); - fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) { - cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes"); - } - - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { match args.name_value().and_then(|nv| nv.value_as_str()) { Some(sym::transparent) => Some(Transparency::Transparent), Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 35fb768..47f7223 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -1,13 +1,17 @@ use std::cell::RefCell; use std::collections::BTreeMap; -use std::ops::Deref; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; +use private::Sealed; use rustc_ast as ast; +use rustc_ast::NodeId; use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::Features; -use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId}; +use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -22,20 +26,40 @@ use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; +macro_rules! group_type { + ($stage: ty) => { + LazyLock<( + BTreeMap<&'static [Symbol], Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>, + Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>> + )> + }; +} + macro_rules! attribute_parsers { ( pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { - type Accepts = BTreeMap< - &'static [Symbol], - Box<dyn Send + Sync + Fn(&AcceptContext<'_>, &ArgParser<'_>)> - >; - type Finalizes = Vec< - Box<dyn Send + Sync + Fn(&FinalizeContext<'_>) -> Option<AttributeKind>> - >; - pub(crate) static $name: LazyLock<(Accepts, Finalizes)> = LazyLock::new(|| { - let mut accepts = Accepts::new(); - let mut finalizes = Finalizes::new(); + mod early { + use super::*; + type Combine<T> = super::Combine<T, Early>; + type Single<T> = super::Single<T, Early>; + + attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];); + } + mod late { + use super::*; + type Combine<T> = super::Combine<T, Late>; + type Single<T> = super::Single<T, Late>; + + attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];); + } + }; + ( + @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; + ) => { + pub(crate) static $name: group_type!($ty) = LazyLock::new(|| { + let mut accepts = BTreeMap::<_, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>::new(); + let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new(); $( { thread_local! { @@ -62,7 +86,6 @@ macro_rules! attribute_parsers { }); }; } - attribute_parsers!( pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start @@ -86,50 +109,114 @@ macro_rules! attribute_parsers { ]; ); +mod private { + pub trait Sealed {} + impl Sealed for super::Early {} + impl Sealed for super::Late {} +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +pub trait Stage: Sized + 'static + Sealed { + type Id: Copy; + + fn parsers() -> &'static group_type!(Self); + + fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed; +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +impl Stage for Early { + type Id = NodeId; + + fn parsers() -> &'static group_type!(Self) { + &early::ATTRIBUTE_PARSERS + } + fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + sess.dcx().create_err(diag).delay_as_bug() + } +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +impl Stage for Late { + type Id = HirId; + + fn parsers() -> &'static group_type!(Self) { + &late::ATTRIBUTE_PARSERS + } + fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + tcx.dcx().emit_err(diag) + } +} + +/// used when parsing attributes for miscelaneous things *before* ast lowering +pub struct Early; +/// used when parsing attributes during ast lowering +pub struct Late; + /// Context given to every attribute parser when accepting /// /// Gives [`AttributeParser`]s enough information to create errors, for example. -pub(crate) struct AcceptContext<'a> { - pub(crate) finalize_cx: &'a FinalizeContext<'a>, +pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { + pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, } -impl<'a> AcceptContext<'a> { - pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed { - if self.limit_diagnostics { - self.dcx().create_err(diag).delay_as_bug() - } else { - self.dcx().emit_err(diag) - } +impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { + pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + S::emit_err(&self.sess, diag) + } + + pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { + let id = self.target_id; + (self.emit_lint)(AttributeLint { id, span, kind: lint }); } } -impl<'a> Deref for AcceptContext<'a> { - type Target = FinalizeContext<'a>; +impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { + type Target = FinalizeContext<'f, 'sess, S>; fn deref(&self) -> &Self::Target { &self.finalize_cx } } +impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.finalize_cx + } +} + /// Context given to every attribute parser during finalization. /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create /// errors, for example. -pub(crate) struct FinalizeContext<'a> { +pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. - pub(crate) cx: &'a AttributeParser<'a>, + pub(crate) cx: &'p mut AttributeParser<'sess, S>, /// The span of the syntactical component this attribute was applied to pub(crate) target_span: Span, + /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to + pub(crate) target_id: S::Id, + + pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>), } -impl<'a> Deref for FinalizeContext<'a> { - type Target = AttributeParser<'a>; +impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { + type Target = AttributeParser<'sess, S>; fn deref(&self) -> &Self::Target { - &self.cx + self.cx + } +} + +impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.cx } } @@ -141,23 +228,20 @@ pub enum OmitDoc { /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. -pub struct AttributeParser<'sess> { +pub struct AttributeParser<'sess, S: Stage = Late> { #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes tools: Vec<Symbol>, - sess: &'sess Session, features: Option<&'sess Features>, + sess: &'sess Session, + stage: PhantomData<S>, /// *Only* parse attributes with this symbol. /// /// Used in cases where we want the lowering infrastructure for parse just a single attribute. parse_only: Option<Symbol>, - - /// Can be used to instruct parsers to reduce the number of diagnostics it emits. - /// Useful when using `parse_limited` and you know the attr will be reparsed later. - pub(crate) limit_diagnostics: bool, } -impl<'sess> AttributeParser<'sess> { +impl<'sess> AttributeParser<'sess, Early> { /// This method allows you to parse attributes *before* you have access to features or tools. /// One example where this is necessary, is to parse `feature` attributes themselves for /// example. @@ -168,33 +252,53 @@ impl<'sess> AttributeParser<'sess> { /// /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with /// that symbol are picked out of the list of instructions and parsed. Those are returned. + /// + /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while + /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed + /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors pub fn parse_limited( sess: &'sess Session, attrs: &[ast::Attribute], sym: Symbol, target_span: Span, - limit_diagnostics: bool, + target_node_id: NodeId, ) -> Option<Attribute> { - let mut parsed = Self { - sess, + let mut p = Self { features: None, tools: Vec::new(), parse_only: Some(sym), - limit_diagnostics, - } - .parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity); - + sess, + stage: PhantomData, + }; + let mut parsed = p.parse_attribute_list( + attrs, + target_span, + target_node_id, + OmitDoc::Skip, + std::convert::identity, + |_lint| { + panic!("can't emit lints here for now (nothing uses this atm)"); + }, + ); assert!(parsed.len() <= 1); parsed.pop() } - pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self { - Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false } + pub fn new_early(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } } +} +impl<'sess> AttributeParser<'sess, Late> { + pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } + } +} + +impl<'sess, S: Stage> AttributeParser<'sess, S> { pub(crate) fn sess(&self) -> &'sess Session { - self.sess + &self.sess } pub(crate) fn features(&self) -> &'sess Features { @@ -202,25 +306,25 @@ pub(crate) fn features(&self) -> &'sess Features { } pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { - self.sess.dcx() + self.sess().dcx() } /// Parse a list of attributes. /// /// `target_span` is the span of the thing this list of attributes is applied to, /// and when `omit_doc` is set, doc attributes are filtered out. - pub fn parse_attribute_list<'a>( - &'a self, - attrs: &'a [ast::Attribute], + pub fn parse_attribute_list( + &mut self, + attrs: &[ast::Attribute], target_span: Span, + target_id: S::Id, omit_doc: OmitDoc, lower_span: impl Copy + Fn(Span) -> Span, + mut emit_lint: impl FnMut(AttributeLint<S::Id>), ) -> Vec<Attribute> { let mut attributes = Vec::new(); - let finalize_cx = FinalizeContext { cx: self, target_span }; - for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. if let Some(expected) = self.parse_only { @@ -268,13 +372,18 @@ pub fn parse_attribute_list<'a>( let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::<Vec<_>>(); - if let Some(accept) = ATTRIBUTE_PARSERS.0.get(parts.as_slice()) { - let cx = AcceptContext { - finalize_cx: &finalize_cx, + if let Some(accept) = S::parsers().0.get(parts.as_slice()) { + let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { + finalize_cx: FinalizeContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }, attr_span: lower_span(attr.span), }; - accept(&cx, &args) + accept(&mut cx, args) } else { // If we're here, we must be compiling a tool attribute... Or someone // forgot to parse their fancy new attribute. Let's warn them in any case. @@ -304,8 +413,13 @@ pub fn parse_attribute_list<'a>( } let mut parsed_attributes = Vec::new(); - for f in &ATTRIBUTE_PARSERS.1 { - if let Some(attr) = f(&finalize_cx) { + for f in &S::parsers().1 { + if let Some(attr) = f(&mut FinalizeContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }) { parsed_attributes.push(Attribute::Parsed(attr)); } }
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 15037e8..47eeb63 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -85,7 +85,8 @@ #[macro_use] mod attributes; -mod context; +pub(crate) mod context; +mod lints; pub mod parser; mod session_diagnostics; @@ -93,6 +94,7 @@ pub use attributes::util::{ find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, }; -pub use context::{AttributeParser, OmitDoc}; +pub use context::{AttributeParser, Early, Late, OmitDoc}; +pub use lints::emit_attribute_lint; rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs new file mode 100644 index 0000000..d0d1124 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/lints.rs
@@ -0,0 +1,19 @@ +use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; +use rustc_errors::LintEmitter; +use rustc_hir::HirId; + +use crate::session_diagnostics; + +pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) { + let AttributeLint { id, span, kind } = lint; + + match kind { + &AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter + .emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *span, + session_diagnostics::UnusedDuplicate { this, other, warning }, + ), + } +}
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index e10e3b5..1edbe3a 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -115,7 +115,7 @@ pub fn span(&self) -> Option<Span> { } } - pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self { + pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self { match value { AttrArgs::Empty => Self::NoArgs, AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { @@ -235,7 +235,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { impl<'a> MetaItemParser<'a> { /// Create a new parser from a [`NormalAttr`], which is stored inside of any /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self { + pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self { Self { path: PathParser::Ast(&attr.item.path), args: ArgParser::from_attr_args(&attr.item.args, dcx), @@ -320,13 +320,13 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit } } -struct MetaItemListParserContext<'a> { +struct MetaItemListParserContext<'a, 'sess> { // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside inside_delimiters: Peekable<TokenStreamIter<'a>>, - dcx: DiagCtxtHandle<'a>, + dcx: DiagCtxtHandle<'sess>, } -impl<'a> MetaItemListParserContext<'a> { +impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { fn done(&mut self) -> bool { self.inside_delimiters.peek().is_none() } @@ -507,11 +507,11 @@ pub struct MetaItemListParser<'a> { } impl<'a> MetaItemListParser<'a> { - fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> { + fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self { MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx) } - fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self { + fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self { MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span) }
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2c43417..7f847d3 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -3,7 +3,7 @@ use rustc_ast as ast; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; @@ -451,6 +451,17 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_unused_duplicate)] +pub(crate) struct UnusedDuplicate { + #[suggestion(code = "", applicability = "machine-applicable")] + pub this: Span, + #[note] + pub other: Span, + #[warning] + pub warning: bool, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd {
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 7511a55..57db2e9 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph; -use rustc_index::bit_set::DenseBitSet; +use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; use rustc_middle::mir::{ self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, }; @@ -548,7 +548,7 @@ fn kill_borrows_on_place( } } -type BorrowsDomain = DenseBitSet<BorrowIndex>; +type BorrowsDomain = MixedBitSet<BorrowIndex>; /// Forward dataflow computation of the set of borrows that are in scope at a particular location. /// - we gen the introduced loans @@ -564,7 +564,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = nothing is reserved or activated yet; - DenseBitSet::new_empty(self.borrow_set.len()) + MixedBitSet::new_empty(self.borrow_set.len()) } fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1b4bb11..34d3684 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3229,8 +3229,20 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { Applicability::MaybeIncorrect, ); } + + let mutability = if matches!(borrow.kind(), BorrowKind::Mut { .. }) { + "mut " + } else { + "" + }; + if !is_format_arguments_item { - let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + let addition = format!( + "let {}binding = {};\n{}", + mutability, + s, + " ".repeat(p) + ); err.multipart_suggestion_verbose( msg, vec![
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index a845431..c4b0f50 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -342,6 +342,10 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { } } } else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { + let sp = info + .span + .find_ancestor_in_same_ctxt(local_decl.source_info.span) + .unwrap_or(info.span); if info.tail_result_is_ignored { // #85581: If the first mutable borrow's scope contains // the second borrow, this suggestion isn't helpful. @@ -349,7 +353,7 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { old.to(info.span.shrink_to_hi()).contains(new) }) { err.span_suggestion_verbose( - info.span.shrink_to_hi(), + sp.shrink_to_hi(), "consider adding semicolon after the expression so its \ temporaries are dropped sooner, before the local variables \ declared by the block are dropped", @@ -368,8 +372,8 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { local variable `x` and then make `x` be the expression at the \ end of the block", vec![ - (info.span.shrink_to_lo(), "let x = ".to_string()), - (info.span.shrink_to_hi(), "; x".to_string()), + (sp.shrink_to_lo(), "let x = ".to_string()), + (sp.shrink_to_hi(), "; x".to_string()), ], Applicability::MaybeIncorrect, );
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e6eae7d..4d85f10 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs
@@ -29,7 +29,7 @@ use rustc_hir as hir; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LocalDefId; -use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; +use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, @@ -1151,11 +1151,11 @@ fn borrows_in_scope<'s>( &self, location: Location, state: &'s BorrowckDomain, - ) -> Cow<'s, DenseBitSet<BorrowIndex>> { + ) -> Cow<'s, MixedBitSet<BorrowIndex>> { if let Some(polonius) = &self.polonius_output { // Use polonius output if it has been enabled. let location = self.location_table.start_index(location); - let mut polonius_output = DenseBitSet::new_empty(self.borrow_set.len()); + let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len()); for &idx in polonius.errors_at(location) { polonius_output.insert(idx); }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 4f75dd7..9b6dcfd 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -373,8 +373,7 @@ fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> RegionVid { } fn unsized_feature_enabled(&self) -> bool { - let features = self.tcx().features(); - features.unsized_locals() || features.unsized_fn_params() + self.tcx().features().unsized_fn_params() } /// Equate the inferred type and the annotated type for user type annotations @@ -957,7 +956,7 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { } } - // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls + // When `unsized_fn_params` is enabled, only function calls // and nullary ops are checked in `check_call_dest`. if !self.unsized_feature_enabled() { match self.body.local_kind(local) { @@ -1941,7 +1940,7 @@ fn check_call_dest( ); } - // When `unsized_fn_params` and `unsized_locals` are both not enabled, + // When `unsized_fn_params` is not enabled, // this check is done at `check_local`. if self.unsized_feature_enabled() { let span = term.source_info.span;
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6dd3adf..d642851 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -484,7 +484,7 @@ pub(crate) fn expand_ext( match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true), + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) );
diff --git a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs index 5479b0c..f0d1f6e 100644 --- a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs +++ b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -32,10 +32,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {} impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {} trait Trait { - // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable - // without unsized_locals), but wrappers around `Self` currently are not. - // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented - // fn wrapper(self: Wrapper<Self>) -> i32; fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32; fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32; fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 1dc799c..012e4db 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -644,9 +644,9 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] - pub fn min_align_of<T>() -> usize; + pub fn align_of<T>() -> usize; #[rustc_intrinsic] - pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize; + pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic]
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 93ca2e0..1499f94 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -204,11 +204,8 @@ fn main() { assert_eq!(intrinsics::size_of_val(a) as u8, 16); assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); - assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2); - assert_eq!( - intrinsics::min_align_of_val(&a) as u8, - intrinsics::min_align_of::<&str>() as u8 - ); + assert_eq!(intrinsics::align_of::<u16>() as u8, 2); + assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); assert!(!intrinsics::needs_drop::<u8>()); assert!(!intrinsics::needs_drop::<[u8]>());
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index fe5b220..4c6fd90 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv( CanonAbi::Rust | CanonAbi::C => default_call_conv, CanonAbi::RustCold => CallConv::Cold, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => default_call_conv, + CanonAbi::X86(x86_call) => match x86_call { X86Call::SysV64 => CallConv::SystemV, X86Call::Win64 => CallConv::WindowsFastcall,
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 6d8614a..9a0a5b5 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -1,6 +1,6 @@ //! Argument passing -use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; +use cranelift_codegen::ir::ArgumentPurpose; use rustc_abi::{Reg, RegKind}; use rustc_target::callconv::{ ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, @@ -32,13 +32,12 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam { AbiParam::new(clif_ty) } -fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam { +fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam { match arg_attrs.arg_ext { - RustcArgExtension::None => {} - RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext, - RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext, + RustcArgExtension::None => param, + RustcArgExtension::Zext => param.uext(), + RustcArgExtension::Sext => param.sext(), } - param } fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> { @@ -82,7 +81,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { match self.mode { PassMode::Ignore => smallvec![], PassMode::Direct(attrs) => match self.layout.backend_repr { - BackendRepr::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( + BackendRepr::Scalar(scalar) => smallvec![apply_attrs_to_abi_param( AbiParam::new(scalar_to_clif_type(tcx, scalar)), attrs )], @@ -97,8 +96,8 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); smallvec![ - apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a), - apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b), + apply_attrs_to_abi_param(AbiParam::new(a), attrs_a), + apply_attrs_to_abi_param(AbiParam::new(b), attrs_b), ] } _ => unreachable!("{:?}", self.layout.backend_repr), @@ -112,19 +111,19 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { // Abi requires aligning struct size to pointer size let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi); let size = u32::try_from(size.bytes()).unwrap(); - smallvec![apply_arg_attrs_to_abi_param( + smallvec![apply_attrs_to_abi_param( AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),), attrs )] } else { - smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] + smallvec![apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] } } PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { assert!(!on_stack); smallvec![ - apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), - apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs), + apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), + apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs), ] } } @@ -133,30 +132,46 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) { match self.mode { PassMode::Ignore => (None, vec![]), - PassMode::Direct(_) => match self.layout.backend_repr { - BackendRepr::Scalar(scalar) => { - (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) - } + PassMode::Direct(attrs) => match self.layout.backend_repr { + BackendRepr::Scalar(scalar) => ( + None, + vec![apply_attrs_to_abi_param( + AbiParam::new(scalar_to_clif_type(tcx, scalar)), + attrs, + )], + ), BackendRepr::SimdVector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); - (None, vec![AbiParam::new(vector_ty)]) + (None, vec![apply_attrs_to_abi_param(AbiParam::new(vector_ty), attrs)]) } _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Pair(_, _) => match self.layout.backend_repr { + PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr { BackendRepr::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); - (None, vec![AbiParam::new(a), AbiParam::new(b)]) + ( + None, + vec![ + apply_attrs_to_abi_param(AbiParam::new(a), attrs_a), + apply_attrs_to_abi_param(AbiParam::new(b), attrs_b), + ], + ) } _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Cast { ref cast, .. } => { (None, cast_target_to_abi_params(cast).into_iter().collect()) } - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => { + PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { assert!(!on_stack); - (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![]) + ( + Some(apply_attrs_to_abi_param( + AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn), + attrs, + )), + vec![], + ) } PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value")
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 5d07c94..442151f 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -11,7 +11,6 @@ use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::assert_module_sources::CguReuse; use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{ CodegenResults, CompiledModule, CrateInfo, ModuleKind, errors as ssa_errors, @@ -19,7 +18,6 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; -use rustc_metadata::EncodedMetadata; use rustc_metadata::fs::copy_to_stdout; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -61,8 +59,6 @@ fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { pub(crate) struct OngoingCodegen { modules: Vec<OngoingModuleCodegen>, allocator_module: Option<CompiledModule>, - metadata_module: Option<CompiledModule>, - metadata: EncodedMetadata, crate_info: CrateInfo, concurrency_limiter: ConcurrencyLimiter, } @@ -134,8 +130,6 @@ pub(crate) fn join( let codegen_results = CodegenResults { modules, allocator_module: self.allocator_module, - metadata_module: self.metadata_module, - metadata: self.metadata, crate_info: self.crate_info, }; @@ -646,42 +640,6 @@ fn module_codegen( })) } -fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> CompiledModule { - use rustc_middle::mir::mono::CodegenUnitNameBuilder; - - let _timer = tcx.sess.timer("write compressed metadata"); - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) - .as_str() - .to_string(); - - let tmp_file = tcx.output_filenames(()).temp_path_for_cgu( - OutputType::Metadata, - &metadata_cgu_name, - tcx.sess.invocation_temp.as_deref(), - ); - - let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); - let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name); - - if let Err(err) = std::fs::write(&tmp_file, obj) { - tcx.dcx().fatal(format!("error writing metadata object file: {}", err)); - } - - CompiledModule { - name: metadata_cgu_name, - kind: ModuleKind::Metadata, - object: Some(tmp_file), - dwarf_object: None, - bytecode: None, - assembly: None, - llvm_ir: None, - links_from_incr_cache: Vec::new(), - } -} - fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> { let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string()); let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); @@ -706,11 +664,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> { } } -pub(crate) fn run_aot( - tcx: TyCtxt<'_>, - metadata: EncodedMetadata, - need_metadata_module: bool, -) -> Box<OngoingCodegen> { +pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box<OngoingCodegen> { // FIXME handle `-Ctarget-cpu=native` let target_cpu = match tcx.sess.opts.cg.target_cpu { Some(ref name) => name, @@ -726,8 +680,6 @@ pub(crate) fn run_aot( return Box::new(OngoingCodegen { modules: vec![], allocator_module: None, - metadata_module: None, - metadata, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: ConcurrencyLimiter::new(0), }); @@ -787,14 +739,9 @@ pub(crate) fn run_aot( let allocator_module = emit_allocator_module(tcx); - let metadata_module = - if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None }; - Box::new(OngoingCodegen { modules, allocator_module, - metadata_module, - metadata, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: concurrency_limiter.0, })
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 1d1cf88..df5748c 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta); ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); } - sym::min_align_of_val => { + sym::align_of_val => { intrinsic_args!(fx, args => (ptr); intrinsic); let layout = fx.layout_of(generic_args.type_at(0)); @@ -613,7 +613,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (vtable); intrinsic); let vtable = vtable.load_scalar(fx); - let align = crate::vtable::min_align_of_obj(fx, vtable); + let align = crate::vtable::align_of_obj(fx, vtable); ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); }
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 8ef623c..07ea29f 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -46,7 +46,6 @@ use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenResults, TargetConfig}; -use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; use rustc_session::config::OutputFilenames; @@ -238,12 +237,7 @@ fn print_version(&self) { println!("Cranelift version: {}", cranelift_codegen::VERSION); } - fn codegen_crate( - &self, - tcx: TyCtxt<'_>, - metadata: EncodedMetadata, - need_metadata_module: bool, - ) -> Box<dyn Any> { + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); let config = self.config.clone().unwrap_or_else(|| { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) @@ -256,7 +250,7 @@ fn codegen_crate( #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); } else { - driver::aot::run_aot(tcx, metadata, need_metadata_module) + driver::aot::run_aot(tcx) } }
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 662546e..df60b05 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>( // load size/align from vtable ( crate::vtable::size_of_obj(fx, info.unwrap()), - crate::vtable::min_align_of_obj(fx, info.unwrap()), + crate::vtable::align_of_obj(fx, info.unwrap()), ) } ty::Slice(_) | ty::Str => {
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 05a8e3c..1fae569 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val ) } -pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { +pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; fx.bcx.ins().load( fx.pointer_type,
diff --git a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs index b299aa8..c26606f 100644 --- a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs +++ b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -37,10 +37,6 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {} trait Trait { - // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable - // without unsized_locals), but wrappers around `Self` currently are not. - // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented - // fn wrapper(self: Wrapper<Self>) -> i32; fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32; fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32; fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index d1d8e8f..aca1f00 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -655,9 +655,9 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] - pub fn min_align_of<T>() -> usize; + pub fn align_of<T>() -> usize; #[rustc_intrinsic] - pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize; + pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic]
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 4cbe66c..c3bd62e 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -153,7 +153,7 @@ fn main() { let slice = &[0, 1] as &[i32]; let slice_ptr = slice as *const [i32] as *const i32; - let align = intrinsics::min_align_of::<*const i32>(); + let align = intrinsics::align_of::<*const i32>(); assert_eq!(slice_ptr as usize % align, 0); //return; @@ -194,8 +194,8 @@ fn main() { assert_eq!(intrinsics::size_of_val(a) as u8, 8); assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); - assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2); - assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8); + assert_eq!(intrinsics::align_of::<u16>() as u8, 2); + assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); assert!(!intrinsics::needs_drop::<u8>()); assert!(!intrinsics::needs_drop::<[u8]>());
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 546bfc87..18a8a5a 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl
@@ -2,9 +2,6 @@ unknown feature specified for `-Ctarget-feature`: `{$feature}` .note = features must begin with a `+` to enable or `-` to disable it -codegen_gcc_forbidden_ctarget_feature = - target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason} - codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm @@ -26,10 +23,6 @@ .possible_feature = you might have meant: `{$rust_feature}` .consider_filing_feature_request = consider filing a feature request -codegen_gcc_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future - codegen_gcc_missing_features = add the missing features in a `target_feature` attribute
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 3d0c258..08f3d28 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -239,12 +239,16 @@ fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<FnAttribute<'gcc>> { pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> { let attribute = match conv { CanonAbi::C | CanonAbi::Rust => return None, + CanonAbi::RustCold => FnAttribute::Cold, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => return None, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall, ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry, ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"), }, - CanonAbi::RustCold => FnAttribute::Cold, CanonAbi::GpuKernel => { if arch == "amdgpu" { FnAttribute::GcnAmdGpuHsaKernel
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index d1fb8d8..68c6156 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -30,7 +30,7 @@ use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::callconv::FnAbi; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; @@ -897,7 +897,7 @@ fn frem_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gc fn checked_binop( &mut self, oop: OverflowOp, - typ: Ty<'_>, + typ: Ty<'tcx>, lhs: Self::Value, rhs: Self::Value, ) -> (Self::Value, Self::Value) { @@ -2394,12 +2394,6 @@ fn target_spec(&self) -> &Target { } } -impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.cx.wasm_c_abi_opt() - } -} - impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> { fn x86_abi_opt(&self) -> X86Abi { self.cx.x86_abi_opt()
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index c6c4320..4955e03 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -19,9 +19,7 @@ use rustc_session::Session; use rustc_span::source_map::respan; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::spec::{ - HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi, -}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi}; #[cfg(feature = "master")] use crate::abi::conv_to_fn_attribute; @@ -512,12 +510,6 @@ fn target_spec(&self) -> &Target { } } -impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.tcx.sess.opts.unstable_opts.wasm_c_abi - } -} - impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> { fn x86_abi_opt(&self) -> X86Abi { X86Abi {
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index ccd9abe..7786be9 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> { pub rust_feature: PossibleFeature<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_gcc_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_gcc_forbidden_ctarget_feature)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - #[derive(Subdiagnostic)] pub(crate) enum PossibleFeature<'a> { #[help(codegen_gcc_possible_feature)]
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 2b053ab..d90e66a 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -5,13 +5,17 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_session::Session; +use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; -use crate::errors::{ - ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, - UnstableCTargetFeature, -}; +use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; + +fn gcc_features_by_flags(sess: &Session) -> Vec<&str> { + let mut features: Vec<&str> = Vec::new(); + retpoline_features_by_flags(sess, &mut features); + features +} /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). @@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri // Compute implied features let mut all_rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',') { + for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) { if let Some(feature) = feature.strip_prefix('+') { all_rust_features.extend( UnordSet::from(sess.target.implied_target_features(feature)) @@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri sess.dcx().emit_warn(unknown_feature); } Some(&(_, stability, _)) => { - if let Err(reason) = stability.toggle_allowed() { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. (It makes little sense - // to hard-error here since we just warn about fully unknown - // features above). - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } + stability.verify_feature_enabled_by_flag(sess, enable, feature); } }
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 0591ffa..dbecbc4 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -48,7 +48,6 @@ #[cfg(feature = "master")] extern crate rustc_interface; extern crate rustc_macros; -extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; @@ -106,7 +105,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; -use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; @@ -230,20 +228,9 @@ fn provide(&self, providers: &mut Providers) { providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true) } - fn codegen_crate( - &self, - tcx: TyCtxt<'_>, - metadata: EncodedMetadata, - need_metadata_module: bool, - ) -> Box<dyn Any> { + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> { let target_cpu = target_cpu(tcx.sess); - let res = codegen_crate( - self.clone(), - tcx, - target_cpu.to_string(), - metadata, - need_metadata_module, - ); + let res = codegen_crate(self.clone(), tcx, target_cpu.to_string()); Box::new(res) }
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index bda121c..3faeb9b 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -10,11 +10,6 @@ codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture -codegen_llvm_forbidden_ctarget_feature = - target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} - .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> - codegen_llvm_from_llvm_diag = {$message} codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message} @@ -76,10 +71,6 @@ codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo -codegen_llvm_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future - codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} codegen_llvm_write_ir = failed to write LLVM IR to {$path}
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 119cd63..aba63d7 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -649,6 +649,10 @@ pub(crate) fn from_conv(conv: CanonAbi, arch: &str) -> Self { match conv { CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, CanonAbi::RustCold => llvm::PreserveMost, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => llvm::CCallConv, CanonAbi::GpuKernel => { if arch == "amdgpu" { llvm::AmdgpuKernel
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 4185aef..9ddadcf 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -1021,6 +1021,15 @@ fn llvm_fixup_input<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } + (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) => + { + // Smaller floats are always "NaN-boxed" inside larger floats on LoongArch. + let value = bx.bitcast(value, bx.type_i16()); + let value = bx.zext(value, bx.type_i32()); + let value = bx.or(value, bx.const_u32(0xFFFF_0000)); + bx.bitcast(value, bx.type_f32()) + } (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1178,6 +1187,13 @@ fn llvm_fixup_output<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } + (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) => + { + let value = bx.bitcast(value, bx.type_i32()); + let value = bx.trunc(value, bx.type_i16()); + bx.bitcast(value, bx.type_f16()) + } (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1318,6 +1334,11 @@ fn llvm_fixup_output_type<'ll, 'tcx>( ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } + (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) => + { + cx.type_f32() + } (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics.
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index ec006b5..5e9594d 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -14,7 +14,6 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; -use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, @@ -484,73 +483,31 @@ fn or_disjoint(&mut self, a: &'ll Value, b: &'ll Value) -> &'ll Value { fn checked_binop( &mut self, oop: OverflowOp, - ty: Ty<'_>, + ty: Ty<'tcx>, lhs: Self::Value, rhs: Self::Value, ) -> (Self::Value, Self::Value) { - use rustc_middle::ty::IntTy::*; - use rustc_middle::ty::UintTy::*; - use rustc_middle::ty::{Int, Uint}; + let (size, signed) = ty.int_size_and_signed(self.tcx); + let width = size.bits(); - let new_kind = match ty.kind() { - Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), - Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), - t @ (Uint(_) | Int(_)) => *t, - _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), + if oop == OverflowOp::Sub && !signed { + // Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these + // to be the canonical form. It will attempt to reform llvm.usub.with.overflow + // in the backend if profitable. + let sub = self.sub(lhs, rhs); + let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs); + return (sub, cmp); + } + + let oop_str = match oop { + OverflowOp::Add => "add", + OverflowOp::Sub => "sub", + OverflowOp::Mul => "mul", }; - let name = match oop { - OverflowOp::Add => match new_kind { - Int(I8) => "llvm.sadd.with.overflow.i8", - Int(I16) => "llvm.sadd.with.overflow.i16", - Int(I32) => "llvm.sadd.with.overflow.i32", - Int(I64) => "llvm.sadd.with.overflow.i64", - Int(I128) => "llvm.sadd.with.overflow.i128", + let name = format!("llvm.{}{oop_str}.with.overflow", if signed { 's' } else { 'u' }); - Uint(U8) => "llvm.uadd.with.overflow.i8", - Uint(U16) => "llvm.uadd.with.overflow.i16", - Uint(U32) => "llvm.uadd.with.overflow.i32", - Uint(U64) => "llvm.uadd.with.overflow.i64", - Uint(U128) => "llvm.uadd.with.overflow.i128", - - _ => unreachable!(), - }, - OverflowOp::Sub => match new_kind { - Int(I8) => "llvm.ssub.with.overflow.i8", - Int(I16) => "llvm.ssub.with.overflow.i16", - Int(I32) => "llvm.ssub.with.overflow.i32", - Int(I64) => "llvm.ssub.with.overflow.i64", - Int(I128) => "llvm.ssub.with.overflow.i128", - - Uint(_) => { - // Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these - // to be the canonical form. It will attempt to reform llvm.usub.with.overflow - // in the backend if profitable. - let sub = self.sub(lhs, rhs); - let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs); - return (sub, cmp); - } - - _ => unreachable!(), - }, - OverflowOp::Mul => match new_kind { - Int(I8) => "llvm.smul.with.overflow.i8", - Int(I16) => "llvm.smul.with.overflow.i16", - Int(I32) => "llvm.smul.with.overflow.i32", - Int(I64) => "llvm.smul.with.overflow.i64", - Int(I128) => "llvm.smul.with.overflow.i128", - - Uint(U8) => "llvm.umul.with.overflow.i8", - Uint(U16) => "llvm.umul.with.overflow.i16", - Uint(U32) => "llvm.umul.with.overflow.i32", - Uint(U64) => "llvm.umul.with.overflow.i64", - Uint(U128) => "llvm.umul.with.overflow.i128", - - _ => unreachable!(), - }, - }; - - let res = self.call_intrinsic(name, &[lhs, rhs]); + let res = self.call_intrinsic(name, &[self.type_ix(width)], &[lhs, rhs]); (self.extract_value(res, 0), self.extract_value(res, 1)) } @@ -954,11 +911,11 @@ fn sext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { } fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.fptoint_sat(false, val, dest_ty) + self.call_intrinsic("llvm.fptoui.sat", &[dest_ty, self.val_ty(val)], &[val]) } fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.fptoint_sat(true, val, dest_ty) + self.call_intrinsic("llvm.fptosi.sat", &[dest_ty, self.val_ty(val)], &[val]) } fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { @@ -981,15 +938,12 @@ fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); - let name = match (int_width, float_width) { - (32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"), - (32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"), - (64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"), - (64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"), - _ => None, - }; - if let Some(name) = name { - return self.call_intrinsic(name, &[val]); + if matches!((int_width, float_width), (32 | 64, 32 | 64)) { + return self.call_intrinsic( + "llvm.wasm.trunc.unsigned", + &[dest_ty, src_ty], + &[val], + ); } } } @@ -1003,15 +957,12 @@ fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { if self.cx.type_kind(src_ty) != TypeKind::Vector { let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); - let name = match (int_width, float_width) { - (32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"), - (32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"), - (64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"), - (64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"), - _ => None, - }; - if let Some(name) = name { - return self.call_intrinsic(name, &[val]); + if matches!((int_width, float_width), (32 | 64, 32 | 64)) { + return self.call_intrinsic( + "llvm.wasm.trunc.signed", + &[dest_ty, src_ty], + &[val], + ); } } } @@ -1084,22 +1035,10 @@ fn three_way_compare( return None; } - let name = match (ty.is_signed(), ty.primitive_size(self.tcx).bits()) { - (true, 8) => "llvm.scmp.i8.i8", - (true, 16) => "llvm.scmp.i8.i16", - (true, 32) => "llvm.scmp.i8.i32", - (true, 64) => "llvm.scmp.i8.i64", - (true, 128) => "llvm.scmp.i8.i128", + let size = ty.primitive_size(self.tcx); + let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" }; - (false, 8) => "llvm.ucmp.i8.i8", - (false, 16) => "llvm.ucmp.i8.i16", - (false, 32) => "llvm.ucmp.i8.i32", - (false, 64) => "llvm.ucmp.i8.i64", - (false, 128) => "llvm.ucmp.i8.i128", - - _ => bug!("three-way compare unsupported for type {ty:?}"), - }; - Some(self.call_intrinsic(name, &[lhs, rhs])) + Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs])) } /* Miscellaneous instructions */ @@ -1385,11 +1324,11 @@ fn set_invariant_load(&mut self, load: &'ll Value) { } fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size); + self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size); } fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size); + self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size); } fn call( @@ -1454,7 +1393,8 @@ fn get_static(&mut self, def_id: DefId) -> &'ll Value { // Forward to the `get_static` method of `CodegenCx` let global = self.cx().get_static(def_id); if self.cx().tcx.is_thread_local_static(def_id) { - let pointer = self.call_intrinsic("llvm.threadlocal.address", &[global]); + let pointer = + self.call_intrinsic("llvm.threadlocal.address", &[self.val_ty(global)], &[global]); // Cast to default address space if globals are in a different addrspace self.pointercast(pointer, self.type_ptr()) } else { @@ -1649,12 +1589,17 @@ pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { - pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { - let (ty, f) = self.cx.get_intrinsic(intrinsic); + pub(crate) fn call_intrinsic( + &mut self, + base_name: impl Into<Cow<'static, str>>, + type_params: &[&'ll Type], + args: &[&'ll Value], + ) -> &'ll Value { + let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params); self.call(ty, None, None, f, args, None, None) } - fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) { + fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) { let size = size.bytes(); if size == 0 { return; @@ -1664,7 +1609,7 @@ fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Si return; } - self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]); + self.call_intrinsic(intrinsic, &[self.val_ty(ptr)], &[self.cx.const_u64(size), ptr]); } } impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { @@ -1689,31 +1634,6 @@ fn add_incoming_to_phi(&mut self, phi: &'ll Value, val: &'ll Value, bb: &'ll Bas } } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { - fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - let src_ty = self.cx.val_ty(val); - let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector { - assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty)); - ( - self.cx.element_type(src_ty), - self.cx.element_type(dest_ty), - Some(self.cx.vector_length(src_ty)), - ) - } else { - (src_ty, dest_ty, None) - }; - let float_width = self.cx.float_width(float_ty); - let int_width = self.cx.int_width(int_ty); - - let instr = if signed { "fptosi" } else { "fptoui" }; - let name = if let Some(vector_length) = vector_length { - format!("llvm.{instr}.sat.v{vector_length}i{int_width}.v{vector_length}f{float_width}") - } else { - format!("llvm.{instr}.sat.i{int_width}.f{float_width}") - }; - let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty)); - self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None) - } - pub(crate) fn landing_pad( &mut self, ty: &'ll Type, @@ -1819,7 +1739,7 @@ fn cfi_type_test( // llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces // calls to this intrinsic with code to test type membership. let typeid = self.get_metadata_value(typeid_metadata); - let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]); + let cond = self.call_intrinsic("llvm.type.test", &[], &[llfn, typeid]); let bb_pass = self.append_sibling_block("type_test.pass"); let bb_fail = self.append_sibling_block("type_test.fail"); self.cond_br(cond, bb_pass, bb_fail); @@ -1887,7 +1807,7 @@ pub(crate) fn instrprof_increment( num_counters: &'ll Value, index: &'ll Value, ) { - self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]); + self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]); } /// Emits a call to `llvm.instrprof.mcdc.parameters`. @@ -1906,7 +1826,7 @@ pub(crate) fn mcdc_parameters( hash: &'ll Value, bitmap_bits: &'ll Value, ) { - self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]); + self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]); } #[instrument(level = "debug", skip(self))] @@ -1918,7 +1838,7 @@ pub(crate) fn mcdc_tvbitmap_update( mcdc_temp: &'ll Value, ) { let args = &[fn_name, hash, bitmap_index, mcdc_temp]; - self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args); + self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args); } #[instrument(level = "debug", skip(self))]
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8d6e1d8..bff95ea 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1,4 +1,4 @@ -use std::borrow::Borrow; +use std::borrow::{Borrow, Cow}; use std::cell::{Cell, RefCell}; use std::ffi::{CStr, c_char, c_uint}; use std::marker::PhantomData; @@ -137,7 +137,8 @@ pub(crate) struct FullCx<'ll, 'tcx> { eh_catch_typeinfo: Cell<Option<&'ll Value>>, pub rust_try_fn: Cell<Option<(&'ll Type, &'ll Value)>>, - intrinsics: RefCell<FxHashMap<&'static str, (&'ll Type, &'ll Value)>>, + intrinsics: + RefCell<FxHashMap<(Cow<'static, str>, SmallVec<[&'ll Type; 2]>), (&'ll Type, &'ll Value)>>, /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell<usize>, @@ -842,410 +843,41 @@ fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> { } impl<'ll> CodegenCx<'ll, '_> { - pub(crate) fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) { - if let Some(v) = self.intrinsics.borrow().get(key).cloned() { - return v; - } - - self.declare_intrinsic(key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key)) - } - - fn insert_intrinsic( + pub(crate) fn get_intrinsic( &self, - name: &'static str, - args: Option<&[&'ll llvm::Type]>, - ret: &'ll llvm::Type, - ) -> (&'ll llvm::Type, &'ll llvm::Value) { - let fn_ty = if let Some(args) = args { - self.type_func(args, ret) - } else { - self.type_variadic_func(&[], ret) - }; - let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty); - self.intrinsics.borrow_mut().insert(name, (fn_ty, f)); - (fn_ty, f) + base_name: Cow<'static, str>, + type_params: &[&'ll Type], + ) -> (&'ll Type, &'ll Value) { + *self + .intrinsics + .borrow_mut() + .entry((base_name, SmallVec::from_slice(type_params))) + .or_insert_with_key(|(base_name, type_params)| { + self.declare_intrinsic(base_name, type_params) + }) } - fn declare_intrinsic(&self, key: &str) -> Option<(&'ll Type, &'ll Value)> { - macro_rules! ifn { - ($name:expr, fn() -> $ret:expr) => ( - if key == $name { - return Some(self.insert_intrinsic($name, Some(&[]), $ret)); - } - ); - ($name:expr, fn(...) -> $ret:expr) => ( - if key == $name { - return Some(self.insert_intrinsic($name, None, $ret)); - } - ); - ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( - if key == $name { - return Some(self.insert_intrinsic($name, Some(&[$($arg),*]), $ret)); - } - ); - } - macro_rules! mk_struct { - ($($field_ty:expr),*) => (self.type_struct( &[$($field_ty),*], false)) - } - - let ptr = self.type_ptr(); - let void = self.type_void(); - let i1 = self.type_i1(); - let t_i8 = self.type_i8(); - let t_i16 = self.type_i16(); - let t_i32 = self.type_i32(); - let t_i64 = self.type_i64(); - let t_i128 = self.type_i128(); - let t_isize = self.type_isize(); - let t_f16 = self.type_f16(); - let t_f32 = self.type_f32(); - let t_f64 = self.type_f64(); - let t_f128 = self.type_f128(); - let t_metadata = self.type_metadata(); - let t_token = self.type_token(); - - ifn!("llvm.wasm.get.exception", fn(t_token) -> ptr); - ifn!("llvm.wasm.get.ehselector", fn(t_token) -> t_i32); - - ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.wasm.trunc.unsigned.i64.f64", fn(t_f64) -> t_i64); - ifn!("llvm.wasm.trunc.signed.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.wasm.trunc.signed.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64); - - ifn!("llvm.fptosi.sat.i8.f32", fn(t_f32) -> t_i8); - ifn!("llvm.fptosi.sat.i16.f32", fn(t_f32) -> t_i16); - ifn!("llvm.fptosi.sat.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.fptosi.sat.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.fptosi.sat.i128.f32", fn(t_f32) -> t_i128); - ifn!("llvm.fptosi.sat.i8.f64", fn(t_f64) -> t_i8); - ifn!("llvm.fptosi.sat.i16.f64", fn(t_f64) -> t_i16); - ifn!("llvm.fptosi.sat.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.fptosi.sat.i64.f64", fn(t_f64) -> t_i64); - ifn!("llvm.fptosi.sat.i128.f64", fn(t_f64) -> t_i128); - - ifn!("llvm.fptoui.sat.i8.f32", fn(t_f32) -> t_i8); - ifn!("llvm.fptoui.sat.i16.f32", fn(t_f32) -> t_i16); - ifn!("llvm.fptoui.sat.i32.f32", fn(t_f32) -> t_i32); - ifn!("llvm.fptoui.sat.i64.f32", fn(t_f32) -> t_i64); - ifn!("llvm.fptoui.sat.i128.f32", fn(t_f32) -> t_i128); - ifn!("llvm.fptoui.sat.i8.f64", fn(t_f64) -> t_i8); - ifn!("llvm.fptoui.sat.i16.f64", fn(t_f64) -> t_i16); - ifn!("llvm.fptoui.sat.i32.f64", fn(t_f64) -> t_i32); - ifn!("llvm.fptoui.sat.i64.f64", fn(t_f64) -> t_i64); - ifn!("llvm.fptoui.sat.i128.f64", fn(t_f64) -> t_i128); - - ifn!("llvm.trap", fn() -> void); - ifn!("llvm.debugtrap", fn() -> void); - ifn!("llvm.frameaddress", fn(t_i32) -> ptr); - - ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16); - ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32); - ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64); - ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128); - - ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.pow.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.sqrt.f16", fn(t_f16) -> t_f16); - ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); - ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); - ifn!("llvm.sqrt.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.sin.f16", fn(t_f16) -> t_f16); - ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); - ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); - ifn!("llvm.sin.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.cos.f16", fn(t_f16) -> t_f16); - ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); - ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); - ifn!("llvm.cos.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.exp.f16", fn(t_f16) -> t_f16); - ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); - ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); - ifn!("llvm.exp.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.exp2.f16", fn(t_f16) -> t_f16); - ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); - ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); - ifn!("llvm.exp2.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.log.f16", fn(t_f16) -> t_f16); - ifn!("llvm.log.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.log10.f16", fn(t_f16) -> t_f16); - ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log10.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.log2.f16", fn(t_f16) -> t_f16); - ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log2.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.fma.f16", fn(t_f16, t_f16, t_f16) -> t_f16); - ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); - ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); - ifn!("llvm.fma.f128", fn(t_f128, t_f128, t_f128) -> t_f128); - - ifn!("llvm.fmuladd.f16", fn(t_f16, t_f16, t_f16) -> t_f16); - ifn!("llvm.fmuladd.f32", fn(t_f32, t_f32, t_f32) -> t_f32); - ifn!("llvm.fmuladd.f64", fn(t_f64, t_f64, t_f64) -> t_f64); - ifn!("llvm.fmuladd.f128", fn(t_f128, t_f128, t_f128) -> t_f128); - - ifn!("llvm.fabs.f16", fn(t_f16) -> t_f16); - ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); - ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); - ifn!("llvm.fabs.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.minnum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.minimum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64); - // There are issues on x86_64 and aarch64 with the f128 variant. - // - https://github.com/llvm/llvm-project/issues/139380 - // - https://github.com/llvm/llvm-project/issues/139381 - // ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64); - // There are issues on x86_64 and aarch64 with the f128 variant. - // - https://github.com/llvm/llvm-project/issues/139380 - // - https://github.com/llvm/llvm-project/issues/139381 - // ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.floor.f16", fn(t_f16) -> t_f16); - ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); - ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); - ifn!("llvm.floor.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.ceil.f16", fn(t_f16) -> t_f16); - ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); - ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); - ifn!("llvm.ceil.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.trunc.f16", fn(t_f16) -> t_f16); - ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); - ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); - ifn!("llvm.trunc.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.copysign.f16", fn(t_f16, t_f16) -> t_f16); - ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.copysign.f128", fn(t_f128, t_f128) -> t_f128); - - ifn!("llvm.round.f16", fn(t_f16) -> t_f16); - ifn!("llvm.round.f32", fn(t_f32) -> t_f32); - ifn!("llvm.round.f64", fn(t_f64) -> t_f64); - ifn!("llvm.round.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.roundeven.f16", fn(t_f16) -> t_f16); - ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32); - ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64); - ifn!("llvm.roundeven.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.rint.f16", fn(t_f16) -> t_f16); - ifn!("llvm.rint.f32", fn(t_f32) -> t_f32); - ifn!("llvm.rint.f64", fn(t_f64) -> t_f64); - ifn!("llvm.rint.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.nearbyint.f16", fn(t_f16) -> t_f16); - ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32); - ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64); - ifn!("llvm.nearbyint.f128", fn(t_f128) -> t_f128); - - ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8); - ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); - ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); - ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); - ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.ctlz.i8", fn(t_i8, i1) -> t_i8); - ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); - ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); - ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); - ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); - - ifn!("llvm.cttz.i8", fn(t_i8, i1) -> t_i8); - ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); - ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); - ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); - ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); - - ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); - ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); - ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); - ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); - ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); - ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); - ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); - ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.fshl.i8", fn(t_i8, t_i8, t_i8) -> t_i8); - ifn!("llvm.fshl.i16", fn(t_i16, t_i16, t_i16) -> t_i16); - ifn!("llvm.fshl.i32", fn(t_i32, t_i32, t_i32) -> t_i32); - ifn!("llvm.fshl.i64", fn(t_i64, t_i64, t_i64) -> t_i64); - ifn!("llvm.fshl.i128", fn(t_i128, t_i128, t_i128) -> t_i128); - - ifn!("llvm.fshr.i8", fn(t_i8, t_i8, t_i8) -> t_i8); - ifn!("llvm.fshr.i16", fn(t_i16, t_i16, t_i16) -> t_i16); - ifn!("llvm.fshr.i32", fn(t_i32, t_i32, t_i32) -> t_i32); - ifn!("llvm.fshr.i64", fn(t_i64, t_i64, t_i64) -> t_i64); - ifn!("llvm.fshr.i128", fn(t_i128, t_i128, t_i128) -> t_i128); - - ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); - ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); - ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); - ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); - ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); - - ifn!("llvm.sadd.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.sadd.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.sadd.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.sadd.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.sadd.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.uadd.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.uadd.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.uadd.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.uadd.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.uadd.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.ssub.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.ssub.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.ssub.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.ssub.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.ssub.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.usub.sat.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.usub.sat.i16", fn(t_i16, t_i16) -> t_i16); - ifn!("llvm.usub.sat.i32", fn(t_i32, t_i32) -> t_i32); - ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64); - ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128); - - ifn!("llvm.scmp.i8.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.scmp.i8.i16", fn(t_i16, t_i16) -> t_i8); - ifn!("llvm.scmp.i8.i32", fn(t_i32, t_i32) -> t_i8); - ifn!("llvm.scmp.i8.i64", fn(t_i64, t_i64) -> t_i8); - ifn!("llvm.scmp.i8.i128", fn(t_i128, t_i128) -> t_i8); - - ifn!("llvm.ucmp.i8.i8", fn(t_i8, t_i8) -> t_i8); - ifn!("llvm.ucmp.i8.i16", fn(t_i16, t_i16) -> t_i8); - ifn!("llvm.ucmp.i8.i32", fn(t_i32, t_i32) -> t_i8); - ifn!("llvm.ucmp.i8.i64", fn(t_i64, t_i64) -> t_i8); - ifn!("llvm.ucmp.i8.i128", fn(t_i128, t_i128) -> t_i8); - - ifn!("llvm.lifetime.start.p0i8", fn(t_i64, ptr) -> void); - ifn!("llvm.lifetime.end.p0i8", fn(t_i64, ptr) -> void); - - // FIXME: This is an infinitesimally small portion of the types you can - // pass to this intrinsic, if we can ever lazily register intrinsics we - // should register these when they're used, that way any type can be - // passed. - ifn!("llvm.is.constant.i1", fn(i1) -> i1); - ifn!("llvm.is.constant.i8", fn(t_i8) -> i1); - ifn!("llvm.is.constant.i16", fn(t_i16) -> i1); - ifn!("llvm.is.constant.i32", fn(t_i32) -> i1); - ifn!("llvm.is.constant.i64", fn(t_i64) -> i1); - ifn!("llvm.is.constant.i128", fn(t_i128) -> i1); - ifn!("llvm.is.constant.isize", fn(t_isize) -> i1); - ifn!("llvm.is.constant.f16", fn(t_f16) -> i1); - ifn!("llvm.is.constant.f32", fn(t_f32) -> i1); - ifn!("llvm.is.constant.f64", fn(t_f64) -> i1); - ifn!("llvm.is.constant.f128", fn(t_f128) -> i1); - ifn!("llvm.is.constant.ptr", fn(ptr) -> i1); - - ifn!("llvm.expect.i1", fn(i1, i1) -> i1); - ifn!("llvm.eh.typeid.for", fn(ptr) -> t_i32); - ifn!("llvm.localescape", fn(...) -> void); - ifn!("llvm.localrecover", fn(ptr, ptr, t_i32) -> ptr); - ifn!("llvm.x86.seh.recoverfp", fn(ptr, ptr) -> ptr); - - ifn!("llvm.assume", fn(i1) -> void); - ifn!("llvm.prefetch", fn(ptr, t_i32, t_i32, t_i32) -> void); - + fn declare_intrinsic( + &self, + base_name: &str, + type_params: &[&'ll Type], + ) -> (&'ll Type, &'ll Value) { // This isn't an "LLVM intrinsic", but LLVM's optimization passes // recognize it like one (including turning it into `bcmp` sometimes) // and we use it to implement intrinsics like `raw_eq` and `compare_bytes` - match self.sess().target.arch.as_ref() { - "avr" | "msp430" => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i16), - _ => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i32), + if base_name == "memcmp" { + let fn_ty = self + .type_func(&[self.type_ptr(), self.type_ptr(), self.type_isize()], self.type_int()); + let f = self.declare_cfn("memcmp", llvm::UnnamedAddr::No, fn_ty); + + return (fn_ty, f); } - // variadic intrinsics - ifn!("llvm.va_start", fn(ptr) -> void); - ifn!("llvm.va_end", fn(ptr) -> void); - ifn!("llvm.va_copy", fn(ptr, ptr) -> void); + let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes()) + .unwrap_or_else(|| bug!("Unknown intrinsic: `{base_name}`")); + let f = intrinsic.get_declaration(self.llmod, &type_params); - if self.sess().instrument_coverage() { - ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void); - ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void); - ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void); - } - - ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1); - ifn!("llvm.type.checked.load", fn(ptr, t_i32, t_metadata) -> mk_struct! {ptr, i1}); - - if self.sess().opts.debuginfo != DebugInfo::None { - ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void); - ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void); - } - - ifn!("llvm.ptrmask", fn(ptr, t_isize) -> ptr); - ifn!("llvm.threadlocal.address", fn(ptr) -> ptr); - - None + (self.get_type_of_global(f), f) } pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value {
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index eaafc68..8bc74fb 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> { pub rust_feature: PossibleFeature<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_llvm_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_llvm_forbidden_ctarget_feature)] -#[note] -#[note(codegen_llvm_forbidden_ctarget_feature_issue)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - #[derive(Subdiagnostic)] pub(crate) enum PossibleFeature<'a> { #[help(codegen_llvm_possible_feature)]
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 10697b9..f7f0628 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -15,7 +15,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::spec::{HasTargetSpec, PanicStrategy}; +use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::abi::FnAbiLlvmExt; @@ -27,137 +27,140 @@ use crate::va_arg::emit_va_arg; use crate::value::Value; -fn get_simple_intrinsic<'ll>( - cx: &CodegenCx<'ll, '_>, +fn call_simple_intrinsic<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, name: Symbol, -) -> Option<(&'ll Type, &'ll Value)> { - let llvm_name = match name { - sym::sqrtf16 => "llvm.sqrt.f16", - sym::sqrtf32 => "llvm.sqrt.f32", - sym::sqrtf64 => "llvm.sqrt.f64", - sym::sqrtf128 => "llvm.sqrt.f128", + args: &[OperandRef<'tcx, &'ll Value>], +) -> Option<&'ll Value> { + let (base_name, type_params): (&'static str, &[&'ll Type]) = match name { + sym::sqrtf16 => ("llvm.sqrt", &[bx.type_f16()]), + sym::sqrtf32 => ("llvm.sqrt", &[bx.type_f32()]), + sym::sqrtf64 => ("llvm.sqrt", &[bx.type_f64()]), + sym::sqrtf128 => ("llvm.sqrt", &[bx.type_f128()]), - sym::powif16 => "llvm.powi.f16.i32", - sym::powif32 => "llvm.powi.f32.i32", - sym::powif64 => "llvm.powi.f64.i32", - sym::powif128 => "llvm.powi.f128.i32", + sym::powif16 => ("llvm.powi", &[bx.type_f16(), bx.type_i32()]), + sym::powif32 => ("llvm.powi", &[bx.type_f32(), bx.type_i32()]), + sym::powif64 => ("llvm.powi", &[bx.type_f64(), bx.type_i32()]), + sym::powif128 => ("llvm.powi", &[bx.type_f128(), bx.type_i32()]), - sym::sinf16 => "llvm.sin.f16", - sym::sinf32 => "llvm.sin.f32", - sym::sinf64 => "llvm.sin.f64", - sym::sinf128 => "llvm.sin.f128", + sym::sinf16 => ("llvm.sin", &[bx.type_f16()]), + sym::sinf32 => ("llvm.sin", &[bx.type_f32()]), + sym::sinf64 => ("llvm.sin", &[bx.type_f64()]), + sym::sinf128 => ("llvm.sin", &[bx.type_f128()]), - sym::cosf16 => "llvm.cos.f16", - sym::cosf32 => "llvm.cos.f32", - sym::cosf64 => "llvm.cos.f64", - sym::cosf128 => "llvm.cos.f128", + sym::cosf16 => ("llvm.cos", &[bx.type_f16()]), + sym::cosf32 => ("llvm.cos", &[bx.type_f32()]), + sym::cosf64 => ("llvm.cos", &[bx.type_f64()]), + sym::cosf128 => ("llvm.cos", &[bx.type_f128()]), - sym::powf16 => "llvm.pow.f16", - sym::powf32 => "llvm.pow.f32", - sym::powf64 => "llvm.pow.f64", - sym::powf128 => "llvm.pow.f128", + sym::powf16 => ("llvm.pow", &[bx.type_f16()]), + sym::powf32 => ("llvm.pow", &[bx.type_f32()]), + sym::powf64 => ("llvm.pow", &[bx.type_f64()]), + sym::powf128 => ("llvm.pow", &[bx.type_f128()]), - sym::expf16 => "llvm.exp.f16", - sym::expf32 => "llvm.exp.f32", - sym::expf64 => "llvm.exp.f64", - sym::expf128 => "llvm.exp.f128", + sym::expf16 => ("llvm.exp", &[bx.type_f16()]), + sym::expf32 => ("llvm.exp", &[bx.type_f32()]), + sym::expf64 => ("llvm.exp", &[bx.type_f64()]), + sym::expf128 => ("llvm.exp", &[bx.type_f128()]), - sym::exp2f16 => "llvm.exp2.f16", - sym::exp2f32 => "llvm.exp2.f32", - sym::exp2f64 => "llvm.exp2.f64", - sym::exp2f128 => "llvm.exp2.f128", + sym::exp2f16 => ("llvm.exp2", &[bx.type_f16()]), + sym::exp2f32 => ("llvm.exp2", &[bx.type_f32()]), + sym::exp2f64 => ("llvm.exp2", &[bx.type_f64()]), + sym::exp2f128 => ("llvm.exp2", &[bx.type_f128()]), - sym::logf16 => "llvm.log.f16", - sym::logf32 => "llvm.log.f32", - sym::logf64 => "llvm.log.f64", - sym::logf128 => "llvm.log.f128", + sym::logf16 => ("llvm.log", &[bx.type_f16()]), + sym::logf32 => ("llvm.log", &[bx.type_f32()]), + sym::logf64 => ("llvm.log", &[bx.type_f64()]), + sym::logf128 => ("llvm.log", &[bx.type_f128()]), - sym::log10f16 => "llvm.log10.f16", - sym::log10f32 => "llvm.log10.f32", - sym::log10f64 => "llvm.log10.f64", - sym::log10f128 => "llvm.log10.f128", + sym::log10f16 => ("llvm.log10", &[bx.type_f16()]), + sym::log10f32 => ("llvm.log10", &[bx.type_f32()]), + sym::log10f64 => ("llvm.log10", &[bx.type_f64()]), + sym::log10f128 => ("llvm.log10", &[bx.type_f128()]), - sym::log2f16 => "llvm.log2.f16", - sym::log2f32 => "llvm.log2.f32", - sym::log2f64 => "llvm.log2.f64", - sym::log2f128 => "llvm.log2.f128", + sym::log2f16 => ("llvm.log2", &[bx.type_f16()]), + sym::log2f32 => ("llvm.log2", &[bx.type_f32()]), + sym::log2f64 => ("llvm.log2", &[bx.type_f64()]), + sym::log2f128 => ("llvm.log2", &[bx.type_f128()]), - sym::fmaf16 => "llvm.fma.f16", - sym::fmaf32 => "llvm.fma.f32", - sym::fmaf64 => "llvm.fma.f64", - sym::fmaf128 => "llvm.fma.f128", + sym::fmaf16 => ("llvm.fma", &[bx.type_f16()]), + sym::fmaf32 => ("llvm.fma", &[bx.type_f32()]), + sym::fmaf64 => ("llvm.fma", &[bx.type_f64()]), + sym::fmaf128 => ("llvm.fma", &[bx.type_f128()]), - sym::fmuladdf16 => "llvm.fmuladd.f16", - sym::fmuladdf32 => "llvm.fmuladd.f32", - sym::fmuladdf64 => "llvm.fmuladd.f64", - sym::fmuladdf128 => "llvm.fmuladd.f128", + sym::fmuladdf16 => ("llvm.fmuladd", &[bx.type_f16()]), + sym::fmuladdf32 => ("llvm.fmuladd", &[bx.type_f32()]), + sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]), + sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]), - sym::fabsf16 => "llvm.fabs.f16", - sym::fabsf32 => "llvm.fabs.f32", - sym::fabsf64 => "llvm.fabs.f64", - sym::fabsf128 => "llvm.fabs.f128", + sym::fabsf16 => ("llvm.fabs", &[bx.type_f16()]), + sym::fabsf32 => ("llvm.fabs", &[bx.type_f32()]), + sym::fabsf64 => ("llvm.fabs", &[bx.type_f64()]), + sym::fabsf128 => ("llvm.fabs", &[bx.type_f128()]), - sym::minnumf16 => "llvm.minnum.f16", - sym::minnumf32 => "llvm.minnum.f32", - sym::minnumf64 => "llvm.minnum.f64", - sym::minnumf128 => "llvm.minnum.f128", + sym::minnumf16 => ("llvm.minnum", &[bx.type_f16()]), + sym::minnumf32 => ("llvm.minnum", &[bx.type_f32()]), + sym::minnumf64 => ("llvm.minnum", &[bx.type_f64()]), + sym::minnumf128 => ("llvm.minnum", &[bx.type_f128()]), - sym::minimumf16 => "llvm.minimum.f16", - sym::minimumf32 => "llvm.minimum.f32", - sym::minimumf64 => "llvm.minimum.f64", + sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), + sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), + sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, // let's instead use the instrinsic fallback body. - // sym::minimumf128 => "llvm.minimum.f128", - sym::maxnumf16 => "llvm.maxnum.f16", - sym::maxnumf32 => "llvm.maxnum.f32", - sym::maxnumf64 => "llvm.maxnum.f64", - sym::maxnumf128 => "llvm.maxnum.f128", + // sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), + sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]), + sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]), + sym::maxnumf64 => ("llvm.maxnum", &[bx.type_f64()]), + sym::maxnumf128 => ("llvm.maxnum", &[bx.type_f128()]), - sym::maximumf16 => "llvm.maximum.f16", - sym::maximumf32 => "llvm.maximum.f32", - sym::maximumf64 => "llvm.maximum.f64", + sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), + sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), + sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, // let's instead use the instrinsic fallback body. - // sym::maximumf128 => "llvm.maximum.f128", - sym::copysignf16 => "llvm.copysign.f16", - sym::copysignf32 => "llvm.copysign.f32", - sym::copysignf64 => "llvm.copysign.f64", - sym::copysignf128 => "llvm.copysign.f128", + // sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), + sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]), + sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]), + sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]), + sym::copysignf128 => ("llvm.copysign", &[bx.type_f128()]), - sym::floorf16 => "llvm.floor.f16", - sym::floorf32 => "llvm.floor.f32", - sym::floorf64 => "llvm.floor.f64", - sym::floorf128 => "llvm.floor.f128", + sym::floorf16 => ("llvm.floor", &[bx.type_f16()]), + sym::floorf32 => ("llvm.floor", &[bx.type_f32()]), + sym::floorf64 => ("llvm.floor", &[bx.type_f64()]), + sym::floorf128 => ("llvm.floor", &[bx.type_f128()]), - sym::ceilf16 => "llvm.ceil.f16", - sym::ceilf32 => "llvm.ceil.f32", - sym::ceilf64 => "llvm.ceil.f64", - sym::ceilf128 => "llvm.ceil.f128", + sym::ceilf16 => ("llvm.ceil", &[bx.type_f16()]), + sym::ceilf32 => ("llvm.ceil", &[bx.type_f32()]), + sym::ceilf64 => ("llvm.ceil", &[bx.type_f64()]), + sym::ceilf128 => ("llvm.ceil", &[bx.type_f128()]), - sym::truncf16 => "llvm.trunc.f16", - sym::truncf32 => "llvm.trunc.f32", - sym::truncf64 => "llvm.trunc.f64", - sym::truncf128 => "llvm.trunc.f128", + sym::truncf16 => ("llvm.trunc", &[bx.type_f16()]), + sym::truncf32 => ("llvm.trunc", &[bx.type_f32()]), + sym::truncf64 => ("llvm.trunc", &[bx.type_f64()]), + sym::truncf128 => ("llvm.trunc", &[bx.type_f128()]), // We could use any of `rint`, `nearbyint`, or `roundeven` // for this -- they are all identical in semantics when // assuming the default FP environment. // `rint` is what we used for $forever. - sym::round_ties_even_f16 => "llvm.rint.f16", - sym::round_ties_even_f32 => "llvm.rint.f32", - sym::round_ties_even_f64 => "llvm.rint.f64", - sym::round_ties_even_f128 => "llvm.rint.f128", + sym::round_ties_even_f16 => ("llvm.rint", &[bx.type_f16()]), + sym::round_ties_even_f32 => ("llvm.rint", &[bx.type_f32()]), + sym::round_ties_even_f64 => ("llvm.rint", &[bx.type_f64()]), + sym::round_ties_even_f128 => ("llvm.rint", &[bx.type_f128()]), - sym::roundf16 => "llvm.round.f16", - sym::roundf32 => "llvm.round.f32", - sym::roundf64 => "llvm.round.f64", - sym::roundf128 => "llvm.round.f128", - - sym::ptr_mask => "llvm.ptrmask", + sym::roundf16 => ("llvm.round", &[bx.type_f16()]), + sym::roundf32 => ("llvm.round", &[bx.type_f32()]), + sym::roundf64 => ("llvm.round", &[bx.type_f64()]), + sym::roundf128 => ("llvm.round", &[bx.type_f128()]), _ => return None, }; - Some(cx.get_intrinsic(llvm_name)) + Some(bx.call_intrinsic( + base_name, + type_params, + &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), + )) } impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { @@ -173,36 +176,24 @@ fn codegen_intrinsic_call( let name = tcx.item_name(instance.def_id()); let fn_args = instance.args; - let simple = get_simple_intrinsic(self, name); + let simple = call_simple_intrinsic(self, name, args); let llval = match name { - _ if simple.is_some() => { - let (simple_ty, simple_fn) = simple.unwrap(); - self.call( - simple_ty, - None, - None, - simple_fn, - &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), - None, - Some(instance), + _ if simple.is_some() => simple.unwrap(), + sym::ptr_mask => { + let ptr = args[0].immediate(); + self.call_intrinsic( + "llvm.ptrmask", + &[self.val_ty(ptr), self.type_isize()], + &[ptr, args[1].immediate()], ) } sym::is_val_statically_known => { - let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx); - let kind = self.type_kind(intrinsic_type); - let intrinsic_name = match kind { - TypeKind::Pointer | TypeKind::Integer => { - Some(format!("llvm.is.constant.{intrinsic_type:?}")) - } - // LLVM float types' intrinsic names differ from their type names. - TypeKind::Half => Some(format!("llvm.is.constant.f16")), - TypeKind::Float => Some(format!("llvm.is.constant.f32")), - TypeKind::Double => Some(format!("llvm.is.constant.f64")), - TypeKind::FP128 => Some(format!("llvm.is.constant.f128")), - _ => None, - }; - if let Some(intrinsic_name) = intrinsic_name { - self.call_intrinsic(&intrinsic_name, &[args[0].immediate()]) + if let OperandValue::Immediate(imm) = args[0].val { + self.call_intrinsic( + "llvm.is.constant", + &[args[0].layout.immediate_llvm_type(self.cx)], + &[imm], + ) } else { self.const_bool(false) } @@ -246,9 +237,14 @@ fn codegen_intrinsic_call( ); return Ok(()); } - sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[]), + sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]), sym::va_copy => { - self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()]) + let dest = args[0].immediate(); + self.call_intrinsic( + "llvm.va_copy", + &[self.val_ty(dest)], + &[dest, args[1].immediate()], + ) } sym::va_arg => { match result.layout.backend_repr { @@ -322,14 +318,11 @@ fn codegen_intrinsic_call( sym::prefetch_write_instruction => (1, 0), _ => bug!(), }; + let ptr = args[0].immediate(); self.call_intrinsic( "llvm.prefetch", - &[ - args[0].immediate(), - self.const_i32(rw), - args[1].immediate(), - self.const_i32(cache_type), - ], + &[self.val_ty(ptr)], + &[ptr, self.const_i32(rw), args[1].immediate(), self.const_i32(cache_type)], ) } sym::carrying_mul_add => { @@ -385,11 +378,13 @@ fn codegen_intrinsic_call( } let (size, signed) = ty.int_size_and_signed(self.tcx); let width = size.bits(); + let llty = self.type_ix(width); match name { sym::ctlz | sym::cttz => { let y = self.const_bool(false); let ret = self.call_intrinsic( - &format!("llvm.{name}.i{width}"), + format!("llvm.{name}"), + &[llty], &[args[0].immediate(), y], ); @@ -397,62 +392,54 @@ fn codegen_intrinsic_call( } sym::ctlz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.ctlz.i{width}"); - let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]); + let ret = + self.call_intrinsic("llvm.ctlz", &[llty], &[args[0].immediate(), y]); self.intcast(ret, result.layout.llvm_type(self), false) } sym::cttz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.cttz.i{width}"); - let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]); + let ret = + self.call_intrinsic("llvm.cttz", &[llty], &[args[0].immediate(), y]); self.intcast(ret, result.layout.llvm_type(self), false) } sym::ctpop => { - let ret = self.call_intrinsic( - &format!("llvm.ctpop.i{width}"), - &[args[0].immediate()], - ); + let ret = + self.call_intrinsic("llvm.ctpop", &[llty], &[args[0].immediate()]); self.intcast(ret, result.layout.llvm_type(self), false) } sym::bswap => { if width == 8 { args[0].immediate() // byte swap a u8/i8 is just a no-op } else { - self.call_intrinsic( - &format!("llvm.bswap.i{width}"), - &[args[0].immediate()], - ) + self.call_intrinsic("llvm.bswap", &[llty], &[args[0].immediate()]) } } - sym::bitreverse => self.call_intrinsic( - &format!("llvm.bitreverse.i{width}"), - &[args[0].immediate()], - ), + sym::bitreverse => { + self.call_intrinsic("llvm.bitreverse", &[llty], &[args[0].immediate()]) + } sym::rotate_left | sym::rotate_right => { let is_left = name == sym::rotate_left; let val = args[0].immediate(); let raw_shift = args[1].immediate(); // rotate = funnel shift with first two args the same - let llvm_name = - &format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width); + let llvm_name = format!("llvm.fsh{}", if is_left { 'l' } else { 'r' }); // llvm expects shift to be the same type as the values, but rust // always uses `u32`. let raw_shift = self.intcast(raw_shift, self.val_ty(val), false); - self.call_intrinsic(llvm_name, &[val, val, raw_shift]) + self.call_intrinsic(llvm_name, &[llty], &[val, val, raw_shift]) } sym::saturating_add | sym::saturating_sub => { let is_add = name == sym::saturating_add; let lhs = args[0].immediate(); let rhs = args[1].immediate(); - let llvm_name = &format!( - "llvm.{}{}.sat.i{}", + let llvm_name = format!( + "llvm.{}{}.sat", if signed { 's' } else { 'u' }, if is_add { "add" } else { "sub" }, - width ); - self.call_intrinsic(llvm_name, &[lhs, rhs]) + self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs]) } _ => bug!(), } @@ -484,11 +471,8 @@ fn codegen_intrinsic_call( self.icmp(IntPredicate::IntEQ, a_val, b_val) } else { let n = self.const_usize(layout.size().bytes()); - let cmp = self.call_intrinsic("memcmp", &[a, b, n]); - match self.cx.sess().target.arch.as_ref() { - "avr" | "msp430" => self.icmp(IntPredicate::IntEQ, cmp, self.const_i16(0)), - _ => self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)), - } + let cmp = self.call_intrinsic("memcmp", &[], &[a, b, n]); + self.icmp(IntPredicate::IntEQ, cmp, self.const_int(self.type_int(), 0)) } } @@ -496,6 +480,7 @@ fn codegen_intrinsic_call( // Here we assume that the `memcmp` provided by the target is a NOP for size 0. let cmp = self.call_intrinsic( "memcmp", + &[], &[args[0].immediate(), args[1].immediate(), args[2].immediate()], ); // Some targets have `memcmp` returning `i16`, but the intrinsic is always `i32`. @@ -619,18 +604,22 @@ fn codegen_intrinsic_call( } fn abort(&mut self) { - self.call_intrinsic("llvm.trap", &[]); + self.call_intrinsic("llvm.trap", &[], &[]); } fn assume(&mut self, val: Self::Value) { if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { - self.call_intrinsic("llvm.assume", &[val]); + self.call_intrinsic("llvm.assume", &[], &[val]); } } fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value { if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { - self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) + self.call_intrinsic( + "llvm.expect", + &[self.type_i1()], + &[cond, self.const_bool(expected)], + ) } else { cond } @@ -644,17 +633,20 @@ fn type_checked_load( ) -> Self::Value { let typeid = self.get_metadata_value(typeid); let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32); - let type_checked_load = - self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]); + let type_checked_load = self.call_intrinsic( + "llvm.type.checked.load", + &[], + &[llvtable, vtable_byte_offset, typeid], + ); self.extract_value(type_checked_load, 0) } fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.va_start", &[va_list]) + self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list]) } fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.va_end", &[va_list]) + self.call_intrinsic("llvm.va_end", &[self.val_ty(va_list)], &[va_list]) } } @@ -893,8 +885,8 @@ fn codegen_wasm_try<'ll, 'tcx>( let null = bx.const_null(bx.type_ptr()); let funclet = bx.catch_pad(cs, &[null]); - let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[funclet.cleanuppad()]); - let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[funclet.cleanuppad()]); + let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[], &[funclet.cleanuppad()]); + let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[], &[funclet.cleanuppad()]); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); @@ -1031,7 +1023,7 @@ fn codegen_emcc_try<'ll, 'tcx>( let selector = bx.extract_value(vals, 1); // Check if the typeid we got is the one for a Rust panic. - let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[tydesc]); + let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.val_ty(tydesc)], &[tydesc]); let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid); let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool()); @@ -1522,56 +1514,37 @@ macro_rules! return_error { }}; } - let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 16 => ("f16", elem_ty), - 32 => ("f32", elem_ty), - 64 => ("f64", elem_ty), - 128 => ("f128", elem_ty), - _ => return_error!(InvalidMonomorphization::FloatingPointVector { - span, - name, - f_ty: *f, - in_ty, - }), - } + let elem_ty = if let ty::Float(f) = in_elem.kind() { + bx.cx.type_float_from_ty(*f) } else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; let vec_ty = bx.type_vector(elem_ty, in_len); - let (intr_name, fn_ty) = match name { - sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), - sym::simd_relaxed_fma => ("fmuladd", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), - sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)), + let intr_name = match name { + sym::simd_ceil => "llvm.ceil", + sym::simd_fabs => "llvm.fabs", + sym::simd_fcos => "llvm.cos", + sym::simd_fexp2 => "llvm.exp2", + sym::simd_fexp => "llvm.exp", + sym::simd_flog10 => "llvm.log10", + sym::simd_flog2 => "llvm.log2", + sym::simd_flog => "llvm.log", + sym::simd_floor => "llvm.floor", + sym::simd_fma => "llvm.fma", + sym::simd_relaxed_fma => "llvm.fmuladd", + sym::simd_fsin => "llvm.sin", + sym::simd_fsqrt => "llvm.sqrt", + sym::simd_round => "llvm.round", + sym::simd_trunc => "llvm.trunc", _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; - let llvm_name = &format!("llvm.{intr_name}.v{in_len}{elem_ty_str}"); - let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty); - let c = bx.call( - fn_ty, - None, - None, - f, + Ok(bx.call_intrinsic( + intr_name, + &[vec_ty], &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), - None, - None, - ); - Ok(c) + )) } if std::matches!( @@ -1595,29 +1568,6 @@ macro_rules! return_error { return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); } - // FIXME: use: - // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 - // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 - fn llvm_vector_str(bx: &Builder<'_, '_, '_>, elem_ty: Ty<'_>, vec_len: u64) -> String { - match *elem_ty.kind() { - ty::Int(v) => format!( - "v{}i{}", - vec_len, - // Normalize to prevent crash if v: IntTy::Isize - v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() - ), - ty::Uint(v) => format!( - "v{}i{}", - vec_len, - // Normalize to prevent crash if v: UIntTy::Usize - v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() - ), - ty::Float(v) => format!("v{}f{}", vec_len, v.bit_width()), - ty::RawPtr(_, _) => format!("v{}p0", vec_len), - _ => unreachable!(), - } - } - fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -> &'ll Type { let elem_ty = match *elem_ty.kind() { ty::Int(v) => cx.type_int_from_ty(v), @@ -1698,38 +1648,22 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) - ); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32); // Truncate the mask vector to a vector of i1s: let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len); - let mask_ty = bx.type_vector(bx.type_i1(), in_len); // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len); - let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len); - let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len); - let llvm_intrinsic = - format!("llvm.masked.gather.{llvm_elem_vec_str}.{llvm_pointer_vec_str}"); - let fn_ty = bx.type_func( - &[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty], - llvm_elem_vec_ty, - ); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + return Ok(bx.call_intrinsic( + "llvm.masked.gather", + &[llvm_elem_vec_ty, llvm_pointer_vec_ty], &[args[1].immediate(), alignment, mask, args[0].immediate()], - None, - None, - ); - return Ok(v); + )); } if name == sym::simd_masked_load { @@ -1795,32 +1729,20 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) - ); let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len); - let mask_ty = bx.type_vector(bx.type_i1(), mask_len); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32); let llvm_pointer = bx.type_ptr(); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len); - let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len); - let llvm_intrinsic = format!("llvm.masked.load.{llvm_elem_vec_str}.p0"); - let fn_ty = bx - .type_func(&[llvm_pointer, alignment_ty, mask_ty, llvm_elem_vec_ty], llvm_elem_vec_ty); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + return Ok(bx.call_intrinsic( + "llvm.masked.load", + &[llvm_elem_vec_ty, llvm_pointer], &[args[1].immediate(), alignment, mask, args[2].immediate()], - None, - None, - ); - return Ok(v); + )); } if name == sym::simd_masked_store { @@ -1880,33 +1802,20 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) - ); let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len); - let mask_ty = bx.type_vector(bx.type_i1(), mask_len); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32); - let ret_t = bx.type_void(); - let llvm_pointer = bx.type_ptr(); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len); - let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len); - let llvm_intrinsic = format!("llvm.masked.store.{llvm_elem_vec_str}.p0"); - let fn_ty = bx.type_func(&[llvm_elem_vec_ty, llvm_pointer, alignment_ty, mask_ty], ret_t); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + return Ok(bx.call_intrinsic( + "llvm.masked.store", + &[llvm_elem_vec_ty, llvm_pointer], &[args[2].immediate(), args[1].immediate(), alignment, mask], - None, - None, - ); - return Ok(v); + )); } if name == sym::simd_scatter { @@ -1971,38 +1880,22 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) - ); // Alignment of T, must be a constant integer value: - let alignment_ty = bx.type_i32(); let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32); // Truncate the mask vector to a vector of i1s: let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len); - let mask_ty = bx.type_vector(bx.type_i1(), in_len); - - let ret_t = bx.type_void(); // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len); - let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len); - let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len); - let llvm_intrinsic = - format!("llvm.masked.scatter.{llvm_elem_vec_str}.{llvm_pointer_vec_str}"); - let fn_ty = - bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call( - fn_ty, - None, - None, - f, + return Ok(bx.call_intrinsic( + "llvm.masked.scatter", + &[llvm_elem_vec_ty, llvm_pointer_vec_ty], &[args[0].immediate(), args[1].immediate(), alignment, mask], - None, - None, - ); - return Ok(v); + )); } macro_rules! arith_red { @@ -2431,40 +2324,31 @@ macro_rules! arith_unary { }, in_len as u64, ); - let intrinsic_name = match name { - sym::simd_bswap => "bswap", - sym::simd_bitreverse => "bitreverse", - sym::simd_ctlz => "ctlz", - sym::simd_ctpop => "ctpop", - sym::simd_cttz => "cttz", + let llvm_intrinsic = match name { + sym::simd_bswap => "llvm.bswap", + sym::simd_bitreverse => "llvm.bitreverse", + sym::simd_ctlz => "llvm.ctlz", + sym::simd_ctpop => "llvm.ctpop", + sym::simd_cttz => "llvm.cttz", _ => unreachable!(), }; let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits(); - let llvm_intrinsic = &format!("llvm.{}.v{}i{}", intrinsic_name, in_len, int_size,); return match name { // byte swap is no-op for i8/u8 sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()), sym::simd_ctlz | sym::simd_cttz => { // for the (int, i1 immediate) pair, the second arg adds `(0, true) => poison` - let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty); let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0); - let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - Ok(bx.call( - fn_ty, - None, - None, - f, + Ok(bx.call_intrinsic( + llvm_intrinsic, + &[vec_ty], &[args[0].immediate(), dont_poison_on_zero], - None, - None, )) } sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => { // simple unary argument cases - let fn_ty = bx.type_func(&[vec_ty], vec_ty); - let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None)) + Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()])) } _ => unreachable!(), }; @@ -2495,10 +2379,9 @@ macro_rules! arith_unary { let lhs = args[0].immediate(); let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; - let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; - let (signed, elem_width, elem_ty) = match *in_elem.kind() { - ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), - ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)), + let (signed, elem_ty) = match *in_elem.kind() { + ty::Int(i) => (true, bx.cx.type_int_from_ty(i)), + ty::Uint(i) => (false, bx.cx.type_uint_from_ty(i)), _ => { return_error!(InvalidMonomorphization::ExpectedVectorElementType { span, @@ -2508,19 +2391,14 @@ macro_rules! arith_unary { }); } }; - let llvm_intrinsic = &format!( - "llvm.{}{}.sat.v{}i{}", + let llvm_intrinsic = format!( + "llvm.{}{}.sat", if signed { 's' } else { 'u' }, if is_add { "add" } else { "sub" }, - in_len, - elem_width ); let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64); - let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty); - let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None, None); - return Ok(v); + return Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[lhs, rhs])); } span_bug!(span, "unknown SIMD intrinsic");
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 6890923..cdfffbe 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -340,18 +340,11 @@ fn target_config(&self, sess: &Session) -> TargetConfig { target_config(sess) } - fn codegen_crate<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: EncodedMetadata, - need_metadata_module: bool, - ) -> Box<dyn Any> { + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> { Box::new(rustc_codegen_ssa::base::codegen_crate( LlvmCodegenBackend(()), tcx, crate::llvm_util::target_cpu(tcx.sess).to_string(), - metadata, - need_metadata_module, )) } @@ -376,14 +369,20 @@ fn join_codegen( (codegen_results, work_products) } - fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) { + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + metadata: EncodedMetadata, + outputs: &OutputFilenames, + ) { use rustc_codegen_ssa::back::link::link_binary; use crate::back::archive::LlvmArchiveBuilderBuilder; // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs); + link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs); } }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e27fbf9..91ada85 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -15,6 +15,7 @@ use std::fmt::Debug; use std::marker::PhantomData; +use std::num::NonZero; use std::ptr; use bitflags::bitflags; @@ -1077,8 +1078,6 @@ pub(crate) fn LLVMStructTypeInContext<'a>( // Operations on other types pub(crate) fn LLVMVoidTypeInContext(C: &Context) -> &Type; - pub(crate) fn LLVMTokenTypeInContext(C: &Context) -> &Type; - pub(crate) fn LLVMMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values pub(crate) fn LLVMTypeOf(Val: &Value) -> &Type; @@ -1195,6 +1194,15 @@ pub(crate) fn LLVMCreateStringAttribute( // Operations on functions pub(crate) fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint); + // Operations about llvm intrinsics + pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint; + pub(crate) fn LLVMGetIntrinsicDeclaration<'a>( + Mod: &'a Module, + ID: NonZero<c_uint>, + ParamTypes: *const &'a Type, + ParamCount: size_t, + ) -> &'a Value; + // Operations on parameters pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; pub(crate) safe fn LLVMCountParams(Fn: &Value) -> c_uint;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index ed23f91..661174a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -1,6 +1,7 @@ #![allow(non_snake_case)] use std::ffi::{CStr, CString}; +use std::num::NonZero; use std::ptr; use std::str::FromStr; use std::string::FromUtf8Error; @@ -327,6 +328,28 @@ pub(crate) fn get_value_name(value: &Value) -> &[u8] { } } +#[derive(Debug, Copy, Clone)] +pub(crate) struct Intrinsic { + id: NonZero<c_uint>, +} + +impl Intrinsic { + pub(crate) fn lookup(name: &[u8]) -> Option<Self> { + let id = unsafe { LLVMLookupIntrinsicID(name.as_c_char_ptr(), name.len()) }; + NonZero::new(id).map(|id| Self { id }) + } + + pub(crate) fn get_declaration<'ll>( + self, + llmod: &'ll Module, + type_params: &[&'ll Type], + ) -> &'ll Value { + unsafe { + LLVMGetIntrinsicDeclaration(llmod, self.id, type_params.as_ptr(), type_params.len()) + } + } +} + /// Safe wrapper for `LLVMSetValueName2` from a byte slice pub(crate) fn set_value_name(value: &Value, name: &[u8]) { unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9718c95f..0e77bc4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -16,6 +16,7 @@ use rustc_middle::bug; use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; +use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_span::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; @@ -23,8 +24,7 @@ use crate::back::write::create_informational_target_machine; use crate::errors::{ - FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, - UnknownCTargetFeaturePrefix, UnstableCTargetFeature, + FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, }; use crate::llvm; @@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str { handle_native(cpu_name) } +fn llvm_features_by_flags(sess: &Session) -> Vec<&str> { + let mut features: Vec<&str> = Vec::new(); + retpoline_features_by_flags(sess, &mut features); + features +} + /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). pub(crate) fn global_llvm_features( @@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features( // Compute implied features let mut all_rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',') { + for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) { if let Some(feature) = feature.strip_prefix('+') { all_rust_features.extend( UnordSet::from(sess.target.implied_target_features(feature)) @@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features( sess.dcx().emit_warn(unknown_feature); } Some((_, stability, _)) => { - if let Err(reason) = stability.toggle_allowed() { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. It makes little sense - // to hard-error here since we just warn about fully unknown - // features above. - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } + stability.verify_feature_enabled_by_flag(sess, enable, feature); } }
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 169036f..453eca2 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -1,4 +1,5 @@ use std::borrow::Borrow; +use std::hash::{Hash, Hasher}; use std::{fmt, ptr}; use libc::{c_char, c_uint}; @@ -25,6 +26,14 @@ fn eq(&self, other: &Self) -> bool { } } +impl Eq for Type {} + +impl Hash for Type { + fn hash<H: Hasher>(&self, state: &mut H) { + ptr::hash(self, state); + } +} + impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str( @@ -49,13 +58,6 @@ pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: b pub(crate) fn type_void(&self) -> &'ll Type { unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } } - pub(crate) fn type_token(&self) -> &'ll Type { - unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) } - } - - pub(crate) fn type_metadata(&self) -> &'ll Type { - unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) } - } ///x Creates an integer type with the given number of bits, e.g., i24 pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type {
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 91f6af7..5322fe5 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -198,8 +198,6 @@ codegen_ssa_malformed_cgu_name = found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). -codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error} - codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload codegen_ssa_missing_features = add the missing features in a `target_feature` attribute
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 1e1bdfb..84a56f6 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -14,11 +14,12 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_fs_util::TempDirBuilder; +use rustc_metadata::EncodedMetadata; use rustc_session::Session; use rustc_span::Symbol; use tracing::trace; -use super::metadata::search_for_section; +use super::metadata::{create_compressed_metadata_file, search_for_section}; use crate::common; // Re-exporting for rustc_codegen_llvm::back::archive pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind}; @@ -58,6 +59,15 @@ fn from(item: ImportLibraryItem) -> Self { pub trait ArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>; + fn create_dylib_metadata_wrapper( + &self, + sess: &Session, + metadata: &EncodedMetadata, + symbol_name: &str, + ) -> Vec<u8> { + create_compressed_metadata_file(sess, metadata, symbol_name) + } + /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>. /// and returns the path on disk to that import library. /// This functions doesn't take `self` so that it can be called from
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1680772..8c52ed6 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -23,7 +23,8 @@ use rustc_macros::LintDiagnostic; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; use rustc_metadata::{ - NativeLibSearchFallback, find_native_static_library, walk_native_lib_search_dirs, + EncodedMetadata, NativeLibSearchFallback, find_native_static_library, + walk_native_lib_search_dirs, }; use rustc_middle::bug; use rustc_middle::lint::lint_level; @@ -91,6 +92,7 @@ pub fn link_binary( sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: CodegenResults, + metadata: EncodedMetadata, outputs: &OutputFilenames, ) { let _timer = sess.timer("link_binary"); @@ -142,6 +144,7 @@ pub fn link_binary( sess, archive_builder_builder, &codegen_results, + &metadata, RlibFlavor::Normal, &path, ) @@ -152,6 +155,7 @@ pub fn link_binary( sess, archive_builder_builder, &codegen_results, + &metadata, &out_filename, &path, ); @@ -163,6 +167,7 @@ pub fn link_binary( crate_type, &out_filename, &codegen_results, + &metadata, path.as_ref(), ); } @@ -226,11 +231,7 @@ pub fn link_binary( let remove_temps_from_module = |module: &CompiledModule| maybe_remove_temps_from_module(false, false, module); - // Otherwise, always remove the metadata and allocator module temporaries. - if let Some(ref metadata_module) = codegen_results.metadata_module { - remove_temps_from_module(metadata_module); - } - + // Otherwise, always remove the allocator module temporaries. if let Some(ref allocator_module) = codegen_results.allocator_module { remove_temps_from_module(allocator_module); } @@ -312,6 +313,7 @@ fn link_rlib<'a>( sess: &'a Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, flavor: RlibFlavor, tmpdir: &MaybeTempDir, ) -> Box<dyn ArchiveBuilder + 'a> { @@ -319,12 +321,9 @@ fn link_rlib<'a>( let trailing_metadata = match flavor { RlibFlavor::Normal => { - let (metadata, metadata_position) = create_wrapper_file( - sess, - ".rmeta".to_string(), - codegen_results.metadata.stub_or_full(), - ); - let metadata = emit_wrapper_file(sess, &metadata, tmpdir, METADATA_FILENAME); + let (metadata, metadata_position) = + create_wrapper_file(sess, ".rmeta".to_string(), metadata.stub_or_full()); + let metadata = emit_wrapper_file(sess, &metadata, tmpdir.as_ref(), METADATA_FILENAME); match metadata_position { MetadataPosition::First => { // Most of the time metadata in rlib files is wrapped in a "dummy" object @@ -392,7 +391,7 @@ fn link_rlib<'a>( let src = read(path) .unwrap_or_else(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e })); let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src); - let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str()); + let wrapper_file = emit_wrapper_file(sess, &data, tmpdir.as_ref(), filename.as_str()); packed_bundled_libs.push(wrapper_file); } else { let path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess); @@ -473,6 +472,7 @@ fn link_staticlib( sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, out_filename: &Path, tempdir: &MaybeTempDir, ) { @@ -481,6 +481,7 @@ fn link_staticlib( sess, archive_builder_builder, codegen_results, + metadata, RlibFlavor::StaticlibBase, tempdir, ); @@ -694,6 +695,7 @@ fn link_natively( crate_type: CrateType, out_filename: &Path, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, tmpdir: &Path, ) { info!("preparing {:?} to {:?}", crate_type, out_filename); @@ -718,6 +720,7 @@ fn link_natively( tmpdir, temp_filename, codegen_results, + metadata, self_contained_components, ); @@ -1065,11 +1068,11 @@ fn link_natively( match strip { Strip::Debuginfo => { // FIXME: AIX's strip utility only offers option to strip line number information. - strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"]) + strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-l"]) } Strip::Symbols => { // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata. - strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"]) + strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-r"]) } Strip::None => {} } @@ -2095,17 +2098,25 @@ fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &Cod /// Add object files containing metadata for the current crate. fn add_local_crate_metadata_objects( cmd: &mut dyn Linker, + sess: &Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, crate_type: CrateType, + tmpdir: &Path, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, ) { // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main - // object file, so we link that in here. - if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro) - && let Some(m) = &codegen_results.metadata_module - && let Some(obj) = &m.object - { - cmd.add_object(obj); + // object file, so we create and link it in here. + if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro) { + let data = archive_builder_builder.create_dylib_metadata_wrapper( + sess, + &metadata, + &codegen_results.crate_info.metadata_symbol, + ); + let obj = emit_wrapper_file(sess, &data, tmpdir, "rmeta.o"); + + cmd.add_object(&obj); } } @@ -2195,6 +2206,7 @@ fn linker_with_args( tmpdir: &Path, out_filename: &Path, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, self_contained_components: LinkSelfContainedComponents, ) -> Command { let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); @@ -2269,7 +2281,15 @@ fn linker_with_args( // in this DAG so far because they can only depend on other native libraries // and such dependencies are also required to be specified. add_local_crate_regular_objects(cmd, codegen_results); - add_local_crate_metadata_objects(cmd, crate_type, codegen_results); + add_local_crate_metadata_objects( + cmd, + sess, + archive_builder_builder, + crate_type, + tmpdir, + codegen_results, + metadata, + ); add_local_crate_allocator_objects(cmd, codegen_results); // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index a41ca8c..bbf9cce 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -24,7 +24,6 @@ use rustc_incremental::{ copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, }; -use rustc_metadata::EncodedMetadata; use rustc_metadata::fs::copy_to_stdout; use rustc_middle::bug; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -142,7 +141,6 @@ macro_rules! if_regular { || match kind { ModuleKind::Regular => sess.opts.output_types.contains_key(&OutputType::Object), ModuleKind::Allocator => false, - ModuleKind::Metadata => sess.opts.output_types.contains_key(&OutputType::Metadata), }; let emit_obj = if !should_emit_obj { @@ -350,7 +348,6 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub output_filenames: Arc<OutputFilenames>, pub invocation_temp: Option<String>, pub regular_module_config: Arc<ModuleConfig>, - pub metadata_module_config: Arc<ModuleConfig>, pub allocator_module_config: Arc<ModuleConfig>, pub tm_factory: TargetMachineFactoryFn<B>, pub msvc_imps_needed: bool, @@ -395,7 +392,6 @@ pub fn create_dcx(&self) -> DiagCtxt { pub fn config(&self, kind: ModuleKind) -> &ModuleConfig { match kind { ModuleKind::Regular => &self.regular_module_config, - ModuleKind::Metadata => &self.metadata_module_config, ModuleKind::Allocator => &self.allocator_module_config, } } @@ -474,8 +470,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( backend: B, tcx: TyCtxt<'_>, target_cpu: String, - metadata: EncodedMetadata, - metadata_module: Option<CompiledModule>, ) -> OngoingCodegen<B> { let (coordinator_send, coordinator_receive) = channel(); @@ -485,7 +479,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( let crate_info = CrateInfo::new(tcx, target_cpu); let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins); - let metadata_config = ModuleConfig::new(ModuleKind::Metadata, tcx, no_builtins); let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins); let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); @@ -499,15 +492,12 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( codegen_worker_send, coordinator_receive, Arc::new(regular_config), - Arc::new(metadata_config), Arc::new(allocator_config), coordinator_send.clone(), ); OngoingCodegen { backend, - metadata, - metadata_module, crate_info, codegen_worker_receive, @@ -843,12 +833,6 @@ pub(crate) fn compute_per_cgu_lto_type( sess_crate_types: &[CrateType], module_kind: ModuleKind, ) -> ComputedLtoType { - // Metadata modules never participate in LTO regardless of the lto - // settings. - if module_kind == ModuleKind::Metadata { - return ComputedLtoType::No; - } - // If the linker does LTO, we don't have to do it. Note that we // keep doing full LTO, if it is requested, as not to break the // assumption that the output will be a single module. @@ -1029,10 +1013,7 @@ fn finish_intra_module_work<B: ExtraBackendMethods>( let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - if !cgcx.opts.unstable_opts.combine_cgu - || module.kind == ModuleKind::Metadata - || module.kind == ModuleKind::Allocator - { + if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator { let module = B::codegen(cgcx, dcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) } else { @@ -1123,7 +1104,6 @@ fn start_executing_work<B: ExtraBackendMethods>( codegen_worker_send: Sender<CguMessage>, coordinator_receive: Receiver<Box<dyn Any + Send>>, regular_config: Arc<ModuleConfig>, - metadata_config: Arc<ModuleConfig>, allocator_config: Arc<ModuleConfig>, tx_to_llvm_workers: Sender<Box<dyn Any + Send>>, ) -> thread::JoinHandle<Result<CompiledModules, ()>> { @@ -1216,7 +1196,6 @@ fn start_executing_work<B: ExtraBackendMethods>( diag_emitter: shared_emitter.clone(), output_filenames: Arc::clone(tcx.output_filenames(())), regular_module_config: regular_config, - metadata_module_config: metadata_config, allocator_module_config: allocator_config, tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), msvc_imps_needed: msvc_imps_needed(tcx), @@ -1673,7 +1652,6 @@ enum CodegenState { assert!(compiled_allocator_module.is_none()); compiled_allocator_module = Some(compiled_module); } - ModuleKind::Metadata => bug!("Should be handled separately"), } } Ok(WorkItemResult::NeedsLink(module)) => { @@ -2055,8 +2033,6 @@ fn drop(&mut self) { pub struct OngoingCodegen<B: ExtraBackendMethods> { pub backend: B, - pub metadata: EncodedMetadata, - pub metadata_module: Option<CompiledModule>, pub crate_info: CrateInfo, pub codegen_worker_receive: Receiver<CguMessage>, pub shared_emitter_main: SharedEmitterMain, @@ -2096,12 +2072,10 @@ pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId, ( CodegenResults { - metadata: self.metadata, crate_info: self.crate_info, modules: compiled_modules.modules, allocator_module: compiled_modules.allocator_module, - metadata_module: self.metadata_module, }, work_products, )
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c2d6a26..a3d6c73 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -15,11 +15,10 @@ use rustc_hir::ItemId; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; -use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; -use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_middle::middle::{exported_symbols, lang_items}; +use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; +use rustc_middle::middle::lang_items; use rustc_middle::mir::BinOp; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions}; @@ -28,7 +27,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::Session; -use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; +use rustc_session::config::{self, CrateType, EntryFnType}; use rustc_span::{DUMMY_SP, Symbol, sym}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; @@ -37,7 +36,6 @@ use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; -use crate::back::metadata::create_compressed_metadata_file; use crate::back::write::{ ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, @@ -48,8 +46,7 @@ use crate::mir::place::PlaceRef; use crate::traits::*; use crate::{ - CachedModuleCodegen, CodegenLintLevels, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, - errors, meth, mir, + CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir, }; pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate { @@ -669,12 +666,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>( backend: B, tcx: TyCtxt<'_>, target_cpu: String, - metadata: EncodedMetadata, - need_metadata_module: bool, ) -> OngoingCodegen<B> { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu); ongoing_codegen.codegen_finished(tcx); @@ -707,39 +702,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( } } - let metadata_module = need_metadata_module.then(|| { - // Emit compressed metadata object. - let metadata_cgu_name = - cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string(); - tcx.sess.time("write_compressed_metadata", || { - let file_name = tcx.output_filenames(()).temp_path_for_cgu( - OutputType::Metadata, - &metadata_cgu_name, - tcx.sess.invocation_temp.as_deref(), - ); - let data = create_compressed_metadata_file( - tcx.sess, - &metadata, - &exported_symbols::metadata_symbol_name(tcx), - ); - if let Err(error) = std::fs::write(&file_name, data) { - tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite { error }); - } - CompiledModule { - name: metadata_cgu_name, - kind: ModuleKind::Metadata, - object: Some(file_name), - dwarf_object: None, - bytecode: None, - assembly: None, - llvm_ir: None, - links_from_incr_cache: Vec::new(), - } - }) - }); - - let ongoing_codegen = - start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module); + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu); // Codegen an allocator shim, if necessary. if let Some(kind) = allocator_kind_for_codegen(tcx) { @@ -1010,6 +973,7 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo { windows_subsystem, natvis_debugger_visualizers: Default::default(), lint_levels: CodegenLintLevels::from_tcx(tcx), + metadata_symbol: exported_symbols::metadata_symbol_name(tcx), }; info.native_libraries.reserve(n_crates);
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f843347..bac02bd 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -778,12 +778,6 @@ pub(crate) struct MultipleMainFunctions { } #[derive(Diagnostic)] -#[diag(codegen_ssa_metadata_object_file_write)] -pub(crate) struct MetadataObjectFileWrite { - pub error: Error, -} - -#[derive(Diagnostic)] #[diag(codegen_ssa_invalid_windows_subsystem)] pub(crate) struct InvalidWindowsSubsystem { pub subsystem: Symbol,
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8491964..523c9f2 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -31,6 +31,7 @@ use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::CrateNum; use rustc_macros::{Decodable, Encodable, HashStable}; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::lint::LevelAndSource; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -169,7 +170,6 @@ pub(crate) struct CachedModuleCodegen { #[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable)] pub enum ModuleKind { Regular, - Metadata, Allocator, } @@ -233,6 +233,7 @@ pub struct CrateInfo { pub windows_subsystem: Option<String>, pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>, pub lint_levels: CodegenLintLevels, + pub metadata_symbol: String, } /// Target-specific options that get set in `cfg(...)`. @@ -257,8 +258,6 @@ pub struct TargetConfig { pub struct CodegenResults { pub modules: Vec<CompiledModule>, pub allocator_module: Option<CompiledModule>, - pub metadata_module: Option<CompiledModule>, - pub metadata: rustc_metadata::EncodedMetadata, pub crate_info: CrateInfo, } @@ -303,6 +302,7 @@ pub fn serialize_rlink( sess: &Session, rlink_file: &Path, codegen_results: &CodegenResults, + metadata: &EncodedMetadata, outputs: &OutputFilenames, ) -> Result<usize, io::Error> { let mut encoder = FileEncoder::new(rlink_file)?; @@ -312,6 +312,7 @@ pub fn serialize_rlink( encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); encoder.emit_str(sess.cfg_version); Encodable::encode(codegen_results, &mut encoder); + Encodable::encode(metadata, &mut encoder); Encodable::encode(outputs, &mut encoder); encoder.finish().map_err(|(_path, err)| err) } @@ -319,7 +320,7 @@ pub fn serialize_rlink( pub fn deserialize_rlink( sess: &Session, data: Vec<u8>, - ) -> Result<(Self, OutputFilenames), CodegenErrors> { + ) -> Result<(Self, EncodedMetadata, OutputFilenames), CodegenErrors> { // The Decodable machinery is not used here because it panics if the input data is invalid // and because its internal representation may change. if !data.starts_with(RLINK_MAGIC) { @@ -350,8 +351,9 @@ pub fn deserialize_rlink( } let codegen_results = CodegenResults::decode(&mut decoder); + let metadata = EncodedMetadata::decode(&mut decoder); let outputs = OutputFilenames::decode(&mut decoder); - Ok((codegen_results, outputs)) + Ok((codegen_results, metadata, outputs)) } }
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index e217c09..27fcab8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -118,7 +118,7 @@ pub fn codegen_intrinsic_call( let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); llsize } - sym::min_align_of_val => { + sym::align_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 46fb9a8..b805dc0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -1,14 +1,13 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; use rustc_attr_data_structures::InstructionSetAttr; -use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility}; use rustc_middle::mir::{InlineAsmOperand, START_BLOCK}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::{bug, span_bug, ty}; +use rustc_middle::{bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::{BinaryFormat, WasmCAbi}; +use rustc_target::spec::BinaryFormat; use crate::common; use crate::mir::AsmCodegenMethods; @@ -287,12 +286,7 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, "{}", arch_prefix).unwrap(); } writeln!(begin, "{asm_name}:").unwrap(); - writeln!( - begin, - ".functype {asm_name} {}", - wasm_functype(tcx, fn_abi, instance.def_id()) - ) - .unwrap(); + writeln!(begin, ".functype {asm_name} {}", wasm_functype(tcx, fn_abi)).unwrap(); writeln!(end).unwrap(); // .size is ignored for function symbols, so we can skip it @@ -333,7 +327,7 @@ fn prefix_and_suffix<'tcx>( /// The webassembly type signature for the given function. /// /// Used by the `.functype` directive on wasm targets. -fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String { +fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String { let mut signature = String::with_capacity(64); let ptr_type = match tcx.data_layout.pointer_size.bits() { @@ -342,17 +336,6 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id other => bug!("wasm pointer size cannot be {other} bits"), }; - // FIXME: remove this once the wasm32-unknown-unknown ABI is fixed - // please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs` - // basically the commit introducing this comment should be reverted - if let PassMode::Pair { .. } = fn_abi.ret.mode { - let _ = WasmCAbi::Legacy { with_lint: true }; - span_bug!( - tcx.def_span(def_id), - "cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" - ); - } - let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); signature.push('('); @@ -366,7 +349,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id let mut it = fn_abi.args.iter().peekable(); while let Some(arg_abi) = it.next() { - wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id); + wasm_type(&mut signature, arg_abi, ptr_type); if it.peek().is_some() { signature.push_str(", "); } @@ -375,7 +358,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id signature.push_str(") -> ("); if !hidden_return { - wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id); + wasm_type(&mut signature, &fn_abi.ret, ptr_type); } signature.push(')'); @@ -383,27 +366,13 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id signature } -fn wasm_type<'tcx>( - tcx: TyCtxt<'tcx>, - signature: &mut String, - arg_abi: &ArgAbi<'_, Ty<'tcx>>, - ptr_type: &'static str, - def_id: DefId, -) { +fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_type: &'static str) { match arg_abi.mode { PassMode::Ignore => { /* do nothing */ } PassMode::Direct(_) => { let direct_type = match arg_abi.layout.backend_repr { BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type), BackendRepr::SimdVector { .. } => "v128", - BackendRepr::Memory { .. } => { - // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed - let _ = WasmCAbi::Legacy { with_lint: true }; - span_bug!( - tcx.def_span(def_id), - "cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" - ); - } other => unreachable!("unexpected BackendRepr: {:?}", other), };
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 6bb3150..640d197 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -8,6 +8,7 @@ use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -66,7 +67,7 @@ pub(crate) fn from_target_feature_attr( // Only allow target features whose feature gates have been enabled // and which are permitted to be toggled. - if let Err(reason) = stability.toggle_allowed() { + if let Err(reason) = stability.is_toggle_permitted(tcx.sess) { tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { span: item.span(), feature,
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 95bf3b1..29ec7eb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -74,12 +74,7 @@ fn metadata_loader(&self) -> Box<MetadataLoaderDyn> { fn provide(&self, _providers: &mut Providers) {} - fn codegen_crate<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: EncodedMetadata, - need_metadata_module: bool, - ) -> Box<dyn Any>; + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any>; /// This is called on the returned `Box<dyn Any>` from [`codegen_crate`](Self::codegen_crate) /// @@ -94,8 +89,14 @@ fn join_codegen( ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>); /// This is called on the returned [`CodegenResults`] from [`join_codegen`](Self::join_codegen). - fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) { - link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs); + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + metadata: EncodedMetadata, + outputs: &OutputFilenames, + ) { + link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, metadata, outputs); } }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 7f78bc7..f35f551 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -23,7 +23,7 @@ use crate::mir::operand::{OperandRef, OperandValue}; use crate::mir::place::{PlaceRef, PlaceValue}; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum OverflowOp { Add, Sub, @@ -215,7 +215,7 @@ fn or_disjoint(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { fn checked_binop( &mut self, oop: OverflowOp, - ty: Ty<'_>, + ty: Ty<'tcx>, lhs: Self::Value, rhs: Self::Value, ) -> (Self::Value, Self::Value);
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index ab27182..96c39c7 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -120,7 +120,7 @@ pub fn eval_intrinsic( self.copy_op(&val, dest)?; } - sym::min_align_of_val | sym::size_of_val => { + sym::align_of_val | sym::size_of_val => { // Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be // dereferenceable! let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?; @@ -129,7 +129,7 @@ pub fn eval_intrinsic( .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?; let result = match intrinsic_name { - sym::min_align_of_val => align.bytes(), + sym::align_of_val => align.bytes(), sym::size_of_val => size.bytes(), _ => bug!(), }; @@ -139,13 +139,13 @@ pub fn eval_intrinsic( sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { let gid = GlobalId { instance, promoted: None }; - let ty = match intrinsic_name { - sym::variant_count => self.tcx.types.usize, - sym::needs_drop => self.tcx.types.bool, - sym::type_id => self.tcx.types.u128, - sym::type_name => Ty::new_static_str(self.tcx.tcx), - _ => bug!(), - }; + let ty = self + .tcx + .fn_sig(instance.def_id()) + .instantiate(self.tcx.tcx, instance.args) + .output() + .no_bound_vars() + .unwrap(); let val = self .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
diff --git a/compiler/rustc_data_structures/src/thousands/mod.rs b/compiler/rustc_data_structures/src/thousands/mod.rs index e7ab7ec..b251ebe 100644 --- a/compiler/rustc_data_structures/src/thousands/mod.rs +++ b/compiler/rustc_data_structures/src/thousands/mod.rs
@@ -1,16 +1,37 @@ -//! This is an extremely bare-bones alternative to the `thousands` crate on -//! crates.io, for printing large numbers in a readable fashion. +//! This is a bare-bones alternative to the `thousands` crate on crates.io, for +//! printing large numbers in a readable fashion. #[cfg(test)] mod tests; -// Converts the number to a string, with underscores as the thousands separator. -pub fn format_with_underscores(n: usize) -> String { - let mut s = n.to_string(); - let mut i = s.len(); - while i > 3 { +fn format_with_underscores(mut s: String) -> String { + // Ignore a leading '-'. + let start = if s.starts_with('-') { 1 } else { 0 }; + + // Stop after the first non-digit, e.g. '.' or 'e' for floats. + let non_digit = s[start..].find(|c: char| !c.is_digit(10)); + let end = if let Some(non_digit) = non_digit { start + non_digit } else { s.len() }; + + // Insert underscores within `start..end`. + let mut i = end; + while i > start + 3 { i -= 3; s.insert(i, '_'); } s } + +/// Print a `usize` with underscore separators. +pub fn usize_with_underscores(n: usize) -> String { + format_with_underscores(format!("{n}")) +} + +/// Print an `isize` with underscore separators. +pub fn isize_with_underscores(n: isize) -> String { + format_with_underscores(format!("{n}")) +} + +/// Print an `f64` with precision 1 (one decimal place) and underscore separators. +pub fn f64p1_with_underscores(n: f64) -> String { + format_with_underscores(format!("{n:.1}")) +}
diff --git a/compiler/rustc_data_structures/src/thousands/tests.rs b/compiler/rustc_data_structures/src/thousands/tests.rs index 906605d..0f9a648 100644 --- a/compiler/rustc_data_structures/src/thousands/tests.rs +++ b/compiler/rustc_data_structures/src/thousands/tests.rs
@@ -2,13 +2,51 @@ #[test] fn test_format_with_underscores() { - assert_eq!("0", format_with_underscores(0)); - assert_eq!("1", format_with_underscores(1)); - assert_eq!("99", format_with_underscores(99)); - assert_eq!("345", format_with_underscores(345)); - assert_eq!("1_000", format_with_underscores(1_000)); - assert_eq!("12_001", format_with_underscores(12_001)); - assert_eq!("999_999", format_with_underscores(999_999)); - assert_eq!("1_000_000", format_with_underscores(1_000_000)); - assert_eq!("12_345_678", format_with_underscores(12_345_678)); + assert_eq!("", format_with_underscores("".to_string())); + assert_eq!("0", format_with_underscores("0".to_string())); + assert_eq!("12_345.67e14", format_with_underscores("12345.67e14".to_string())); + assert_eq!("-1_234.5678e10", format_with_underscores("-1234.5678e10".to_string())); + assert_eq!("------", format_with_underscores("------".to_string())); + assert_eq!("abcdefgh", format_with_underscores("abcdefgh".to_string())); + assert_eq!("-1b", format_with_underscores("-1b".to_string())); + assert_eq!("-3_456xyz", format_with_underscores("-3456xyz".to_string())); +} + +#[test] +fn test_usize_with_underscores() { + assert_eq!("0", usize_with_underscores(0)); + assert_eq!("1", usize_with_underscores(1)); + assert_eq!("99", usize_with_underscores(99)); + assert_eq!("345", usize_with_underscores(345)); + assert_eq!("1_000", usize_with_underscores(1_000)); + assert_eq!("12_001", usize_with_underscores(12_001)); + assert_eq!("999_999", usize_with_underscores(999_999)); + assert_eq!("1_000_000", usize_with_underscores(1_000_000)); + assert_eq!("12_345_678", usize_with_underscores(12_345_678)); +} + +#[test] +fn test_isize_with_underscores() { + assert_eq!("0", isize_with_underscores(0)); + assert_eq!("-1", isize_with_underscores(-1)); + assert_eq!("99", isize_with_underscores(99)); + assert_eq!("345", isize_with_underscores(345)); + assert_eq!("-1_000", isize_with_underscores(-1_000)); + assert_eq!("12_001", isize_with_underscores(12_001)); + assert_eq!("-999_999", isize_with_underscores(-999_999)); + assert_eq!("1_000_000", isize_with_underscores(1_000_000)); + assert_eq!("-12_345_678", isize_with_underscores(-12_345_678)); +} + +#[test] +fn test_f64p1_with_underscores() { + assert_eq!("0.0", f64p1_with_underscores(0f64)); + assert_eq!("0.0", f64p1_with_underscores(0.00000001)); + assert_eq!("-0.0", f64p1_with_underscores(-0.00000001)); + assert_eq!("1.0", f64p1_with_underscores(0.9999999)); + assert_eq!("-1.0", f64p1_with_underscores(-0.9999999)); + assert_eq!("345.5", f64p1_with_underscores(345.4999999)); + assert_eq!("-100_000.0", f64p1_with_underscores(-100_000f64)); + assert_eq!("123_456_789.1", f64p1_with_underscores(123456789.123456789)); + assert_eq!("-123_456_789.1", f64p1_with_underscores(-123456789.123456789)); }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 54a331a..d53126d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -557,27 +557,34 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) { let rlink_data = fs::read(file).unwrap_or_else(|err| { dcx.emit_fatal(RlinkUnableToRead { err }); }); - let (codegen_results, outputs) = match CodegenResults::deserialize_rlink(sess, rlink_data) { - Ok((codegen, outputs)) => (codegen, outputs), - Err(err) => { - match err { - CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType), - CodegenErrors::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber), - CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => dcx - .emit_fatal(RLinkEncodingVersionMismatch { version_array, rlink_version }), - CodegenErrors::RustcVersionMismatch { rustc_version } => { - dcx.emit_fatal(RLinkRustcVersionMismatch { - rustc_version, - current_version: sess.cfg_version, - }) - } - CodegenErrors::CorruptFile => { - dcx.emit_fatal(RlinkCorruptFile { file }); - } - }; - } - }; - compiler.codegen_backend.link(sess, codegen_results, &outputs); + let (codegen_results, metadata, outputs) = + match CodegenResults::deserialize_rlink(sess, rlink_data) { + Ok((codegen, metadata, outputs)) => (codegen, metadata, outputs), + Err(err) => { + match err { + CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType), + CodegenErrors::EmptyVersionNumber => { + dcx.emit_fatal(RLinkEmptyVersionNumber) + } + CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => { + dcx.emit_fatal(RLinkEncodingVersionMismatch { + version_array, + rlink_version, + }) + } + CodegenErrors::RustcVersionMismatch { rustc_version } => { + dcx.emit_fatal(RLinkRustcVersionMismatch { + rustc_version, + current_version: sess.cfg_version, + }) + } + CodegenErrors::CorruptFile => { + dcx.emit_fatal(RlinkCorruptFile { file }); + } + }; + } + }; + compiler.codegen_backend.link(sess, codegen_results, metadata, &outputs); } else { dcx.emit_fatal(RlinkNotAFile {}); } @@ -1500,13 +1507,31 @@ pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) { /// This allows tools to enable rust logging without having to magically match rustc's /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose -/// the values directly rather than having to set an environment variable. +/// the logger config directly rather than having to set an environment variable. pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) { if let Err(error) = rustc_log::init_logger(cfg) { early_dcx.early_fatal(error.to_string()); } } +/// This allows tools to enable rust logging without having to magically match rustc's +/// tracing crate version. In contrast to `init_rustc_env_logger`, it allows you to +/// choose the logger config directly rather than having to set an environment variable. +/// Moreover, in contrast to `init_logger`, it allows you to add a custom tracing layer +/// via `build_subscriber`, for example `|| Registry::default().with(custom_layer)`. +pub fn init_logger_with_additional_layer<F, T>( + early_dcx: &EarlyDiagCtxt, + cfg: rustc_log::LoggerConfig, + build_subscriber: F, +) where + F: FnOnce() -> T, + T: rustc_log::BuildSubscriberRet, +{ + if let Err(error) = rustc_log::init_logger_with_additional_layer(cfg, build_subscriber) { + early_dcx.early_fatal(error.to_string()); + } +} + /// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`]. /// Making this handler optional lets tools can install a different handler, if they wish. pub fn install_ctrlc_handler() {
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 133bd36..9f72fc4 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs
@@ -60,8 +60,9 @@ SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_hashes::Hash128; -use rustc_lint_defs::LintExpectationId; +use rustc_hir::HirId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; +use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -101,6 +102,19 @@ #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); +/// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. +/// Always the `TyCtxt`. +pub trait LintEmitter: Copy { + #[track_caller] + fn emit_node_span_lint( + self, + lint: &'static Lint, + hir_id: HirId, + span: impl Into<MultiSpan>, + decorator: impl for<'a> LintDiagnostic<'a, ()>, + ); +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { /// Hide the suggested code when displaying this suggestion inline.
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 08b7a36..8b7c47d 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl
@@ -113,7 +113,7 @@ variable `{$key}` is not recognized in meta-variable expression expand_missing_fragment_specifier = missing fragment specifier - .note = fragment specifiers must be specified in the 2024 edition + .note = fragment specifiers must be provided .suggestion_add_fragspec = try adding a specifier here .valid = {$valid}
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c7b975d..311dadb 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs
@@ -12,7 +12,7 @@ use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr}; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; @@ -727,6 +727,7 @@ pub enum SyntaxExtensionKind { /// A trivial attribute "macro" that does nothing, /// only keeps the attribute and marks it as inert, /// thus making it ineligible for further expansion. + /// E.g. `#[default]`, `#[rustfmt::skip]`. NonMacroAttr, /// A token-based derive macro. @@ -1189,6 +1190,8 @@ pub struct ExtCtxt<'a> { /// in the AST, but insert it here so that we know /// not to expand it again. pub(super) expanded_inert_attrs: MarkedAttrs, + /// `-Zmacro-stats` data. + pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals } impl<'a> ExtCtxt<'a> { @@ -1218,6 +1221,7 @@ pub fn new( expansions: FxIndexMap::default(), expanded_inert_attrs: MarkedAttrs::new(), buffered_early_lint: vec![], + macro_stats: Default::default(), } }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 569165a..3cfeb01 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs
@@ -42,13 +42,22 @@ DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod, }; use crate::placeholders::{PlaceholderExpander, placeholder}; +use crate::stats::*; macro_rules! ast_fragments { ( $($Kind:ident($AstTy:ty) { $kind_name:expr; - $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)? - $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)? + $(one + fn $mut_visit_ast:ident; + fn $visit_ast:ident; + fn $ast_to_string:path; + )? + $(many + fn $flat_map_ast_elt:ident; + fn $visit_ast_elt:ident($($args:tt)*); + fn $ast_to_string_elt:path; + )? fn $make_ast:ident; })* ) => { @@ -61,7 +70,7 @@ pub enum AstFragment { } /// "Discriminant" of an AST fragment. - #[derive(Copy, Clone, PartialEq, Eq)] + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum AstFragmentKind { OptExpr, MethodReceiverExpr, @@ -151,6 +160,21 @@ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result { } V::Result::output() } + + pub(crate) fn to_string(&self) -> String { + match self { + AstFragment::OptExpr(Some(expr)) => pprust::expr_to_string(expr), + AstFragment::OptExpr(None) => unreachable!(), + AstFragment::MethodReceiverExpr(expr) => pprust::expr_to_string(expr), + $($(AstFragment::$Kind(ast) => $ast_to_string(ast),)?)* + $($( + AstFragment::$Kind(ast) => { + // The closure unwraps a `P` if present, or does nothing otherwise. + elems_to_string(&*ast, |ast| $ast_to_string_elt(&*ast)) + } + )?)* + } + } } impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> { @@ -163,76 +187,98 @@ impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> { } ast_fragments! { - Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; } - Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; } - Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; } + Expr(P<ast::Expr>) { + "expression"; + one fn visit_expr; fn visit_expr; fn pprust::expr_to_string; + fn make_expr; + } + Pat(P<ast::Pat>) { + "pattern"; + one fn visit_pat; fn visit_pat; fn pprust::pat_to_string; + fn make_pat; + } + Ty(P<ast::Ty>) { + "type"; + one fn visit_ty; fn visit_ty; fn pprust::ty_to_string; + fn make_ty; + } Stmts(SmallVec<[ast::Stmt; 1]>) { - "statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts; + "statement"; + many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string; + fn make_stmts; } Items(SmallVec<[P<ast::Item>; 1]>) { - "item"; many fn flat_map_item; fn visit_item(); fn make_items; + "item"; + many fn flat_map_item; fn visit_item(); fn pprust::item_to_string; + fn make_items; } TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) { "trait item"; - many fn flat_map_assoc_item; - fn visit_assoc_item(AssocCtxt::Trait); + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait); + fn pprust::assoc_item_to_string; fn make_trait_items; } ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { "impl item"; - many fn flat_map_assoc_item; - fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); + fn pprust::assoc_item_to_string; fn make_impl_items; } TraitImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { "impl item"; - many fn flat_map_assoc_item; - fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); + fn pprust::assoc_item_to_string; fn make_trait_impl_items; } ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) { "foreign item"; - many fn flat_map_foreign_item; - fn visit_foreign_item(); + many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string; fn make_foreign_items; } Arms(SmallVec<[ast::Arm; 1]>) { - "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms; + "match arm"; + many fn flat_map_arm; fn visit_arm(); fn unreachable_to_string; + fn make_arms; } ExprFields(SmallVec<[ast::ExprField; 1]>) { - "field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields; + "field expression"; + many fn flat_map_expr_field; fn visit_expr_field(); fn unreachable_to_string; + fn make_expr_fields; } PatFields(SmallVec<[ast::PatField; 1]>) { "field pattern"; - many fn flat_map_pat_field; - fn visit_pat_field(); + many fn flat_map_pat_field; fn visit_pat_field(); fn unreachable_to_string; fn make_pat_fields; } GenericParams(SmallVec<[ast::GenericParam; 1]>) { "generic parameter"; - many fn flat_map_generic_param; - fn visit_generic_param(); + many fn flat_map_generic_param; fn visit_generic_param(); fn unreachable_to_string; fn make_generic_params; } Params(SmallVec<[ast::Param; 1]>) { - "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params; + "function parameter"; + many fn flat_map_param; fn visit_param(); fn unreachable_to_string; + fn make_params; } FieldDefs(SmallVec<[ast::FieldDef; 1]>) { "field"; - many fn flat_map_field_def; - fn visit_field_def(); + many fn flat_map_field_def; fn visit_field_def(); fn unreachable_to_string; fn make_field_defs; } Variants(SmallVec<[ast::Variant; 1]>) { - "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; + "variant"; many fn flat_map_variant; fn visit_variant(); fn unreachable_to_string; + fn make_variants; } WherePredicates(SmallVec<[ast::WherePredicate; 1]>) { "where predicate"; - many fn flat_map_where_predicate; - fn visit_where_predicate(); + many fn flat_map_where_predicate; fn visit_where_predicate(); fn unreachable_to_string; fn make_where_predicates; - } - Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; } + } + Crate(ast::Crate) { + "crate"; + one fn visit_crate; fn visit_crate; fn unreachable_to_string; + fn make_crate; + } } pub enum SupportsMacroExpansion { @@ -270,7 +316,7 @@ pub fn supports_macro_expansion(self) -> SupportsMacroExpansion { } } - fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>( + pub(crate) fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>( self, items: I, ) -> AstFragment { @@ -686,13 +732,26 @@ fn expand_invoc( return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar)); } + let macro_stats = self.cx.sess.opts.unstable_opts.macro_stats; + let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); ExpandResult::Ready(match invoc.kind { InvocationKind::Bang { mac, span } => match ext { SyntaxExtensionKind::Bang(expander) => { match expander.expand(self.cx, span, mac.args.tokens.clone()) { Ok(tok_result) => { - self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) + let fragment = + self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span); + if macro_stats { + update_bang_macro_stats( + self.cx, + fragment_kind, + span, + mac, + &fragment, + ); + } + fragment } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } @@ -708,13 +767,15 @@ fn expand_invoc( }); } }; - let result = if let Some(result) = fragment_kind.make_from(tok_result) { - result + if let Some(fragment) = fragment_kind.make_from(tok_result) { + if macro_stats { + update_bang_macro_stats(self.cx, fragment_kind, span, mac, &fragment); + } + fragment } else { let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span); fragment_kind.dummy(span, guar) - }; - result + } } _ => unreachable!(), }, @@ -746,24 +807,39 @@ fn expand_invoc( } _ => item.to_tokens(), }; - let attr_item = attr.unwrap_normal_item(); + let attr_item = attr.get_normal_item(); if let AttrArgs::Eq { .. } = attr_item.args { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); match expander.expand(self.cx, span, inner_tokens, tokens) { - Ok(tok_result) => self.parse_ast_fragment( - tok_result, - fragment_kind, - &attr_item.path, - span, - ), + Ok(tok_result) => { + let fragment = self.parse_ast_fragment( + tok_result, + fragment_kind, + &attr_item.path, + span, + ); + if macro_stats { + update_attr_macro_stats( + self.cx, + fragment_kind, + span, + &attr_item.path, + &attr, + item, + &fragment, + ); + } + fragment + } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } } SyntaxExtensionKind::LegacyAttr(expander) => { match validate_attr::parse_meta(&self.cx.sess.psess, &attr) { Ok(meta) => { + let item_clone = macro_stats.then(|| item.clone()); let items = match expander.expand(self.cx, span, &meta, item, false) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { @@ -782,7 +858,19 @@ fn expand_invoc( let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span }); fragment_kind.dummy(span, guar) } else { - fragment_kind.expect_from_annotatables(items) + let fragment = fragment_kind.expect_from_annotatables(items); + if macro_stats { + update_attr_macro_stats( + self.cx, + fragment_kind, + span, + &meta.path, + &attr, + item_clone.unwrap(), + &fragment, + ); + } + fragment } } Err(err) => { @@ -792,6 +880,7 @@ fn expand_invoc( } } SyntaxExtensionKind::NonMacroAttr => { + // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); fragment_kind.expect_from_annotatables(iter::once(item)) @@ -822,7 +911,17 @@ fn expand_invoc( }); } }; - fragment_kind.expect_from_annotatables(items) + let fragment = fragment_kind.expect_from_annotatables(items); + if macro_stats { + update_derive_macro_stats( + self.cx, + fragment_kind, + span, + &meta.path, + &fragment, + ); + } + fragment } _ => unreachable!(), }, @@ -852,6 +951,7 @@ fn expand_invoc( let single_delegations = build_single_delegations::<Node>( self.cx, deleg, &item, &suffixes, item.span, true, ); + // `-Zmacro-stats` ignores these because they don't seem important. fragment_kind.expect_from_annotatables( single_delegations .map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })),
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 515d822..64be764 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs
@@ -20,6 +20,7 @@ mod mbe; mod placeholders; mod proc_macro_server; +mod stats; pub use mbe::macro_rules::compile_declarative_macro; pub mod base;
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 1a2db23..3cd803c 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -112,9 +112,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_lint_defs::BuiltinLintDiag; -use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; +use rustc_session::lint::builtin::META_VARIABLE_MISUSE; use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw}; use smallvec::SmallVec; @@ -266,23 +265,11 @@ fn check_binders( // Similarly, this can only happen when checking a toplevel macro. TokenTree::MetaVarDecl(span, name, kind) => { if kind.is_none() && node_id != DUMMY_NODE_ID { - // FIXME: Report this as a hard error eventually and remove equivalent errors from - // `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once - // as a hard error and then once as a buffered lint. - if span.edition() >= Edition::Edition2024 { - psess.dcx().emit_err(errors::MissingFragmentSpecifier { - span, - add_span: span.shrink_to_hi(), - valid: VALID_FRAGMENT_NAMES_MSG, - }); - } else { - psess.buffer_lint( - MISSING_FRAGMENT_SPECIFIER, - span, - node_id, - BuiltinLintDiag::MissingFragmentSpecifier, - ); - } + psess.dcx().emit_err(errors::MissingFragmentSpecifier { + span, + add_span: span.shrink_to_hi(), + valid: VALID_FRAGMENT_NAMES_MSG, + }); } if !macros.is_empty() { psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");
diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs new file mode 100644 index 0000000..6b2ad30 --- /dev/null +++ b/compiler/rustc_expand/src/stats.rs
@@ -0,0 +1,171 @@ +use std::iter; + +use rustc_ast::ptr::P; +use rustc_ast::{self as ast, DUMMY_NODE_ID, Expr, ExprKind}; +use rustc_ast_pretty::pprust; +use rustc_span::hygiene::{ExpnKind, MacroKind}; +use rustc_span::{Span, Symbol, kw, sym}; +use smallvec::SmallVec; + +use crate::base::{Annotatable, ExtCtxt}; +use crate::expand::{AstFragment, AstFragmentKind}; + +#[derive(Default)] +pub struct MacroStat { + /// Number of uses of the macro. + pub uses: usize, + + /// Net increase in number of lines of code (when pretty-printed), i.e. + /// `lines(output) - lines(invocation)`. Can be negative because a macro + /// output may be smaller than the invocation. + pub lines: isize, + + /// Net increase in number of lines of code (when pretty-printed), i.e. + /// `bytes(output) - bytes(invocation)`. Can be negative because a macro + /// output may be smaller than the invocation. + pub bytes: isize, +} + +pub(crate) fn elems_to_string<T>(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> String) -> String { + let mut s = String::new(); + for (i, elem) in elems.iter().enumerate() { + if i > 0 { + s.push('\n'); + } + s.push_str(&f(elem)); + } + s +} + +pub(crate) fn unreachable_to_string<T>(_: &T) -> String { + unreachable!() +} + +pub(crate) fn update_bang_macro_stats( + ecx: &mut ExtCtxt<'_>, + fragment_kind: AstFragmentKind, + span: Span, + mac: P<ast::MacCall>, + fragment: &AstFragment, +) { + // Does this path match any of the include macros, e.g. `include!`? + // Ignore them. They would have large numbers but are entirely + // unsurprising and uninteresting. + let is_include_path = mac.path == sym::include + || mac.path == sym::include_bytes + || mac.path == sym::include_str + || mac.path == [sym::std, sym::include].as_slice() // std::include + || mac.path == [sym::std, sym::include_bytes].as_slice() // std::include_bytes + || mac.path == [sym::std, sym::include_str].as_slice(); // std::include_str + if is_include_path { + return; + } + + // The call itself (e.g. `println!("hi")`) is the input. Need to wrap + // `mac` in something printable; `ast::Expr` is as good as anything + // else. + let expr = Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::MacCall(mac), + span: Default::default(), + attrs: Default::default(), + tokens: None, + }; + let input = pprust::expr_to_string(&expr); + + // Get `mac` back out of `expr`. + let ast::Expr { kind: ExprKind::MacCall(mac), .. } = expr else { unreachable!() }; + + update_macro_stats(ecx, MacroKind::Bang, fragment_kind, span, &mac.path, &input, fragment); +} + +pub(crate) fn update_attr_macro_stats( + ecx: &mut ExtCtxt<'_>, + fragment_kind: AstFragmentKind, + span: Span, + path: &ast::Path, + attr: &ast::Attribute, + item: Annotatable, + fragment: &AstFragment, +) { + // Does this path match `#[derive(...)]` in any of its forms? If so, + // ignore it because the individual derives will go through the + // `Invocation::Derive` handling separately. + let is_derive_path = *path == sym::derive + // ::core::prelude::v1::derive + || *path == [kw::PathRoot, sym::core, sym::prelude, sym::v1, sym::derive].as_slice(); + if is_derive_path { + return; + } + + // The attribute plus the item itself constitute the input, which we + // measure. + let input = format!( + "{}\n{}", + pprust::attribute_to_string(attr), + fragment_kind.expect_from_annotatables(iter::once(item)).to_string(), + ); + update_macro_stats(ecx, MacroKind::Attr, fragment_kind, span, path, &input, fragment); +} + +pub(crate) fn update_derive_macro_stats( + ecx: &mut ExtCtxt<'_>, + fragment_kind: AstFragmentKind, + span: Span, + path: &ast::Path, + fragment: &AstFragment, +) { + // Use something like `#[derive(Clone)]` for the measured input, even + // though it may have actually appeared in a multi-derive attribute + // like `#[derive(Clone, Copy, Debug)]`. + let input = format!("#[derive({})]", pprust::path_to_string(path)); + update_macro_stats(ecx, MacroKind::Derive, fragment_kind, span, path, &input, fragment); +} + +pub(crate) fn update_macro_stats( + ecx: &mut ExtCtxt<'_>, + macro_kind: MacroKind, + fragment_kind: AstFragmentKind, + span: Span, + path: &ast::Path, + input: &str, + fragment: &AstFragment, +) { + fn lines_and_bytes(s: &str) -> (usize, usize) { + (s.trim_end().split('\n').count(), s.len()) + } + + // Measure the size of the output by pretty-printing it and counting + // the lines and bytes. + let name = Symbol::intern(&pprust::path_to_string(path)); + let output = fragment.to_string(); + let (in_l, in_b) = lines_and_bytes(input); + let (out_l, out_b) = lines_and_bytes(&output); + + // This code is useful for debugging `-Zmacro-stats`. For every + // invocation it prints the full input and output. + if false { + let name = ExpnKind::Macro(macro_kind, name).descr(); + let crate_name = &ecx.ecfg.crate_name; + let span = ecx + .sess + .source_map() + .span_to_string(span, rustc_span::FileNameDisplayPreference::Local); + eprint!( + "\ + -------------------------------\n\ + {name}: [{crate_name}] ({fragment_kind:?}) {span}\n\ + -------------------------------\n\ + {input}\n\ + -- ({in_l} lines, {in_b} bytes) --> ({out_l} lines, {out_b} bytes) --\n\ + {output}\n\ + " + ); + } + + // The recorded size is the difference between the input and the output. + let entry = ecx.macro_stats.entry((name, macro_kind)).or_insert(MacroStat::default()); + entry.uses += 1; + entry.lines += out_l as isize - in_l as isize; + entry.bytes += out_b as isize - in_b as isize; +}
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c117e0f..73a2178 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -9,7 +9,7 @@ use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; -use crate::{Features, Stability}; +use crate::Features; type GateFn = fn(&Features) -> bool; @@ -94,34 +94,23 @@ pub enum AttributeSafety { Unsafe { unsafe_since: Option<Edition> }, } -#[derive(Clone, Copy)] +#[derive(Clone, Debug, Copy)] pub enum AttributeGate { - /// Is gated by a given feature gate, reason - /// and function to check if enabled - Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), - + /// A gated attribute which requires a feature gate to be enabled. + Gated { + /// The feature gate, for example `#![feature(rustc_attrs)]` for rustc_* attributes. + feature: Symbol, + /// The error message displayed when an attempt is made to use the attribute without its feature gate. + message: &'static str, + /// Check function to be called during the `PostExpansionVisitor` pass. + check: fn(&Features) -> bool, + /// Notes to be displayed when an attempt is made to use the attribute without its feature gate. + notes: &'static [&'static str], + }, /// Ungated attribute, can be used on all release channels Ungated, } -// fn() is not Debug -impl std::fmt::Debug for AttributeGate { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - Self::Gated(ref stab, name, expl, _) => { - write!(fmt, "Gated({stab:?}, {name}, {expl})") - } - Self::Ungated => write!(fmt, "Ungated"), - } - } -} - -impl AttributeGate { - fn is_deprecated(&self) -> bool { - matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..)) - } -} - /// A template that the attribute input must match. /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. #[derive(Clone, Copy, Default)] @@ -247,7 +236,7 @@ macro_rules! ungated { } macro_rules! gated { - (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -255,10 +244,15 @@ macro_rules! gated { safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), + gate: Gated { + feature: sym::$gate, + message: $message, + check: Features::$gate, + notes: &[], + }, } }; - (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -266,10 +260,15 @@ macro_rules! gated { safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), + gate: Gated { + feature: sym::$attr, + message: $message, + check: Features::$attr, + notes: &[], + }, } }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -277,10 +276,15 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), + gate: Gated { + feature: sym::$gate, + message: $message, + check: Features::$gate, + notes: &[], + }, } }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -288,7 +292,12 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), + gate: Gated { + feature: sym::$attr, + message: $message, + check: Features::$attr, + notes: &[], + }, } }; } @@ -304,12 +313,11 @@ macro_rules! rustc_attr { concat!( "the `#[", stringify!($attr), - "]` attribute is just used for rustc unit tests \ - and will never be stable", + "]` attribute is used for rustc unit tests" ), ) }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -317,7 +325,17 @@ macro_rules! rustc_attr { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs), + gate: Gated { + feature: sym::rustc_attrs, + message: "use of an internal attribute", + check: Features::rustc_attrs, + notes: &[ + concat!("the `#[", + stringify!($attr), + "]` attribute is an internal implementation detail that will never be stable"), + $($notes),* + ] + }, } }; } @@ -328,9 +346,6 @@ macro_rules! experimental { }; } -const IMPL_DETAIL: &str = "internal implementation detail"; -const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; - #[derive(PartialEq)] pub enum EncodeCrossCrate { Yes, @@ -668,7 +683,7 @@ pub struct BuiltinAttribute { rustc_attr!( rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#), ErrorFollowing, EncodeCrossCrate::Yes, - "rustc_deprecated_safe_2024 is supposed to be used in libstd only", + "`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary", ), rustc_attr!( rustc_pub_transparent, Normal, template!(Word), @@ -695,7 +710,7 @@ pub struct BuiltinAttribute { ErrorFollowing, EncodeCrossCrate::No, "`rustc_never_type_options` is used to experiment with never type fallback and work on \ - never type stabilization, and will never be stable" + never type stabilization" ), // ========================================================================== @@ -704,23 +719,23 @@ pub struct BuiltinAttribute { rustc_attr!( rustc_allocator, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_nounwind, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_reallocator, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_deallocator, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, @@ -762,7 +777,7 @@ pub struct BuiltinAttribute { ), rustc_attr!( rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, INTERNAL_UNSTABLE + EncodeCrossCrate::No, ), // ========================================================================== @@ -772,11 +787,11 @@ pub struct BuiltinAttribute { rustc_attr!( rustc_builtin_macro, Normal, template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing, - EncodeCrossCrate::Yes, IMPL_DETAIL + EncodeCrossCrate::Yes, ), rustc_attr!( rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, INTERNAL_UNSTABLE + EncodeCrossCrate::No, ), rustc_attr!( rustc_macro_transparency, Normal, @@ -786,7 +801,7 @@ pub struct BuiltinAttribute { rustc_attr!( rustc_autodiff, Normal, template!(Word, List: r#""...""#), DuplicatesOk, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, ), // Traces that are left when `cfg` and `cfg_attr` attributes are expanded. // The attributes are not gated, to avoid stability errors, but they cannot be used in stable @@ -812,54 +827,53 @@ pub struct BuiltinAttribute { NameValueStr: "message" ), ErrorFollowing, EncodeCrossCrate::Yes, - INTERNAL_UNSTABLE + "see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute" ), rustc_attr!( rustc_confusables, Normal, template!(List: r#""name1", "name2", ..."#), ErrorFollowing, EncodeCrossCrate::Yes, - INTERNAL_UNSTABLE, ), // Enumerates "identity-like" conversion methods to suggest on type mismatch. rustc_attr!( rustc_conversion_suggestion, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Prevents field reads in the marked trait or method to be considered // during dead code analysis. rustc_attr!( rustc_trivial_field_reads, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::potential_query_instability` lint to warn methods which // might not be stable during incremental compilation. rustc_attr!( rustc_lint_query_instability, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::untracked_query_information` lint to warn methods which // might not be stable during incremental compilation. rustc_attr!( rustc_lint_untracked_query_information, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic // APIs. Any function with this attribute will be checked by that lint. rustc_attr!( rustc_lint_diagnostics, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions` // types (as well as any others in future). rustc_attr!( rustc_lint_opt_ty, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::bad_opt_access` lint on fields // types (as well as any others in future). rustc_attr!( rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // ========================================================================== @@ -868,28 +882,30 @@ pub struct BuiltinAttribute { rustc_attr!( rustc_promotable, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL), + EncodeCrossCrate::No, ), rustc_attr!( rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, ), // Do not const-check this function's body. It will always get replaced during CTFE. rustc_attr!( rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body", ), - // Ensure the argument to this function is &&str during const-check. rustc_attr!( rustc_const_panic_str, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, "`#[rustc_const_panic_str]` ensures the argument to this function is &&str during const-check", ), rustc_attr!( rustc_const_stable_indirect, Normal, - template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + template!(Word), + WarnFollowing, + EncodeCrossCrate::No, + "this is an internal implementation detail", ), rustc_attr!( rustc_intrinsic_const_stable_indirect, Normal, - template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail", ), gated!( rustc_allow_const_fn_unstable, Normal, @@ -905,21 +921,21 @@ pub struct BuiltinAttribute { rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ - niche optimizations in libcore and libstd and will never be stable", + niche optimizations in the standard library", ), rustc_attr!( rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ - niche optimizations in libcore and libstd and will never be stable", + niche optimizations in the standard library", ), rustc_attr!( rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \ - guaranteed niche optimizations in libcore and libstd and will never be stable\n\ - (note that the compiler does not even check whether the type indeed is being non-null-optimized; \ - it is your responsibility to ensure that the attribute is only used on types that are optimized)", + guaranteed niche optimizations in the standard library", + "the compiler does not even check whether the type indeed is being non-null-optimized; \ + it is your responsibility to ensure that the attribute is only used on types that are optimized", ), // ========================================================================== @@ -932,17 +948,17 @@ pub struct BuiltinAttribute { rustc_attr!( rustc_as_ptr, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations." + "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations." ), rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." + "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference." ), rustc_attr!( rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers." + "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers." ), rustc_attr!( rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, @@ -950,15 +966,15 @@ pub struct BuiltinAttribute { ), rustc_attr!( rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." + "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`." ), rustc_attr!( rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, - "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver." + "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver." ), rustc_attr!( rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." + "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl." ), rustc_attr!( rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, @@ -970,7 +986,7 @@ pub struct BuiltinAttribute { template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" + "`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls" ), rustc_attr!( rustc_do_not_implement_via_object, @@ -978,14 +994,14 @@ pub struct BuiltinAttribute { template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \ + "`#[rustc_do_not_implement_via_object]` opts out of the automatic trait impl for trait objects \ (`impl Trait for dyn Trait`)" ), rustc_attr!( rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ - the given type by annotating all impl items with #[rustc_allow_incoherent_impl]." + "`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \ + the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`." ), BuiltinAttribute { @@ -996,12 +1012,13 @@ pub struct BuiltinAttribute { safety: AttributeSafety::Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, - gate: Gated( - Stability::Unstable, - sym::rustc_attrs, - "diagnostic items compiler internal support for linting", - Features::rustc_attrs, - ), + gate: Gated{ + feature: sym::rustc_attrs, + message: "use of an internal attribute", + check: Features::rustc_attrs, + notes: &["the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types \ + from the standard library for diagnostic purposes"], + }, }, gated!( // Used in resolve: @@ -1015,14 +1032,14 @@ pub struct BuiltinAttribute { rustc_attr!( rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ - overflow checking behavior of several libcore functions that are inlined \ - across crates and will never be stable", + overflow checking behavior of several functions in the standard library that are inlined \ + across crates", ), rustc_attr!( rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_reservation_impl]` attribute is internally used \ - for reserving for `for<T> From<!> for T` impl" + for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`" ), rustc_attr!( rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing, @@ -1053,12 +1070,13 @@ pub struct BuiltinAttribute { rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing, EncodeCrossCrate::No, "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \ - definition of a trait, it's currently in experimental form and should be changed before \ - being exposed outside of the std" + definition of a trait. Its syntax and semantics are highly experimental and will be \ + subject to change before stabilization", ), rustc_attr!( rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing, - EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#, + EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \ + to provide a way to generate documentation for primitive types", ), gated!( rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, @@ -1066,11 +1084,11 @@ pub struct BuiltinAttribute { ), rustc_attr!( rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, - "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" + "`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen" ), rustc_attr!( rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, - "#[rustc_force_inline] forces a free function to be inlined" + "`#[rustc_force_inline]` forces a free function to be inlined" ), // ========================================================================== @@ -1209,10 +1227,6 @@ pub struct BuiltinAttribute { ), ]; -pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { - BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect() -} - pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() }
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 2576475..dbc0daa 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs
@@ -40,14 +40,6 @@ pub struct Feature { issue: Option<NonZero<u32>>, } -#[derive(Copy, Clone, Debug)] -pub enum Stability { - Unstable, - // First argument is tracking issue link; second argument is an optional - // help message, which defaults to "remove this attribute". - Deprecated(&'static str, Option<&'static str>), -} - #[derive(Clone, Copy, Debug, Hash)] pub enum UnstableFeatures { /// Disallow use of unstable features, as on beta/stable channels. @@ -144,9 +136,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u pub use accepted::ACCEPTED_LANG_FEATURES; pub use builtin_attrs::{ AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType, - BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes, - encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, - is_valid_for_get_attr, + BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate, + find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr, }; pub use removed::REMOVED_LANG_FEATURES; pub use unstable::{
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 9738f16..0cd090b 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs
@@ -263,6 +263,8 @@ macro_rules! declare_features { /// Allows unnamed fields of struct and union type (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign"), 131045), (removed, unsafe_no_drop_flag, "1.0.0", None, None), + /// Allows unsized rvalues at arguments and parameters. + (removed, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), Some("removed due to implementation concerns; see https://github.com/rust-lang/rust/issues/111942")), (removed, unsized_tuple_coercion, "1.87.0", Some(42877), Some("The feature restricts possible layouts for tuples, and this restriction is not worth it."), 137728), /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 594021d..bd6ea85 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs
@@ -353,6 +353,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), /// Allows `extern "C-cmse-nonsecure-call" fn()`. (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)), + /// Allows `extern "custom" fn()`. + (unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)), /// Allows `extern "gpu-kernel" fn()`. (unstable, abi_gpu_kernel, "1.86.0", Some(135467)), /// Allows `extern "msp430-interrupt" fn()`. @@ -665,8 +667,6 @@ pub fn internal(&self, feature: Symbol) -> bool { (incomplete, unsized_const_params, "1.82.0", Some(95174)), /// Allows unsized fn parameters. (internal, unsized_fn_params, "1.49.0", Some(48055)), - /// Allows unsized rvalues at arguments and parameters. - (incomplete, unsized_locals, "1.30.0", Some(48055)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), /// Allows use of attributes in `where` clauses.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6f288bb..556f50a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs
@@ -34,6 +34,7 @@ use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; +use crate::lints::DelayedLints; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] pub enum AngleBrackets { @@ -1526,6 +1527,10 @@ pub struct OwnerInfo<'hir> { /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. pub trait_map: ItemLocalMap<Box<[TraitCandidate]>>, + + /// Lints delayed during ast lowering to be emitted + /// after hir has completely built + pub delayed_lints: DelayedLints, } impl<'tcx> OwnerInfo<'tcx> { @@ -2280,12 +2285,23 @@ pub struct Expr<'hir> { } impl Expr<'_> { - pub fn precedence(&self) -> ExprPrecedence { + pub fn precedence( + &self, + for_each_attr: &dyn Fn(HirId, &mut dyn FnMut(&Attribute)), + ) -> ExprPrecedence { + let prefix_attrs_precedence = || -> ExprPrecedence { + let mut has_outer_attr = false; + for_each_attr(self.hir_id, &mut |attr: &Attribute| { + has_outer_attr |= matches!(attr.style(), AttrStyle::Outer) + }); + if has_outer_attr { ExprPrecedence::Prefix } else { ExprPrecedence::Unambiguous } + }; + match &self.kind { ExprKind::Closure(closure) => { match closure.fn_decl.output { FnRetTy::DefaultReturn(_) => ExprPrecedence::Jump, - FnRetTy::Return(_) => ExprPrecedence::Unambiguous, + FnRetTy::Return(_) => prefix_attrs_precedence(), } } @@ -2310,7 +2326,7 @@ pub fn precedence(&self) -> ExprPrecedence { | ExprKind::Let(..) | ExprKind::Unary(..) => ExprPrecedence::Prefix, - // Never need parens + // Need parens if and only if there are prefix attributes. ExprKind::Array(_) | ExprKind::Block(..) | ExprKind::Call(..) @@ -2332,9 +2348,9 @@ pub fn precedence(&self) -> ExprPrecedence { | ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) | ExprKind::Use(..) - | ExprKind::Err(_) => ExprPrecedence::Unambiguous, + | ExprKind::Err(_) => prefix_attrs_precedence(), - ExprKind::DropTemps(expr, ..) => expr.precedence(), + ExprKind::DropTemps(expr, ..) => expr.precedence(for_each_attr), } } @@ -3059,6 +3075,7 @@ pub struct TraitItem<'hir> { pub kind: TraitItemKind<'hir>, pub span: Span, pub defaultness: Defaultness, + pub has_delayed_lints: bool, } macro_rules! expect_methods_self_kind { @@ -3163,6 +3180,7 @@ pub struct ImplItem<'hir> { pub defaultness: Defaultness, pub span: Span, pub vis_span: Span, + pub has_delayed_lints: bool, } impl<'hir> ImplItem<'hir> { @@ -4082,6 +4100,7 @@ pub struct Item<'hir> { pub kind: ItemKind<'hir>, pub span: Span, pub vis_span: Span, + pub has_delayed_lints: bool, } impl<'hir> Item<'hir> { @@ -4487,6 +4506,7 @@ pub struct ForeignItem<'hir> { pub owner_id: OwnerId, pub span: Span, pub vis_span: Span, + pub has_delayed_lints: bool, } impl ForeignItem<'_> { @@ -4969,7 +4989,7 @@ mod size_asserts { static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 48); static_assert_size!(FnDecl<'_>, 40); - static_assert_size!(ForeignItem<'_>, 88); + static_assert_size!(ForeignItem<'_>, 96); static_assert_size!(ForeignItemKind<'_>, 56); static_assert_size!(GenericArg<'_>, 16); static_assert_size!(GenericBound<'_>, 64);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index bebac3a..57e4962 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs
@@ -537,7 +537,7 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result { - let Item { owner_id: _, kind, span: _, vis_span: _ } = item; + let Item { owner_id: _, kind, span: _, vis_span: _, has_delayed_lints: _ } = item; try_visit!(visitor.visit_id(item.hir_id())); match *kind { ItemKind::ExternCrate(orig_name, ident) => { @@ -656,7 +656,8 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( visitor: &mut V, foreign_item: &'v ForeignItem<'v>, ) -> V::Result { - let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _ } = foreign_item; + let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _, has_delayed_lints: _ } = + foreign_item; try_visit!(visitor.visit_id(foreign_item.hir_id())); try_visit!(visitor.visit_ident(*ident)); @@ -1205,7 +1206,15 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( visitor: &mut V, trait_item: &'v TraitItem<'v>, ) -> V::Result { - let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; + let TraitItem { + ident, + generics, + ref defaultness, + ref kind, + span, + owner_id: _, + has_delayed_lints: _, + } = *trait_item; let hir_id = trait_item.hir_id(); try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(&generics)); @@ -1261,6 +1270,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( ref defaultness, span: _, vis_span: _, + has_delayed_lints: _, } = *impl_item; try_visit!(visitor.visit_ident(ident));
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index c6fe475..dafd313 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs
@@ -27,6 +27,7 @@ pub mod hir_id; pub mod intravisit; pub mod lang_items; +pub mod lints; pub mod pat_util; mod stable_hash_impls; mod target;
diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs new file mode 100644 index 0000000..7be6c32 --- /dev/null +++ b/compiler/rustc_hir/src/lints.rs
@@ -0,0 +1,23 @@ +use rustc_attr_data_structures::lints::AttributeLint; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_macros::HashStable_Generic; + +use crate::HirId; + +/// During ast lowering, no lints can be emitted. +/// That is because lints attach to nodes either in the AST, or on the built HIR. +/// When attached to AST nodes, they're emitted just before building HIR, +/// and then there's a gap where no lints can be emitted until HIR is done. +/// The variants in this enum represent lints that are temporarily stashed during +/// AST lowering to be emitted once HIR is built. +#[derive(Clone, Debug, HashStable_Generic)] +pub enum DelayedLint { + AttributeParsing(AttributeLint<HirId>), +} + +#[derive(Debug)] +pub struct DelayedLints { + pub lints: Box<[DelayedLint]>, + // Only present when the crate hash is needed. + pub opt_hash: Option<Fingerprint>, +}
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 91ea88c..6acf152 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -6,6 +6,7 @@ AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, }; use crate::hir_id::{HirId, ItemLocalId}; +use crate::lints::DelayedLints; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro @@ -102,6 +103,13 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { } } +impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for DelayedLints { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let DelayedLints { opt_hash, .. } = *self; + opt_hash.unwrap().hash_stable(hcx, hasher); + } +} + impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { // We ignore the `map` since it refers to information included in `opt_hash` which is
diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 899370b..5d6c49e 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -14,6 +14,7 @@ rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 4fcd9f8..f768bd1 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -1,3 +1,7 @@ +hir_analysis_abi_custom_clothed_function = + items with the `"custom"` ABI can only be declared externally or defined via naked functions + .suggestion = convert this to an `#[unsafe(naked)]` function + hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}` .label = ambiguous associated {$assoc_kind} `{$assoc_ident}` @@ -595,7 +599,7 @@ .label = re-bound here .previous_bound_label = `{$item_name}` bound here first -hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} +hir_analysis_variadic_function_compatible_convention = C-variadic functions with the {$convention} calling convention are not supported .label = C-variadic function must have a compatible calling convention hir_analysis_variances_of = {$variances}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 60ca0155b..32fec06 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::Discr; use rustc_middle::ty::{ - AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, + AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; @@ -100,6 +100,18 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex } } +pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) { + if fn_sig.abi == ExternAbi::Custom { + // Function definitions that use `extern "custom"` must be naked functions. + if !tcx.has_attr(def_id, sym::naked) { + tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction { + span: fn_sig_span, + naked_span: tcx.def_span(def_id).shrink_to_lo(), + }); + } + } +} + fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 481cdaa..060fc51 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -71,7 +71,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::box_new | sym::breakpoint | sym::size_of - | sym::min_align_of + | sym::align_of | sym::needs_drop | sym::caller_location | sym::add_with_overflow @@ -200,10 +200,8 @@ pub(crate) fn check_intrinsic_type( sym::abort => (0, 0, vec![], tcx.types.never), sym::unreachable => (0, 0, vec![], tcx.types.never), sym::breakpoint => (0, 0, vec![], tcx.types.unit), - sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { - (1, 0, vec![], tcx.types.usize) - } - sym::size_of_val | sym::min_align_of_val => { + sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize), + sym::size_of_val | sym::align_of_val => { (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index fad8abf..c5c7e6b 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -72,7 +72,7 @@ use std::num::NonZero; -pub use check::{check_abi, check_abi_fn_ptr}; +pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi}; use rustc_abi::{ExternAbi, VariantIdx}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 7cb31a6..c458878 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Arm, Block, Expr, LetStmt, Pat, PatKind, Stmt}; @@ -752,13 +753,19 @@ fn record_rvalue_scope_if_borrow_expr<'tcx>( record_rvalue_scope_if_borrow_expr(visitor, arm.body, blk_id); } } - hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => { - // FIXME(@dingxiangfei2009): choose call arguments here - // for candidacy for extended parameter rule application - } - hir::ExprKind::Index(..) => { - // FIXME(@dingxiangfei2009): select the indices - // as candidate for rvalue scope rules + hir::ExprKind::Call(func, args) => { + // Recurse into tuple constructors, such as `Some(&temp())`. + // + // That way, there is no difference between `Some(..)` and `Some { 0: .. }`, + // even though the former is syntactically a function call. + if let hir::ExprKind::Path(path) = &func.kind + && let hir::QPath::Resolved(None, path) = path + && let Res::SelfCtor(_) | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) = path.res + { + for arg in args { + record_rvalue_scope_if_borrow_expr(visitor, arg, blk_id); + } + } } _ => {} }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e1df0d6..6e22ac5 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -494,7 +494,7 @@ 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_arg_ty(a, None) + self.lowerer().lower_ty(a) }) .collect();
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index b907ec0..f5821ae 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -276,8 +276,7 @@ fn create_generic_args<'tcx>( tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args; let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); - let method_args = - tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count)); + let method_args = tcx.mk_args(&trait_args[callee_generics.parent_count..]); let method_args = build_generic_args(tcx, sig_id, def_id, method_args); tcx.mk_args_from_iter(parent_args.iter().chain(method_args))
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a27d1ed..8de2aec 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -633,7 +633,7 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> { #[primary_span] #[label] pub span: Span, - pub conventions: &'a str, + pub convention: &'a str, } #[derive(Diagnostic)] @@ -1698,3 +1698,17 @@ pub(crate) struct SelfInTypeAlias { #[label] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_abi_custom_clothed_function)] +pub(crate) struct AbiCustomClothedFunction { + #[primary_span] + pub span: Span, + #[suggestion( + hir_analysis_suggestion, + applicability = "maybe-incorrect", + code = "#[unsafe(naked)]\n", + style = "short" + )] + pub naked_span: Span, +}
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 bdc42c7..106420f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -9,8 +9,8 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; use rustc_middle::ty::{ - self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, Upcast, + self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + TypeVisitor, Upcast, }; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::traits; @@ -927,7 +927,7 @@ struct GenericParamAndBoundVarCollector<'a, 'tcx> { impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> { type Result = ControlFlow<ErrorGuaranteed>; - fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>( + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( &mut self, binder: &ty::Binder<'tcx, T>, ) -> Self::Result {
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 4deb47d..bf407cb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2708,16 +2708,6 @@ fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { } } - pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> { - match ty.kind { - hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => { - self.record_ty(ty.hir_id, expected_ty, ty.span); - expected_ty - } - _ => self.lower_ty(ty), - } - } - /// Lower a function type from the HIR to our internal notion of a function signature. #[instrument(level = "debug", skip(self, hir_id, safety, abi, decl, generics, hir_ty), ret)] pub fn lower_fn_ty(
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index a92ee89..7c8c942 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -92,8 +92,9 @@ pub use errors::NoVariantNamed; use rustc_abi::ExternAbi; -use rustc_hir as hir; use rustc_hir::def::DefKind; +use rustc_hir::lints::DelayedLint; +use rustc_hir::{self as hir}; use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; @@ -114,12 +115,6 @@ fn require_c_abi_if_c_variadic( abi: ExternAbi, span: Span, ) { - const CONVENTIONS_UNSTABLE: &str = - "`C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`"; - const CONVENTIONS_STABLE: &str = "`C` or `cdecl`"; - const UNSTABLE_EXPLAIN: &str = - "using calling conventions other than `C` or `cdecl` for varargs functions is unstable"; - // ABIs which can stably use varargs if !decl.c_variadic || matches!(abi, ExternAbi::C { .. } | ExternAbi::Cdecl { .. }) { return; @@ -139,20 +134,18 @@ fn require_c_abi_if_c_variadic( // Looks like we need to pick an error to emit. // Is there any feature which we could have enabled to make this work? + let unstable_explain = + format!("C-variadic functions with the {abi} calling convention are unstable"); match abi { ExternAbi::System { .. } => { - feature_err(&tcx.sess, sym::extern_system_varargs, span, UNSTABLE_EXPLAIN) + feature_err(&tcx.sess, sym::extern_system_varargs, span, unstable_explain) } abi if abi.supports_varargs() => { - feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, UNSTABLE_EXPLAIN) + feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, unstable_explain) } _ => tcx.dcx().create_err(errors::VariadicFunctionCompatibleConvention { span, - conventions: if tcx.sess.opts.unstable_features.is_nightly_build() { - CONVENTIONS_UNSTABLE - } else { - CONVENTIONS_STABLE - }, + convention: &format!("{abi}"), }), } .emit(); @@ -174,6 +167,14 @@ pub fn provide(providers: &mut Providers) { }; } +fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { + match lint { + DelayedLint::AttributeParsing(attribute_lint) => { + rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + } + } +} + pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); @@ -192,6 +193,42 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); + tcx.sess.time("emit_ast_lowering_delayed_lints", || { + // sanity check in debug mode that all lints are really noticed + // and we really will emit them all in the loop right below. + // + // during ast lowering, when creating items, foreign items, trait items and impl items + // we store in them whether they have any lints in their owner node that should be + // picked up by `hir_crate_items`. However, theoretically code can run between that + // boolean being inserted into the item and the owner node being created. + // We don't want any new lints to be emitted there + // (though honestly, you have to really try to manage to do that but still), + // but this check is there to catch that. + #[cfg(debug_assertions)] + { + // iterate over all owners + for owner_id in tcx.hir_crate_items(()).owners() { + // if it has delayed lints + if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { + if !delayed_lints.lints.is_empty() { + // assert that delayed_lint_items also picked up this item to have lints + assert!( + tcx.hir_crate_items(()).delayed_lint_items().any(|i| i == owner_id) + ); + } + } + } + } + + for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { + if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { + for lint in &delayed_lints.lints { + emit_delayed_lint(lint, tcx); + } + } + } + }); + tcx.par_hir_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); // Make sure we evaluate all static and (non-associated) const items, even if unused.
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b23b312..fc50728 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -80,6 +80,13 @@ fn attrs(&self, id: HirId) -> &'a [hir::Attribute] { (self.attrs)(id) } + fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { + let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&hir::Attribute)| { + self.attrs(id).iter().for_each(callback); + }; + expr.precedence(&for_each_attr) + } + fn print_attrs_as_inner(&mut self, attrs: &[hir::Attribute]) { self.print_either_attributes(attrs, ast::AttrStyle::Inner) } @@ -1164,7 +1171,7 @@ fn print_let(&mut self, pat: &hir::Pat<'_>, ty: Option<&hir::Ty<'_>>, init: &hir } self.space(); self.word_space("="); - let npals = || parser::needs_par_as_let_scrutinee(init.precedence()); + let npals = || parser::needs_par_as_let_scrutinee(self.precedence(init)); self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals()) } @@ -1265,7 +1272,7 @@ fn print_expr_tup(&mut self, exprs: &[hir::Expr<'_>]) { fn print_expr_call(&mut self, func: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let needs_paren = match func.kind { hir::ExprKind::Field(..) => true, - _ => func.precedence() < ExprPrecedence::Unambiguous, + _ => self.precedence(func) < ExprPrecedence::Unambiguous, }; self.print_expr_cond_paren(func, needs_paren); @@ -1279,7 +1286,10 @@ fn print_expr_method_call( args: &[hir::Expr<'_>], ) { let base_args = args; - self.print_expr_cond_paren(receiver, receiver.precedence() < ExprPrecedence::Unambiguous); + self.print_expr_cond_paren( + receiver, + self.precedence(receiver) < ExprPrecedence::Unambiguous, + ); self.word("."); self.print_ident(segment.ident); @@ -1293,8 +1303,8 @@ fn print_expr_method_call( fn print_expr_binary(&mut self, op: hir::BinOpKind, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) { let binop_prec = op.precedence(); - let left_prec = lhs.precedence(); - let right_prec = rhs.precedence(); + let left_prec = self.precedence(lhs); + let right_prec = self.precedence(rhs); let (mut left_needs_paren, right_needs_paren) = match op.fixity() { Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec), @@ -1323,7 +1333,7 @@ fn print_expr_binary(&mut self, op: hir::BinOpKind, lhs: &hir::Expr<'_>, rhs: &h fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr<'_>) { self.word(op.as_str()); - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix); + self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix); } fn print_expr_addr_of( @@ -1340,7 +1350,7 @@ fn print_expr_addr_of( self.print_mutability(mutability, true); } } - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix); + self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix); } fn print_literal(&mut self, lit: &hir::Lit) { @@ -1483,7 +1493,7 @@ fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.print_literal(lit); } hir::ExprKind::Cast(expr, ty) => { - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Cast); + self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Cast); self.space(); self.word_space("as"); self.print_type(ty); @@ -1580,24 +1590,30 @@ fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.print_block(blk, cb, ib); } hir::ExprKind::Assign(lhs, rhs, _) => { - self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign); + self.print_expr_cond_paren(lhs, self.precedence(lhs) <= ExprPrecedence::Assign); self.space(); self.word_space("="); - self.print_expr_cond_paren(rhs, rhs.precedence() < ExprPrecedence::Assign); + self.print_expr_cond_paren(rhs, self.precedence(rhs) < ExprPrecedence::Assign); } hir::ExprKind::AssignOp(op, lhs, rhs) => { - self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign); + self.print_expr_cond_paren(lhs, self.precedence(lhs) <= ExprPrecedence::Assign); self.space(); self.word_space(op.node.as_str()); - self.print_expr_cond_paren(rhs, rhs.precedence() < ExprPrecedence::Assign); + self.print_expr_cond_paren(rhs, self.precedence(rhs) < ExprPrecedence::Assign); } hir::ExprKind::Field(expr, ident) => { - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Unambiguous); + self.print_expr_cond_paren( + expr, + self.precedence(expr) < ExprPrecedence::Unambiguous, + ); self.word("."); self.print_ident(ident); } hir::ExprKind::Index(expr, index, _) => { - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Unambiguous); + self.print_expr_cond_paren( + expr, + self.precedence(expr) < ExprPrecedence::Unambiguous, + ); self.word("["); self.print_expr(index); self.word("]"); @@ -1611,7 +1627,7 @@ fn print_expr(&mut self, expr: &hir::Expr<'_>) { } if let Some(expr) = opt_expr { self.space(); - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump); + self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump); } } hir::ExprKind::Continue(destination) => { @@ -1625,13 +1641,13 @@ fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.word("return"); if let Some(expr) = result { self.word(" "); - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump); + self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump); } } hir::ExprKind::Become(result) => { self.word("become"); self.word(" "); - self.print_expr_cond_paren(result, result.precedence() < ExprPrecedence::Jump); + self.print_expr_cond_paren(result, self.precedence(result) < ExprPrecedence::Jump); } hir::ExprKind::InlineAsm(asm) => { self.word("asm!"); @@ -1669,7 +1685,7 @@ fn print_expr(&mut self, expr: &hir::Expr<'_>) { } hir::ExprKind::Yield(expr, _) => { self.word_space("yield"); - self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump); + self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump); } hir::ExprKind::Err(_) => { self.popen();
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 3bdd1b4..ac7ff65 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -1,3 +1,7 @@ +hir_typeck_abi_custom_call = + functions with the `"custom"` ABI cannot be called + .note = an `extern "custom"` function can only be called from within inline assembly + hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function hir_typeck_add_return_type_add = try adding a return type
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d173fe7..80bff09 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,5 +1,6 @@ use std::iter; +use rustc_abi::ExternAbi; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; use rustc_hir::def::{self, CtorKind, Namespace, Res}; @@ -83,6 +84,7 @@ pub(crate) fn check_expr_call( while result.is_none() && autoderef.next().is_some() { result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } + self.check_call_custom_abi(autoderef.final_ty(false), call_expr.span); self.register_predicates(autoderef.into_obligations()); let output = match result { @@ -135,6 +137,22 @@ pub(crate) fn check_expr_call( output } + /// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`. + /// + /// These functions have a calling convention that is unknown to rust, hence it cannot generate + /// code for the call. The only way to execute such a function is via inline assembly. + fn check_call_custom_abi(&self, callee_ty: Ty<'tcx>, span: Span) { + let abi = match callee_ty.kind() { + ty::FnDef(def_id, _) => self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi, + ty::FnPtr(_, header) => header.abi, + _ => return, + }; + + if let ExternAbi::Custom = abi { + self.tcx.dcx().emit_err(errors::AbiCustomCall { span }); + } + } + #[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)] fn try_overloaded_call_step( &self, @@ -602,7 +620,7 @@ fn suggest_call_as_method( }; if let Ok(rest_snippet) = rest_snippet { - let sugg = if callee_expr.precedence() >= ExprPrecedence::Unambiguous { + let sugg = if self.precedence(callee_expr) >= ExprPrecedence::Unambiguous { vec![ (up_to_rcvr_span, "".to_string()), (rest_span, format!(".{}({rest_snippet}", segment.ident)),
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index e17cfc1..6f8abc1 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -1100,7 +1100,7 @@ fn err_if_cenum_impl_drop(&self, fcx: &FnCtxt<'a, 'tcx>) { } fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) { - let expr_prec = self.expr.precedence(); + let expr_prec = fcx.precedence(self.expr); let needs_parens = expr_prec < ExprPrecedence::Unambiguous; let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index d9fa56f..24092c0 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1662,9 +1662,7 @@ pub(crate) fn coerce_inner<'a>( blk_id, expression, ); - if !fcx.tcx.features().unsized_locals() { - unsized_return = self.is_return_ty_definitely_unsized(fcx); - } + unsized_return = self.is_return_ty_definitely_unsized(fcx); } ObligationCauseCode::ReturnValue(return_expr_id) => { err = self.report_return_mismatched_types( @@ -1676,9 +1674,7 @@ pub(crate) fn coerce_inner<'a>( return_expr_id, expression, ); - if !fcx.tcx.features().unsized_locals() { - unsized_return = self.is_return_ty_definitely_unsized(fcx); - } + unsized_return = self.is_return_ty_definitely_unsized(fcx); } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { arm_span,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 7748150..abb8cdc 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -1163,3 +1163,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm { #[label] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_abi_custom_call)] +pub(crate) struct AbiCustomCall { + #[primary_span] + pub span: Span, +}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index dfc7935..55c39d9 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -5,7 +5,8 @@ //! //! See [`rustc_hir_analysis::check`] for more context on type checking in general. -use rustc_abi::{FIRST_VARIANT, FieldIdx}; +use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx}; +use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; @@ -17,7 +18,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, HirId, QPath}; +use rustc_hir::{Attribute, ExprKind, HirId, QPath}; use rustc_hir_analysis::NoVariantNamed; use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _}; use rustc_infer::infer; @@ -54,6 +55,30 @@ }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { + let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&Attribute)| { + for attr in self.tcx.hir_attrs(id) { + // For the purpose of rendering suggestions, disregard attributes + // that originate from desugaring of any kind. For example, `x?` + // desugars to `#[allow(unreachable_code)] match ...`. Failing to + // ignore the prefix attribute in the desugaring would cause this + // suggestion: + // + // let y: u32 = x?.try_into().unwrap(); + // ++++++++++++++++++++ + // + // to be rendered as: + // + // let y: u32 = (x?).try_into().unwrap(); + // + +++++++++++++++++++++ + if attr.span().desugaring_kind().is_none() { + callback(attr); + } + } + }; + expr.precedence(&for_each_attr) + } + /// Check an expr with an expectation type, and also demand that the expr's /// evaluated type is a subtype of the expectation at the end. This is a /// *hard* requirement. @@ -809,9 +834,8 @@ pub(crate) fn check_expr_path( ); } } - // Here we want to prevent struct constructors from returning unsized types. - // There were two cases this happened: fn pointer coercion in stable - // and usual function call in presence of unsized_locals. + // Here we want to prevent struct constructors from returning unsized types, + // which can happen with fn pointer coercion on stable. // Also, as we just want to check sizedness, instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. @@ -1627,6 +1651,14 @@ fn check_expr_method_call( Some(method.def_id), ); + // Functions of type `extern "custom" fn(/* ... */)` cannot be called using + // `ExprKind::MethodCall`. These functions have a calling convention that is + // unknown to rust, hence it cannot generate code for the call. The only way + // to execute such a function is via inline assembly. + if let ExternAbi::Custom = method.sig.abi { + self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span }); + } + method.sig.output() } Err(error) => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 7f1f3c3..e4c62bf 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -120,15 +120,7 @@ fn config(&self) -> InspectConfig { fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) { // No need to walk into goal subtrees that certainly hold, since they // wouldn't then be stalled on an infer var. - // FIXME: We also walk into normalizes-to goals since their certainty - // is forced to `Certainty::Yes` since they pass down ambiguous subgoals - // to their parent. - if inspect_goal.result() == Ok(Certainty::Yes) - && !matches!( - inspect_goal.goal().predicate.kind().skip_binder(), - ty::PredicateKind::NormalizesTo(_) - ) - { + if inspect_goal.result() == Ok(Certainty::Yes) { return; }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 3935569..e979798 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -382,7 +382,7 @@ fn lower_fn_sig( _hir_id: rustc_hir::HirId, _hir_ty: Option<&hir::Ty<'_>>, ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { - let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect(); + let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect(); let output_ty = match decl.output { hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 66af085..7e5f1d9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -399,7 +399,7 @@ pub(crate) fn suggest_deref_ref_or_into( // so we remove the user's `clone` call. { vec![(receiver_method.ident.span, conversion_method_name.to_string())] - } else if expr.precedence() < ExprPrecedence::Unambiguous { + } else if self.precedence(expr) < ExprPrecedence::Unambiguous { vec![ (expr.span.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)), @@ -1395,7 +1395,7 @@ pub(crate) fn suggest_into( { let span = expr.span.find_oldest_ancestor_in_same_ctxt(); - let mut sugg = if expr.precedence() >= ExprPrecedence::Unambiguous { + let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous { vec![(span.shrink_to_hi(), ".into()".to_owned())] } else { vec![ @@ -3106,7 +3106,7 @@ pub(crate) fn suggest_cast( "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`", ); - let close_paren = if expr.precedence() < ExprPrecedence::Unambiguous { + let close_paren = if self.precedence(expr) < ExprPrecedence::Unambiguous { sugg.push((expr.span.shrink_to_lo(), "(".to_string())); ")" } else { @@ -3131,7 +3131,7 @@ pub(crate) fn suggest_cast( let len = src.trim_end_matches(&checked_ty.to_string()).len(); span.with_lo(span.lo() + BytePos(len as u32)) }, - if expr.precedence() < ExprPrecedence::Unambiguous { + if self.precedence(expr) < ExprPrecedence::Unambiguous { // Readd `)` format!("{expected_ty})") } else {
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 7d99b0e..f1d6476 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -202,7 +202,7 @@ fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { ), ); } - } else if !self.fcx.tcx.features().unsized_locals() { + } else { self.fcx.require_type_is_sized( var_ty, p.span,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index a45a771..043a687 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -48,7 +48,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, HirIdMap, Node}; -use rustc_hir_analysis::check::check_abi; +use rustc_hir_analysis::check::{check_abi, check_custom_abi}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; use rustc_middle::query::Providers; @@ -138,7 +138,7 @@ fn typeck_with_inspect<'tcx>( // for visit the asm expr of the body. let ty = fcx.check_expr(body.value); fcx.write_ty(id, ty); - } else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { + } else if let Some(hir::FnSig { header, decl, span: fn_sig_span }) = node.fn_sig() { let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() { // In the case that we're recovering `fn() -> W<_>` or some other return // type that has an infer in it, lower the type directly so that it'll @@ -150,6 +150,8 @@ fn typeck_with_inspect<'tcx>( }; check_abi(tcx, id, span, fn_sig.abi()); + check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span); + loops::check(tcx, def_id, body); // Compute the function signature from point of view of inside the fn.
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 2fac13b..288d915 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -14,7 +14,9 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err}; +use rustc_errors::{ + Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err, +}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -722,7 +724,7 @@ fn report_no_match_method_error( { let def_path = tcx.def_path_str(adt_def.did()); err.span_suggestion( - ty.span.to(item_ident.span), + sugg_span, format!("to construct a value of type `{}`, use the explicit path", def_path), def_path, Applicability::MachineApplicable, @@ -1569,7 +1571,11 @@ fn report_no_match_method_error( ); } - if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive { + if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() + || restrict_type_params + || suggested_derive + || self.lookup_alternative_tuple_impls(&mut err, &unsatisfied_predicates) + { } else { self.suggest_traits_to_import( &mut err, @@ -1744,6 +1750,119 @@ fn report_no_match_method_error( err.emit() } + /// If the predicate failure is caused by an unmet bound on a tuple, recheck if the bound would + /// succeed if all the types on the tuple had no borrows. This is a common problem for libraries + /// like Bevy and ORMs, which rely heavily on traits being implemented on tuples. + fn lookup_alternative_tuple_impls( + &self, + err: &mut Diag<'_>, + unsatisfied_predicates: &[( + ty::Predicate<'tcx>, + Option<ty::Predicate<'tcx>>, + Option<ObligationCause<'tcx>>, + )], + ) -> bool { + let mut found_tuple = false; + for (pred, root, _ob) in unsatisfied_predicates { + let mut preds = vec![pred]; + if let Some(root) = root { + // We will look at both the current predicate and the root predicate that caused it + // to be needed. If calling something like `<(A, &B)>::default()`, then `pred` is + // `&B: Default` and `root` is `(A, &B): Default`, which is the one we are checking + // for further down, so we check both. + preds.push(root); + } + for pred in preds { + if let Some(clause) = pred.as_clause() + && let Some(clause) = clause.as_trait_clause() + && let ty = clause.self_ty().skip_binder() + && let ty::Tuple(types) = ty.kind() + { + let path = clause.skip_binder().trait_ref.print_only_trait_path(); + let def_id = clause.def_id(); + let ty = Ty::new_tup( + self.tcx, + self.tcx.mk_type_list_from_iter(types.iter().map(|ty| ty.peel_refs())), + ); + let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| { + if param.index == 0 { + ty.into() + } else { + self.infcx.var_for_def(DUMMY_SP, param) + } + }); + if self + .infcx + .type_implements_trait(def_id, args, self.param_env) + .must_apply_modulo_regions() + { + // "`Trait` is implemented for `(A, B)` but not for `(A, &B)`" + let mut msg = DiagStyledString::normal(format!("`{path}` ")); + msg.push_highlighted("is"); + msg.push_normal(" implemented for `("); + let len = types.len(); + for (i, t) in types.iter().enumerate() { + msg.push( + format!("{}", with_forced_trimmed_paths!(t.peel_refs())), + t.peel_refs() != t, + ); + if i < len - 1 { + msg.push_normal(", "); + } + } + msg.push_normal(")` but "); + msg.push_highlighted("not"); + msg.push_normal(" for `("); + for (i, t) in types.iter().enumerate() { + msg.push( + format!("{}", with_forced_trimmed_paths!(t)), + t.peel_refs() != t, + ); + if i < len - 1 { + msg.push_normal(", "); + } + } + msg.push_normal(")`"); + + // Find the span corresponding to the impl that was found to point at it. + if let Some(impl_span) = self + .tcx + .all_impls(def_id) + .filter(|&impl_def_id| { + let header = self.tcx.impl_trait_header(impl_def_id).unwrap(); + let trait_ref = header.trait_ref.instantiate( + self.tcx, + self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id), + ); + + let value = ty::fold_regions(self.tcx, ty, |_, _| { + self.tcx.lifetimes.re_erased + }); + // FIXME: Don't bother dealing with non-lifetime binders here... + if value.has_escaping_bound_vars() { + return false; + } + self.infcx.can_eq(ty::ParamEnv::empty(), trait_ref.self_ty(), value) + && header.polarity == ty::ImplPolarity::Positive + }) + .map(|impl_def_id| self.tcx.def_span(impl_def_id)) + .next() + { + err.highlighted_span_note(impl_span, msg.0); + } else { + err.highlighted_note(msg.0); + } + found_tuple = true; + } + // If `pred` was already on the tuple, we don't need to look at the root + // obligation too. + break; + } + } + } + found_tuple + } + /// If an appropriate error source is not found, check method chain for possible candidates fn lookup_segments_chain_for_no_match_method( &self,
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 5b5253c..982cfa2 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -492,7 +492,7 @@ fn analyze_closure( let final_upvar_tys = self.final_upvar_tys(closure_def_id); debug!(?closure_hir_id, ?args, ?final_upvar_tys); - if self.tcx.features().unsized_locals() || self.tcx.features().unsized_fn_params() { + if self.tcx.features().unsized_fn_params() { for capture in self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id) {
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 99520a3..02d1ebd 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs
@@ -8,9 +8,9 @@ use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; -use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal}; +use rustc_data_structures::{parallel, thousands}; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; @@ -18,6 +18,7 @@ use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store}; +use rustc_metadata::EncodedMetadata; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepsType; @@ -35,7 +36,8 @@ use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; use rustc_span::{ - DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, + DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, + Symbol, sym, }; use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; @@ -205,7 +207,7 @@ fn configure_and_expand( // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); - // The rest is error reporting + // The rest is error reporting and stats sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| { buffered_lints.append(&mut ecx.buffered_early_lint); @@ -228,6 +230,10 @@ fn configure_and_expand( } } + if ecx.sess.opts.unstable_opts.macro_stats { + print_macro_stats(&ecx); + } + krate }); @@ -288,6 +294,76 @@ fn configure_and_expand( krate } +fn print_macro_stats(ecx: &ExtCtxt<'_>) { + use std::fmt::Write; + + // No instability because we immediately sort the produced vector. + #[allow(rustc::potential_query_instability)] + let mut macro_stats: Vec<_> = ecx + .macro_stats + .iter() + .map(|((name, kind), stat)| { + // This gives the desired sort order: sort by bytes, then lines, etc. + (stat.bytes, stat.lines, stat.uses, name, *kind) + }) + .collect(); + macro_stats.sort_unstable(); + macro_stats.reverse(); // bigger items first + + let prefix = "macro-stats"; + let name_w = 32; + let uses_w = 7; + let lines_w = 11; + let avg_lines_w = 11; + let bytes_w = 11; + let avg_bytes_w = 11; + let banner_w = name_w + uses_w + lines_w + avg_lines_w + bytes_w + avg_bytes_w; + + // We write all the text into a string and print it with a single + // `eprint!`. This is an attempt to minimize interleaved text if multiple + // rustc processes are printing macro-stats at the same time (e.g. with + // `RUSTFLAGS='-Zmacro-stats' cargo build`). It still doesn't guarantee + // non-interleaving, though. + let mut s = String::new(); + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", ecx.ecfg.crate_name); + _ = writeln!( + s, + "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", + "Macro Name", "Uses", "Lines", "Avg Lines", "Bytes", "Avg Bytes", + ); + _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w)); + // It's helpful to print something when there are no entries, otherwise it + // might look like something went wrong. + if macro_stats.is_empty() { + _ = writeln!(s, "{prefix} (none)"); + } + for (bytes, lines, uses, name, kind) in macro_stats { + let mut name = ExpnKind::Macro(kind, *name).descr(); + let avg_lines = lines as f64 / uses as f64; + let avg_bytes = bytes as f64 / uses as f64; + if name.len() >= name_w { + // If the name is long, print it on a line by itself, then + // set the name to empty and print things normally, to show the + // stats on the next line. + _ = writeln!(s, "{prefix} {:<name_w$}", name); + name = String::new(); + } + _ = writeln!( + s, + "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", + name, + thousands::usize_with_underscores(uses), + thousands::isize_with_underscores(lines), + thousands::f64p1_with_underscores(avg_lines), + thousands::isize_with_underscores(bytes), + thousands::f64p1_with_underscores(avg_bytes), + ); + } + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + eprint!("{s}"); +} + fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let sess = tcx.sess; let (resolver, krate) = &*tcx.resolver_for_lowering().borrow(); @@ -1099,7 +1175,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { pub(crate) fn start_codegen<'tcx>( codegen_backend: &dyn CodegenBackend, tcx: TyCtxt<'tcx>, -) -> Box<dyn Any> { +) -> (Box<dyn Any>, EncodedMetadata) { // Hook for tests. if let Some((def_id, _)) = tcx.entry_fn(()) && tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query) @@ -1122,11 +1198,9 @@ pub(crate) fn start_codegen<'tcx>( info!("Pre-codegen\n{:?}", tcx.debug_stats()); - let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx); + let metadata = rustc_metadata::fs::encode_and_write_metadata(tcx); - let codegen = tcx.sess.time("codegen_crate", move || { - codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) - }); + let codegen = tcx.sess.time("codegen_crate", move || codegen_backend.codegen_crate(tcx)); info!("Post-codegen\n{:?}", tcx.debug_stats()); @@ -1136,7 +1210,7 @@ pub(crate) fn start_codegen<'tcx>( tcx.sess.code_stats.print_type_sizes(); } - codegen + (codegen, metadata) } /// Compute and validate the crate name.
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index c8914c9..9a474b9 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs
@@ -5,6 +5,7 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::svh::Svh; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -18,6 +19,7 @@ pub struct Linker { output_filenames: Arc<OutputFilenames>, // Only present when incr. comp. is enabled. crate_hash: Option<Svh>, + metadata: EncodedMetadata, ongoing_codegen: Box<dyn Any>, } @@ -26,7 +28,7 @@ pub fn codegen_and_build_linker( tcx: TyCtxt<'_>, codegen_backend: &dyn CodegenBackend, ) -> Linker { - let ongoing_codegen = passes::start_codegen(codegen_backend, tcx); + let (ongoing_codegen, metadata) = passes::start_codegen(codegen_backend, tcx); Linker { dep_graph: tcx.dep_graph.clone(), @@ -36,6 +38,7 @@ pub fn codegen_and_build_linker( } else { None }, + metadata, ongoing_codegen, } } @@ -75,6 +78,7 @@ pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) { sess, &rlink_file, &codegen_results, + &self.metadata, &*self.output_filenames, ) .unwrap_or_else(|error| { @@ -84,6 +88,6 @@ pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) { } let _timer = sess.prof.verbose_generic_activity("link_crate"); - codegen_backend.link(sess, codegen_results, &self.output_filenames) + codegen_backend.link(sess, codegen_results, self.metadata, &self.output_filenames) } }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 558f13a..8282358 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs
@@ -27,7 +27,7 @@ use rustc_span::{FileName, SourceFileHashAlgorithm, sym}; use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, - RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, }; use crate::interface::{initialize_checked_jobserver, parse_cfg}; @@ -709,6 +709,7 @@ macro_rules! untracked { untracked!(llvm_time_trace, true); untracked!(ls, vec!["all".to_owned()]); untracked!(macro_backtrace, true); + untracked!(macro_stats, true); untracked!(meta_stats, true); untracked!(mir_include_spans, MirIncludeSpans::On); untracked!(nll_facts, true); @@ -881,7 +882,6 @@ macro_rules! tracked { tracked!(verify_llvm_ir, true); tracked!(virtual_function_elimination, true); tracked!(wasi_exec_model, Some(WasiExecModel::Reactor)); - tracked!(wasm_c_abi, WasmCAbi::Spec); // tidy-alphabetical-end macro_rules! tracked_no_crate_hash {
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fd2e2ba..46ae414 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl
@@ -72,9 +72,6 @@ lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function lint_builtin_decl_unsafe_method = declaration of an `unsafe` method -lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} - .msg_suggestion = {$msg} - .default_suggestion = remove this attribute lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed @@ -533,8 +530,6 @@ lint_mismatched_lifetime_syntaxes_suggestion_mixed = one option is to remove the lifetime for references and use the anonymous lifetime for paths -lint_missing_fragment_specifier = missing fragment specifier - lint_missing_unsafe_on_extern = extern blocks should be unsafe .suggestion = needs `unsafe` before the extern keyword
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 69e9f8e..dedea54 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs
@@ -22,7 +22,7 @@ use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::expr_to_string; use rustc_errors::{Applicability, LintDiagnostic}; -use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes}; +use rustc_feature::GateIssue; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -48,8 +48,7 @@ use crate::errors::BuiltinEllipsisInclusiveRangePatterns; use crate::lints::{ - BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, - BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations, + BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDerefNullptr, BuiltinDoubleNegations, BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, @@ -799,53 +798,6 @@ fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { } } -/// Check for use of attributes which have been deprecated. -#[derive(Clone)] -pub struct DeprecatedAttr { - // This is not free to compute, so we want to keep it around, rather than - // compute it for every attribute. - depr_attrs: Vec<&'static BuiltinAttribute>, -} - -impl_lint_pass!(DeprecatedAttr => []); - -impl Default for DeprecatedAttr { - fn default() -> Self { - DeprecatedAttr { depr_attrs: deprecated_attributes() } - } -} - -impl EarlyLintPass for DeprecatedAttr { - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { - for BuiltinAttribute { name, gate, .. } in &self.depr_attrs { - if attr.ident().map(|ident| ident.name) == Some(*name) { - if let &AttributeGate::Gated( - Stability::Deprecated(link, suggestion), - name, - reason, - _, - ) = gate - { - let suggestion = match suggestion { - Some(msg) => { - BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg } - } - None => { - BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span } - } - }; - cx.emit_span_lint( - DEPRECATED, - attr.span, - BuiltinDeprecatedAttrLink { name, reason, link, suggestion }, - ); - } - return; - } - } - } -} - fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) { use rustc_ast::token::CommentKind;
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5679d45..b6bf45d 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs
@@ -7,6 +7,7 @@ use std::slice; use rustc_ast::BindingMode; +use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; @@ -850,6 +851,20 @@ pub fn get_associated_type( }) } + /// Returns the effective precedence of an expression for the purpose of + /// rendering diagnostic. This is not the same as the precedence that would + /// be used for pretty-printing HIR by rustc_hir_pretty. + pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { + let for_each_attr = |id: hir::HirId, callback: &mut dyn FnMut(&hir::Attribute)| { + for attr in self.tcx.hir_attrs(id) { + if attr.span().desugaring_kind().is_none() { + callback(attr); + } + } + }; + expr.precedence(&for_each_attr) + } + /// If the given expression is a local binding, find the initializer expression. /// If that initializer expression is another local binding, find its initializer again. ///
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 12666d3..48e3bbb 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs
@@ -33,10 +33,8 @@ pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> { } impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { - // This always-inlined function is for the hot call site. - #[inline(always)] #[allow(rustc::diagnostic_outside_of_impl)] - fn inlined_check_id(&mut self, id: ast::NodeId) { + fn check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; self.context.opt_span_lint(lint_id.lint, span, |diag| { @@ -45,11 +43,6 @@ fn inlined_check_id(&mut self, id: ast::NodeId) { } } - // This non-inlined function is for the cold call sites. - fn check_id(&mut self, id: ast::NodeId) { - self.inlined_check_id(id) - } - /// Merge the lints specified by any lint attributes into the /// current lint context, call the provided function, then reset the /// lints in effect to their previous state. @@ -61,7 +54,6 @@ fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'_ [ast::Attribute], f debug!(?id); let push = self.context.builder.push(attrs, is_crate_node, None); - self.inlined_check_id(id); debug!("early context: enter_attrs({:?})", attrs); lint_callback!(self, check_attributes, attrs); ensure_sufficient_stack(|| f(self)); @@ -136,12 +128,8 @@ fn visit_stmt(&mut self, s: &'ast ast::Stmt) { // the AST struct that they wrap (e.g. an item) self.with_lint_attrs(s.id, s.attrs(), |cx| { lint_callback!(cx, check_stmt, s); + ast_visit::walk_stmt(cx, s); }); - // The visitor for the AST struct wrapped - // by the statement (e.g. `Item`) will call - // `with_lint_attrs`, so do this walk - // outside of the above `with_lint_attrs` call - ast_visit::walk_stmt(self, s); } fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, span: Span, id: ast::NodeId) {
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 60c477d..3b0a361 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -432,9 +432,6 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::CfgAttrNoAttributes => { lints::CfgAttrNoAttributes.decorate_lint(diag); } - BuiltinLintDiag::MissingFragmentSpecifier => { - lints::MissingFragmentSpecifier.decorate_lint(diag); - } BuiltinLintDiag::MetaVariableStillRepeating(name) => { lints::MetaVariableStillRepeating { name }.decorate_lint(diag); }
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 8124d7f..aa6f36a 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -15,8 +15,7 @@ Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; @@ -210,7 +209,7 @@ impl<'tcx, VarFn, OutlivesFn> TypeVisitor<TyCtxt<'tcx>> VarFn: FnOnce() -> FxHashMap<DefId, ty::Variance>, OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>, { - fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) { + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) { // When we get into a binder, we need to add its own bound vars to the scope. let mut added = vec![]; for arg in t.bound_vars() {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 72bfead..9a1490d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs
@@ -174,7 +174,6 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, - DeprecatedAttr: DeprecatedAttr::default(), WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, IncompleteInternalFeatures: IncompleteInternalFeatures, @@ -619,6 +618,12 @@ macro_rules! add_lint_group { "converted into hard error, \ see <https://github.com/rust-lang/rust/issues/116558> for more information", ); + store.register_removed( + "missing_fragment_specifier", + "converted into hard error, \ + see <https://github.com/rust-lang/rust/issues/40107> for more information", + ); + store.register_removed("wasm_c_abi", "the wasm C ABI has been fixed"); } fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 31b038e..95b7b69 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -84,19 +84,45 @@ fn check_fn( _: rustc_span::Span, _: rustc_span::def_id::LocalDefId, ) { - let mut input_map = Default::default(); - let mut output_map = Default::default(); - - for input in fd.inputs { - LifetimeInfoCollector::collect(input, &mut input_map); - } - - if let hir::FnRetTy::Return(output) = fd.output { - LifetimeInfoCollector::collect(output, &mut output_map); - } - - report_mismatches(cx, &input_map, &output_map); + check_fn_like(cx, fd); } + + #[instrument(skip_all)] + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, ti: &'tcx hir::TraitItem<'tcx>) { + match ti.kind { + hir::TraitItemKind::Const(..) => {} + hir::TraitItemKind::Fn(fn_sig, _trait_fn) => check_fn_like(cx, fn_sig.decl), + hir::TraitItemKind::Type(..) => {} + } + } + + #[instrument(skip_all)] + fn check_foreign_item( + &mut self, + cx: &LateContext<'tcx>, + fi: &'tcx rustc_hir::ForeignItem<'tcx>, + ) { + match fi.kind { + hir::ForeignItemKind::Fn(fn_sig, _idents, _generics) => check_fn_like(cx, fn_sig.decl), + hir::ForeignItemKind::Static(..) => {} + hir::ForeignItemKind::Type => {} + } + } +} + +fn check_fn_like<'tcx>(cx: &LateContext<'tcx>, fd: &'tcx hir::FnDecl<'tcx>) { + let mut input_map = Default::default(); + let mut output_map = Default::default(); + + for input in fd.inputs { + LifetimeInfoCollector::collect(input, &mut input_map); + } + + if let hir::FnRetTy::Return(output) = fd.output { + LifetimeInfoCollector::collect(output, &mut output_map); + } + + report_mismatches(cx, &input_map, &output_map); } #[instrument(skip_all)]
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 9d3c74a..3d17dfb 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs
@@ -199,32 +199,6 @@ pub(crate) struct BuiltinAnonymousParams<'a> { pub ty_snip: &'a str, } -// FIXME(davidtwco) translatable deprecated attr -#[derive(LintDiagnostic)] -#[diag(lint_builtin_deprecated_attr_link)] -pub(crate) struct BuiltinDeprecatedAttrLink<'a> { - pub name: Symbol, - pub reason: &'a str, - pub link: &'a str, - #[subdiagnostic] - pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum BuiltinDeprecatedAttrLinkSuggestion<'a> { - #[suggestion(lint_msg_suggestion, code = "", applicability = "machine-applicable")] - Msg { - #[primary_span] - suggestion: Span, - msg: &'a str, - }, - #[suggestion(lint_default_suggestion, code = "", applicability = "machine-applicable")] - Default { - #[primary_span] - suggestion: Span, - }, -} - #[derive(LintDiagnostic)] #[diag(lint_builtin_unused_doc_comment)] pub(crate) struct BuiltinUnusedDocComment<'a> { @@ -2617,10 +2591,6 @@ fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { pub(crate) struct CfgAttrNoAttributes; #[derive(LintDiagnostic)] -#[diag(lint_missing_fragment_specifier)] -pub(crate) struct MissingFragmentSpecifier; - -#[derive(LintDiagnostic)] #[diag(lint_metavariable_still_repeating)] pub(crate) struct MetaVariableStillRepeating { pub name: MacroRulesNormalizedIdent,
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 31c1807..1b60466 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -164,7 +164,7 @@ fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, true), + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) );
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fec2335..aaba0c1 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs
@@ -196,7 +196,8 @@ /// same address after being merged together. UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS, Warn, - "detects unpredictable function pointer comparisons" + "detects unpredictable function pointer comparisons", + report_in_external_macro } #[derive(Copy, Clone, Default)]
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 777118e..b0ea968 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -65,7 +65,6 @@ MACRO_USE_EXTERN_CRATE, META_VARIABLE_MISUSE, MISSING_ABI, - MISSING_FRAGMENT_SPECIFIER, MISSING_UNSAFE_ON_EXTERN, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, @@ -141,7 +140,6 @@ UNUSED_VARIABLES, USELESS_DEPRECATED, WARNINGS, - WASM_C_ABI, // tidy-alphabetical-end ] } @@ -1418,51 +1416,6 @@ } declare_lint! { - /// The `missing_fragment_specifier` lint is issued when an unused pattern in a - /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not - /// followed by a fragment specifier (e.g. `:expr`). - /// - /// This warning can always be fixed by removing the unused pattern in the - /// `macro_rules!` macro definition. - /// - /// ### Example - /// - /// ```rust,compile_fail,edition2021 - /// macro_rules! foo { - /// () => {}; - /// ($name) => { }; - /// } - /// - /// fn main() { - /// foo!(); - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// To fix this, remove the unused pattern from the `macro_rules!` macro definition: - /// - /// ```rust - /// macro_rules! foo { - /// () => {}; - /// } - /// fn main() { - /// foo!(); - /// } - /// ``` - pub MISSING_FRAGMENT_SPECIFIER, - Deny, - "detects missing fragment specifiers in unused `macro_rules!` patterns", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>", - report_in_deps: true, - }; -} - -declare_lint! { /// The `late_bound_lifetime_arguments` lint detects generic lifetime /// arguments in path segments with late bound lifetime parameters. /// @@ -3664,7 +3617,7 @@ "use of unsupported calling convention", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, - report_in_deps: true, + report_in_deps: false, reference: "issue #137018 <https://github.com/rust-lang/rust/issues/137018>", }; } @@ -4146,6 +4099,7 @@ @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(Edition::Edition2024), reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>", + report_in_deps: true, }; @edition Edition2024 => Deny; report_in_external_macro @@ -4200,6 +4154,7 @@ @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::EditionAndFutureReleaseError(Edition::Edition2024), reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>", + report_in_deps: true, }; report_in_external_macro } @@ -5027,50 +4982,6 @@ } declare_lint! { - /// The `wasm_c_abi` lint detects usage of the `extern "C"` ABI of wasm that is affected - /// by a planned ABI change that has the goal of aligning Rust with the standard C ABI - /// of this target. - /// - /// ### Example - /// - /// ```rust,ignore (needs wasm32-unknown-unknown) - /// #[repr(C)] - /// struct MyType(i32, i32); - /// - /// extern "C" my_fun(x: MyType) {} - /// ``` - /// - /// This will produce: - /// - /// ```text - /// error: this function function definition is affected by the wasm ABI transition: it passes an argument of non-scalar type `MyType` - /// --> $DIR/wasm_c_abi_transition.rs:17:1 - /// | - /// | pub extern "C" fn my_fun(_x: MyType) {} - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// | - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762> - /// = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target - /// ``` - /// - /// ### Explanation - /// - /// Rust has historically implemented a non-spec-compliant C ABI on wasm32-unknown-unknown. This - /// has caused incompatibilities with other compilers and Wasm targets. In a future version - /// of Rust, this will be fixed, and therefore code relying on the non-spec-compliant C ABI will - /// stop functioning. - pub WASM_C_ABI, - Warn, - "detects code relying on rustc's non-spec-compliant wasm C ABI", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #138762 <https://github.com/rust-lang/rust/issues/138762>", - report_in_deps: true, - }; -} - -declare_lint! { /// The `aarch64_softfloat_neon` lint detects usage of `#[target_feature(enable = "neon")]` on /// softfloat aarch64 targets. Enabling this target feature causes LLVM to alter the ABI of /// function calls, making this attribute unsound to use.
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1d9b7a7..cd402c9 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -778,7 +778,6 @@ pub enum BuiltinLintDiag { UnnameableTestItems, DuplicateMacroAttribute, CfgAttrNoAttributes, - MissingFragmentSpecifier, MetaVariableStillRepeating(MacroRulesNormalizedIdent), MetaVariableWrongOperator, DuplicateMatcherBinding,
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 1bb502c..df648bb 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs
@@ -43,6 +43,7 @@ use tracing_subscriber::fmt::FmtContext; use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields}; use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::{Layer, Registry}; /// The values of all the environment variables that matter for configuring a logger. /// Errors are explicitly preserved so that we can share error handling. @@ -72,6 +73,36 @@ pub fn from_env(env: &str) -> Self { /// Initialize the logger with the given values for the filter, coloring, and other options env variables. pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> { + init_logger_with_additional_layer(cfg, || Registry::default()) +} + +/// Trait alias for the complex return type of `build_subscriber` in +/// [init_logger_with_additional_layer]. A [Registry] with any composition of [tracing::Subscriber]s +/// (e.g. `Registry::default().with(custom_layer)`) should be compatible with this type. +/// Having an alias is also useful so rustc_driver_impl does not need to explicitly depend on +/// `tracing_subscriber`. +pub trait BuildSubscriberRet: + tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync +{ +} + +impl< + T: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync, +> BuildSubscriberRet for T +{ +} + +/// Initialize the logger with the given values for the filter, coloring, and other options env variables. +/// Additionally add a custom layer to collect logging and tracing events via `build_subscriber`, +/// for example: `|| Registry::default().with(custom_layer)`. +pub fn init_logger_with_additional_layer<F, T>( + cfg: LoggerConfig, + build_subscriber: F, +) -> Result<(), Error> +where + F: FnOnce() -> T, + T: BuildSubscriberRet, +{ let filter = match cfg.filter { Ok(env) => EnvFilter::new(env), _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)), @@ -124,7 +155,7 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> { Err(_) => {} // no wraptree } - let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); + let subscriber = build_subscriber().with(layer.with_filter(filter)); match cfg.backtrace { Ok(backtrace_target) => { let fmt_layer = tracing_subscriber::fmt::layer()
diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index e57534b..1eaad26 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs
@@ -4,9 +4,9 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_fs_util::TempDirBuilder; use rustc_middle::ty::TyCtxt; +use rustc_session::Session; use rustc_session::config::{CrateType, OutFileName, OutputType}; use rustc_session::output::filename_for_metadata; -use rustc_session::{MetadataKind, Session}; use crate::errors::{ BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile, @@ -22,13 +22,8 @@ /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a /// directory being searched for `extern crate` (observing an incomplete file). /// The returned path is the temporary file containing the complete metadata. -pub fn emit_wrapper_file( - sess: &Session, - data: &[u8], - tmpdir: &MaybeTempDir, - name: &str, -) -> PathBuf { - let out_filename = tmpdir.as_ref().join(name); +pub fn emit_wrapper_file(sess: &Session, data: &[u8], tmpdir: &Path, name: &str) -> PathBuf { + let out_filename = tmpdir.join(name); let result = fs::write(&out_filename, data); if let Err(err) = result { @@ -38,7 +33,7 @@ pub fn emit_wrapper_file( out_filename } -pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { +pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { let out_filename = filename_for_metadata(tcx.sess, tcx.output_filenames(())); // To avoid races with another rustc process scanning the output directory, // we need to write the file somewhere else and atomically move it to its @@ -59,25 +54,20 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { None }; - // Always create a file at `metadata_filename`, even if we have nothing to write to it. - // This simplifies the creation of the output `out_filename` when requested. - let metadata_kind = tcx.metadata_kind(); - match metadata_kind { - MetadataKind::None => { - std::fs::File::create(&metadata_filename).unwrap_or_else(|err| { - tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err }); + if tcx.needs_metadata() { + encode_metadata(tcx, &metadata_filename, metadata_stub_filename.as_deref()); + } else { + // Always create a file at `metadata_filename`, even if we have nothing to write to it. + // This simplifies the creation of the output `out_filename` when requested. + std::fs::File::create(&metadata_filename).unwrap_or_else(|err| { + tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err }); + }); + if let Some(metadata_stub_filename) = &metadata_stub_filename { + std::fs::File::create(metadata_stub_filename).unwrap_or_else(|err| { + tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_stub_filename, err }); }); - if let Some(metadata_stub_filename) = &metadata_stub_filename { - std::fs::File::create(metadata_stub_filename).unwrap_or_else(|err| { - tcx.dcx() - .emit_fatal(FailedCreateFile { filename: &metadata_stub_filename, err }); - }); - } } - MetadataKind::Uncompressed | MetadataKind::Compressed => { - encode_metadata(tcx, &metadata_filename, metadata_stub_filename.as_deref()) - } - }; + } let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata"); @@ -118,9 +108,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { tcx.dcx().emit_fatal(FailedCreateEncodedMetadata { err }); }); - let need_metadata_module = metadata_kind == MetadataKind::Compressed; - - (metadata, need_metadata_module) + metadata } #[cfg(not(target_os = "linux"))]
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3ab989d..00bd32e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{join, par_for_each_in}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_data_structures::thousands::format_with_underscores; +use rustc_data_structures::thousands::usize_with_underscores; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet}; @@ -789,7 +789,7 @@ macro_rules! stat { "{} {:<23}{:>10} ({:4.1}%)", prefix, label, - format_with_underscores(size), + usize_with_underscores(size), perc(size) ); } @@ -798,7 +798,7 @@ macro_rules! stat { "{} {:<23}{:>10} (of which {:.1}% are zero bytes)", prefix, "Total", - format_with_underscores(total_bytes), + usize_with_underscores(total_bytes), perc(zero_bytes) ); eprintln!("{prefix}");
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 3de97c8..e5e1ae5 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs
@@ -1233,6 +1233,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod body_owners: body_owners.into_boxed_slice(), opaques: opaques.into_boxed_slice(), nested_bodies: nested_bodies.into_boxed_slice(), + delayed_lint_items: Box::new([]), } } @@ -1254,6 +1255,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { body_owners, opaques, nested_bodies, + delayed_lint_items, .. } = collector; @@ -1266,6 +1268,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { body_owners: body_owners.into_boxed_slice(), opaques: opaques.into_boxed_slice(), nested_bodies: nested_bodies.into_boxed_slice(), + delayed_lint_items: delayed_lint_items.into_boxed_slice(), } } @@ -1282,6 +1285,7 @@ struct ItemCollector<'tcx> { body_owners: Vec<LocalDefId>, opaques: Vec<LocalDefId>, nested_bodies: Vec<LocalDefId>, + delayed_lint_items: Vec<OwnerId>, } impl<'tcx> ItemCollector<'tcx> { @@ -1297,6 +1301,7 @@ fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> { body_owners: Vec::default(), opaques: Vec::default(), nested_bodies: Vec::default(), + delayed_lint_items: Vec::default(), } } } @@ -1314,6 +1319,9 @@ fn visit_item(&mut self, item: &'hir Item<'hir>) { } self.items.push(item.item_id()); + if self.crate_collector && item.has_delayed_lints { + self.delayed_lint_items.push(item.item_id().owner_id); + } // Items that are modules are handled here instead of in visit_mod. if let ItemKind::Mod(_, module) = &item.kind { @@ -1329,6 +1337,9 @@ fn visit_item(&mut self, item: &'hir Item<'hir>) { fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) { self.foreign_items.push(item.foreign_item_id()); + if self.crate_collector && item.has_delayed_lints { + self.delayed_lint_items.push(item.foreign_item_id().owner_id); + } intravisit::walk_foreign_item(self, item) } @@ -1362,6 +1373,10 @@ fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { } self.trait_items.push(item.trait_item_id()); + if self.crate_collector && item.has_delayed_lints { + self.delayed_lint_items.push(item.trait_item_id().owner_id); + } + intravisit::walk_trait_item(self, item) } @@ -1371,6 +1386,10 @@ fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { } self.impl_items.push(item.impl_item_id()); + if self.crate_collector && item.has_delayed_lints { + self.delayed_lint_items.push(item.impl_item_id().owner_id); + } + intravisit::walk_impl_item(self, item) } }
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index d1f5caa..9f79ed4 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -12,6 +12,7 @@ use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; +use rustc_hir::lints::DelayedLint; use rustc_hir::*; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{ErrorGuaranteed, ExpnId, Span}; @@ -31,6 +32,8 @@ pub struct ModuleItems { opaques: Box<[LocalDefId]>, body_owners: Box<[LocalDefId]>, nested_bodies: Box<[LocalDefId]>, + // only filled with hir_crate_items, not with hir_module_items + delayed_lint_items: Box<[OwnerId]>, } impl ModuleItems { @@ -48,6 +51,10 @@ pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> { self.trait_items.iter().copied() } + pub fn delayed_lint_items(&self) -> impl Iterator<Item = OwnerId> { + self.delayed_lint_items.iter().copied() + } + /// Returns all items that are associated with some `impl` block (both inherent and trait impl /// blocks). pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> { @@ -161,8 +168,9 @@ pub fn hash_owner_nodes( node: OwnerNode<'_>, bodies: &SortedMap<ItemLocalId, &Body<'_>>, attrs: &SortedMap<ItemLocalId, &[Attribute]>, + delayed_lints: &[DelayedLint], define_opaque: Option<&[(Span, LocalDefId)]>, - ) -> (Option<Fingerprint>, Option<Fingerprint>) { + ) -> (Option<Fingerprint>, Option<Fingerprint>, Option<Fingerprint>) { if self.needs_crate_hash() { self.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); @@ -178,10 +186,16 @@ pub fn hash_owner_nodes( define_opaque.hash_stable(&mut hcx, &mut stable_hasher); let h2 = stable_hasher.finish(); - (Some(h1), Some(h2)) + + // hash lints emitted during ast lowering + let mut stable_hasher = StableHasher::new(); + delayed_lints.hash_stable(&mut hcx, &mut stable_hasher); + let h3 = stable_hasher.finish(); + + (Some(h1), Some(h2), Some(h3)) }) } else { - (None, None) + (None, None, None) } } } @@ -214,6 +228,8 @@ pub fn provide(providers: &mut Providers) { providers.hir_attr_map = |tcx, id| { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; + providers.opt_ast_lowering_delayed_lints = + |tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints); providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)); providers.def_ident_span = |tcx, def_id| { let hir_id = tcx.local_def_id_to_hir_id(def_id);
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 4587dca..6ca1e62 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -12,7 +12,7 @@ pub mod lib_features { #[derive(HashStable, TyEncodable, TyDecodable)] pub enum FeatureStability { AcceptedSince(Symbol), - Unstable, + Unstable { old_name: Option<Symbol> }, } #[derive(HashStable, Debug, Default)]
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 454ab8c..ab6a65e 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -411,7 +411,7 @@ pub fn eval_stability_allow_unstable( match stability { Some(Stability { - level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by }, + level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, feature, .. }) => {
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index f2f975a..56f19d7 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1133,13 +1133,6 @@ pub enum InlineAsmOperand<'tcx> { /// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has /// the address of the local's allocation and the type of the local. /// -/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation -/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation. -/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under -/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and -/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into -/// the current MIR semantics in a clean way - possibly this needs some design work first. -/// /// For places that are not locals, ie they have a non-empty list of projections, we define the /// values as a function of the parent place, that is the place with its last [`ProjectionElem`] /// stripped. The way this is computed of course depends on the kind of that last projection
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d8c927e..15e8c1ef 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs
@@ -221,6 +221,14 @@ feedable } + /// Gives access to lints emitted during ast lowering. + /// + /// This can be conveniently accessed by `tcx.hir_*` methods. + /// Avoid calling this query directly. + query opt_ast_lowering_delayed_lints(key: hir::OwnerId) -> Option<&'tcx hir::lints::DelayedLints> { + desc { |tcx| "getting AST lowering delayed lints in `{}`", tcx.def_path_str(key) } + } + /// Returns the *default* of the const pararameter given by `DefId`. /// /// E.g., given `struct Ty<const N: usize = 3>;` this returns `3` for `N`.
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 145561b..ef5223d 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -49,6 +49,13 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, folder: &mut F, ) -> Result<Self, F::Error> { + // Perf testing has found that this check is slightly faster than + // folding and re-interning an empty `ExternalConstraintsData`. + // See: <https://github.com/rust-lang/rust/pull/142430>. + if self.is_empty() { + return Ok(self); + } + Ok(FallibleTypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().try_fold_with(folder)?, opaque_types: self @@ -64,6 +71,13 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( } fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self { + // Perf testing has found that this check is slightly faster than + // folding and re-interning an empty `ExternalConstraintsData`. + // See: <https://github.com/rust-lang/rust/pull/142430>. + if self.is_empty() { + return self; + } + TypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 455ac66..2fbaa22 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -163,6 +163,10 @@ fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::Bound Const::new_bound(tcx, debruijn, var) } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self { + Const::new_placeholder(tcx, placeholder) + } + fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self { Const::new_unevaluated(interner, uv) }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index cb132ae..fe4dd8d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs
@@ -4,7 +4,7 @@ pub mod tls; -use std::assert_matches::{assert_matches, debug_assert_matches}; +use std::assert_matches::debug_assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::env::VarError; @@ -30,7 +30,7 @@ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan, }; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -47,7 +47,7 @@ use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; -use rustc_session::{Limit, MetadataKind, Session}; +use rustc_session::{Limit, Session}; use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_type_ir::TyKind::*; @@ -283,9 +283,9 @@ fn trait_ref_and_own_args_for_alias( def_id: DefId, args: ty::GenericArgsRef<'tcx>, ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { - assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); + debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); let trait_def_id = self.parent(def_id); - assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); + debug_assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); let trait_generics = self.generics_of(trait_def_id); ( ty::TraitRef::new_from_args(self, trait_def_id, args.truncate_to(self, trait_generics)), @@ -1350,8 +1350,8 @@ pub fn feed_hir(&self) { let bodies = Default::default(); let attrs = hir::AttributeMap::EMPTY; - let (opt_hash_including_bodies, _) = - self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, attrs.define_opaque); + let (opt_hash_including_bodies, _, _) = + self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &[], attrs.define_opaque); let node = node.into(); self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { opt_hash_including_bodies, @@ -1389,6 +1389,18 @@ pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } +impl<'tcx> LintEmitter for TyCtxt<'tcx> { + fn emit_node_span_lint( + self, + lint: &'static Lint, + hir_id: HirId, + span: impl Into<MultiSpan>, + decorator: impl for<'a> LintDiagnostic<'a, ()>, + ) { + self.emit_node_span_lint(lint, hir_id, span, decorator); + } +} + // Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its // field are asserted to implement these traits below, so this is trivially safe, and it greatly // speeds-up compilation of this crate and its dependents. @@ -1846,23 +1858,14 @@ pub fn crate_types(self) -> &'tcx [CrateType] { &self.crate_types } - pub fn metadata_kind(self) -> MetadataKind { - self.crate_types() - .iter() - .map(|ty| match *ty { - CrateType::Executable - | CrateType::Staticlib - | CrateType::Cdylib - | CrateType::Sdylib => MetadataKind::None, - CrateType::Rlib => MetadataKind::Uncompressed, - CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed, - }) - .max() - .unwrap_or(MetadataKind::None) - } - pub fn needs_metadata(self) -> bool { - self.metadata_kind() != MetadataKind::None + self.crate_types().iter().any(|ty| match *ty { + CrateType::Executable + | CrateType::Staticlib + | CrateType::Cdylib + | CrateType::Sdylib => false, + CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true, + }) } pub fn needs_crate_hash(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 5e038f9..7d34d8d 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -588,7 +588,7 @@ pub fn rebase_onto( } pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> GenericArgsRef<'tcx> { - tcx.mk_args_from_iter(self.iter().take(generics.count())) + tcx.mk_args(&self[..generics.count()]) } pub fn print_as_list(&self) -> String {
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 5ba4e54..68adfb3 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -79,7 +79,7 @@ pub enum InstanceKind<'tcx> { Intrinsic(DefId), /// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the - /// `unsized_locals` feature). + /// `unsized_fn_params` feature). /// /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` - /// and dereference the argument to call the original function.
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c2ae6b0..13c281a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -16,9 +16,7 @@ use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use rustc_target::callconv::FnAbi; -use rustc_target::spec::{ - HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi, -}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi}; use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; @@ -565,12 +563,6 @@ fn target_spec(&self) -> &Target { } } -impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.sess.opts.unstable_opts.wasm_c_abi - } -} - impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> { fn x86_abi_opt(&self) -> X86Abi { X86Abi { @@ -625,12 +617,6 @@ fn target_spec(&self) -> &Target { } } -impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> { - fn wasm_c_abi_opt(&self) -> WasmCAbi { - self.calc.cx.wasm_c_abi_opt() - } -} - impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> { fn x86_abi_opt(&self) -> X86Abi { self.calc.cx.x86_abi_opt() @@ -1266,6 +1252,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) | RiscvInterruptS | CCmseNonSecureCall | CCmseNonSecureEntry + | Custom | Unadjusted => false, Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dc3f284..0402d09 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -933,7 +933,9 @@ pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { pub type PlaceholderRegion = Placeholder<BoundRegion>; -impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderRegion { + type Bound = BoundRegion; + fn universe(self) -> UniverseIndex { self.universe } @@ -946,14 +948,20 @@ fn with_updated_universe(self, ui: UniverseIndex) -> Self { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, var: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundRegion) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::Anon } } } } pub type PlaceholderType = Placeholder<BoundTy>; -impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderType { + type Bound = BoundTy; + fn universe(self) -> UniverseIndex { self.universe } @@ -966,7 +974,11 @@ fn with_updated_universe(self, ui: UniverseIndex) -> Self { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, var: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundTy) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } } } } @@ -980,7 +992,9 @@ pub struct BoundConst<'tcx> { pub type PlaceholderConst = Placeholder<BoundVar>; -impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderConst { + type Bound = BoundVar; + fn universe(self) -> UniverseIndex { self.universe } @@ -993,7 +1007,11 @@ fn with_updated_universe(self, ui: UniverseIndex) -> Self { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, var: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundVar) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { Placeholder { universe: ui, bound: var } } }
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 3e4f7a7..cc25cd1 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs
@@ -148,6 +148,10 @@ fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::Bound Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self { + Region::new_placeholder(tcx, placeholder) + } + fn new_static(tcx: TyCtxt<'tcx>) -> Self { tcx.lifetimes.re_static }
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index f8042174..3853a80 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -66,7 +66,7 @@ impl<'tcx, F> TypeVisitor<TyCtxt<'tcx>> for RegionVisitor<F> { type Result = ControlFlow<()>; - fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>( + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( &mut self, t: &Binder<'tcx, T>, ) -> Self::Result { @@ -168,7 +168,7 @@ fn new(just_constrained: bool) -> Self { } impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector { - fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) { + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) { self.current_index.shift_in(1); t.super_visit_with(self); self.current_index.shift_out(1);
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs index 2059610..982e7aa 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs
@@ -55,9 +55,9 @@ pub(crate) fn as_local_operand( /// local variable of unsized type. For example, consider this program: /// /// ``` - /// #![feature(unsized_locals, unsized_fn_params)] + /// #![feature(unsized_fn_params)] /// # use core::fmt::Debug; - /// fn foo(p: dyn Debug) { dbg!(p); } + /// fn foo(_p: dyn Debug) { /* ... */ } /// /// fn bar(box_p: Box<dyn Debug>) { foo(*box_p); } /// ``` @@ -84,7 +84,7 @@ pub(crate) fn as_local_operand( /// will actually provide a pointer to the interior of the box, and not move the `dyn Debug` /// value to the stack. /// - /// See #68304 for more details. + /// See <https://github.com/rust-lang/rust/issues/68304> for more details. pub(crate) fn as_local_call_operand( &mut self, block: BasicBlock,
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index d5d0d56..06c6b46 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1417,9 +1417,9 @@ fn check_field_tys_sized<'tcx>( coroutine_layout: &CoroutineLayout<'tcx>, def_id: LocalDefId, ) { - // No need to check if unsized_locals/unsized_fn_params is disabled, + // No need to check if unsized_fn_params is disabled, // since we will error during typeck. - if !tcx.features().unsized_locals() && !tcx.features().unsized_fn_params() { + if !tcx.features().unsized_fn_params() { return; }
diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 6021e795..dc68629 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs
@@ -132,6 +132,7 @@ fn build_poll_switch<'tcx>( body: &mut Body<'tcx>, poll_enum: Ty<'tcx>, poll_unit_place: &Place<'tcx>, + fut_pin_place: &Place<'tcx>, ready_block: BasicBlock, yield_block: BasicBlock, ) -> BasicBlock { @@ -162,9 +163,11 @@ fn build_poll_switch<'tcx>( Rvalue::Discriminant(*poll_unit_place), ))), }; + let storage_dead = + Statement { source_info, kind: StatementKind::StorageDead(fut_pin_place.local) }; let unreachable_block = insert_term_block(body, TerminatorKind::Unreachable); body.basic_blocks_mut().push(BasicBlockData { - statements: [discr_assign].to_vec(), + statements: [storage_dead, discr_assign].to_vec(), terminator: Some(Terminator { source_info, kind: TerminatorKind::SwitchInt { @@ -332,10 +335,17 @@ pub(super) fn expand_async_drops<'tcx>( kind: StatementKind::Assign(Box::new((context_ref_place, arg))), }); let yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield - let switch_block = - build_poll_switch(tcx, body, poll_enum, &poll_unit_place, target, yield_block); let (pin_bb, fut_pin_place) = build_pin_fut(tcx, body, fut_place.clone(), UnwindAction::Continue); + let switch_block = build_poll_switch( + tcx, + body, + poll_enum, + &poll_unit_place, + &fut_pin_place, + target, + yield_block, + ); let call_bb = build_poll_call( tcx, body, @@ -357,16 +367,17 @@ pub(super) fn expand_async_drops<'tcx>( body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)), ); let drop_yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield + let (pin_bb2, fut_pin_place2) = + build_pin_fut(tcx, body, fut_place, UnwindAction::Continue); let drop_switch_block = build_poll_switch( tcx, body, poll_enum, &poll_unit_place, + &fut_pin_place2, drop.unwrap(), drop_yield_block, ); - let (pin_bb2, fut_pin_place2) = - build_pin_fut(tcx, body, fut_place, UnwindAction::Continue); let drop_call_bb = build_poll_call( tcx, body,
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 3a5e262..c9bc52c 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -390,6 +390,20 @@ fn build_async_drop( Location { block: self.succ, statement_index: 0 }, StatementKind::StorageDead(fut.local), ); + // StorageDead(fut) in unwind block (at the begin) + if let Unwind::To(block) = unwind { + self.elaborator.patch().add_statement( + Location { block, statement_index: 0 }, + StatementKind::StorageDead(fut.local), + ); + } + // StorageDead(fut) in dropline block (at the begin) + if let Some(block) = dropline { + self.elaborator.patch().add_statement( + Location { block, statement_index: 0 }, + StatementKind::StorageDead(fut.local), + ); + } // #1:pin_obj_bb >>> call Pin<ObjTy>::new_unchecked(&mut obj) self.elaborator.patch().patch_terminator(
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 92c30d2..bda71ce 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -240,8 +240,6 @@ struct VnState<'body, 'tcx> { next_opaque: usize, /// Cache the deref values. derefs: Vec<VnIndex>, - /// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop. - feature_unsized_locals: bool, ssa: &'body SsaLocals, dominators: Dominators<BasicBlock>, reused_locals: DenseBitSet<Local>, @@ -273,7 +271,6 @@ fn new( evaluated: IndexVec::with_capacity(num_values), next_opaque: 1, derefs: Vec::new(), - feature_unsized_locals: tcx.features().unsized_locals(), ssa, dominators, reused_locals: DenseBitSet::new_empty(local_decls.len()), @@ -329,13 +326,7 @@ fn get(&self, index: VnIndex) -> &Value<'tcx> { fn assign(&mut self, local: Local, value: VnIndex) { debug_assert!(self.ssa.is_ssa(local)); self.locals[local] = Some(value); - - // Only register the value if its type is `Sized`, as we will emit copies of it. - let is_sized = !self.feature_unsized_locals - || self.local_decls[local].ty.is_sized(self.tcx, self.typing_env()); - if is_sized { - self.rev_locals[value].push(local); - } + self.rev_locals[value].push(local); } fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex {
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 52f4c39..fa29ab9 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -150,12 +150,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { }); terminator.kind = TerminatorKind::Goto { target }; } - sym::size_of | sym::min_align_of => { + sym::size_of | sym::align_of => { let target = target.unwrap(); let tp_ty = generic_args.type_at(0); let null_op = match intrinsic.name { sym::size_of => NullOp::SizeOf, - sym::min_align_of => NullOp::AlignOf, + sym::align_of => NullOp::AlignOf, _ => bug!("unexpected intrinsic"), }; block.statements.push(Statement {
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 35bedf4..2bd19e8 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl
@@ -60,11 +60,4 @@ monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined -monomorphize_wasm_c_abi_transition = - this function {$is_call -> - [true] call - *[false] definition - } involves an argument of type `{$ty}` which is affected by the wasm ABI transition - .help = the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target - monomorphize_written_to_path = the full type name has been written to '{$path}'
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index acf77b5..938c427 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -100,12 +100,3 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { /// Whether this is a problem at a call site or at a declaration. pub is_call: bool, } - -#[derive(LintDiagnostic)] -#[diag(monomorphize_wasm_c_abi_transition)] -#[help] -pub(crate) struct WasmCAbiTransition<'a> { - pub ty: Ty<'a>, - /// Whether this is a problem at a call site or at a declaration. - pub is_call: bool, -}
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 8dbbb4d..b8c001d 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -3,13 +3,10 @@ use rustc_abi::{BackendRepr, CanonAbi, RegKind, X86Call}; use rustc_hir::{CRATE_HIR_ID, HirId}; use rustc_middle::mir::{self, Location, traversal}; -use rustc_middle::ty::layout::LayoutCx; -use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv}; -use rustc_session::lint::builtin::WASM_C_ABI; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; -use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::{HasWasmCAbiOpt, WasmCAbi}; +use rustc_target::callconv::{FnAbi, PassMode}; use crate::errors; @@ -81,73 +78,6 @@ fn do_check_simd_vector_abi<'tcx>( } } -/// Determines whether the given argument is passed the same way on the old and new wasm ABIs. -fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool { - if matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) { - return true; - } - - // Both the old and the new ABIs treat vector types like `v128` the same - // way. - if uses_vector_registers(&arg.mode, &arg.layout.backend_repr) { - return true; - } - - // This matches `unwrap_trivial_aggregate` in the wasm ABI logic. - if arg.layout.is_aggregate() { - let cx = LayoutCx::new(tcx, TypingEnv::fully_monomorphized()); - if let Some(unit) = arg.layout.homogeneous_aggregate(&cx).ok().and_then(|ha| ha.unit()) { - let size = arg.layout.size; - // Ensure there's just a single `unit` element in `arg`. - if unit.size == size { - return true; - } - } - } - - // Zero-sized types are dropped in both ABIs, so they're safe - if arg.layout.is_zst() { - return true; - } - - false -} - -/// Warns against usage of `extern "C"` on wasm32-unknown-unknown that is affected by the -/// ABI transition. -fn do_check_wasm_abi<'tcx>( - tcx: TyCtxt<'tcx>, - abi: &FnAbi<'tcx, Ty<'tcx>>, - is_call: bool, - loc: impl Fn() -> (Span, HirId), -) { - // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what - // `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), and only proceed if - // `wasm_c_abi_opt` indicates we should emit the lint. - if !(tcx.sess.target.arch == "wasm32" - && tcx.sess.target.os == "unknown" - && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true } - && abi.conv == CanonAbi::C) - { - return; - } - // Warn against all types whose ABI will change. Return values are not affected by this change. - for arg_abi in abi.args.iter() { - if wasm_abi_safe(tcx, arg_abi) { - continue; - } - let (span, hir_id) = loc(); - tcx.emit_node_span_lint( - WASM_C_ABI, - hir_id, - span, - errors::WasmCAbiTransition { ty: arg_abi.layout.ty, is_call }, - ); - // Let's only warn once per function. - break; - } -} - /// Checks that the ABI of a given instance of a function does not contain vector-passed arguments /// or return values for which the corresponding target feature is not enabled. fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { @@ -173,7 +103,6 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { ) }; do_check_simd_vector_abi(tcx, abi, instance.def_id(), /*is_call*/ false, loc); - do_check_wasm_abi(tcx, abi, /*is_call*/ false, loc); } /// Checks that a call expression does not try to pass a vector-passed argument which requires a @@ -212,7 +141,6 @@ fn check_call_site_abi<'tcx>( return; }; do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, loc); - do_check_wasm_abi(tcx, callee_abi, /*is_call*/ true, loc); } fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index cea7753..47ed9e8 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -435,13 +435,13 @@ fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty { }, ty::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy( - PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), + PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()), ), CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), }, ty::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy( - PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), + PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()), ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {t:?}"), }, @@ -594,7 +594,7 @@ fn fold_const(&mut self, c: I::Const) -> I::Const { }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst( - PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), + PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()), ), CanonicalizeMode::Response { .. } => { CanonicalVarKind::PlaceholderConst(placeholder) @@ -602,7 +602,7 @@ fn fold_const(&mut self, c: I::Const) -> I::Const { }, ty::ConstKind::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst( - PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), + PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()), ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"), },
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 92cdc28..77f098e 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -12,5 +12,6 @@ pub mod canonicalizer; pub mod coherence; pub mod delegate; +pub mod placeholder; pub mod resolve; pub mod solve;
diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs new file mode 100644 index 0000000..c88fb8d --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs
@@ -0,0 +1,158 @@ +use core::panic; + +use rustc_type_ir::data_structures::IndexMap; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{ + self as ty, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, +}; + +pub struct BoundVarReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + infcx: &'a Infcx, + // These three maps track the bound variable that were replaced by placeholders. It might be + // nice to remove these since we already have the `kind` in the placeholder; we really just need + // the `var` (but we *could* bring that into scope if we were to track them as we pass them). + mapped_regions: IndexMap<I::PlaceholderRegion, I::BoundRegion>, + mapped_types: IndexMap<I::PlaceholderTy, I::BoundTy>, + mapped_consts: IndexMap<I::PlaceholderConst, I::BoundConst>, + // The current depth relative to *this* folding, *not* the entire normalization. In other words, + // the depth of binders we've passed here. + current_index: ty::DebruijnIndex, + // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: + // we don't actually create a universe until we see a bound var we have to replace. + universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, +} + +impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that + /// use a binding level above `universe_indices.len()`, we fail. + pub fn replace_bound_vars<T: TypeFoldable<I>>( + infcx: &'a Infcx, + universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, + value: T, + ) -> ( + T, + IndexMap<I::PlaceholderRegion, I::BoundRegion>, + IndexMap<I::PlaceholderTy, I::BoundTy>, + IndexMap<I::PlaceholderConst, I::BoundConst>, + ) { + let mut replacer = BoundVarReplacer { + infcx, + mapped_regions: Default::default(), + mapped_types: Default::default(), + mapped_consts: Default::default(), + current_index: ty::INNERMOST, + universe_indices, + }; + + let value = value.fold_with(&mut replacer); + + (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) + } + + fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { + let infcx = self.infcx; + let index = + self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; + let universe = self.universe_indices[index].unwrap_or_else(|| { + for i in self.universe_indices.iter_mut().take(index + 1) { + *i = i.or_else(|| Some(infcx.create_next_universe())) + } + self.universe_indices[index].unwrap() + }); + universe + } +} + +impl<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + fn cx(&self) -> I { + self.infcx.cx() + } + + fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + match r.kind() { + ty::ReBound(debruijn, _) + if debruijn.as_usize() + >= self.current_index.as_usize() + self.universe_indices.len() => + { + panic!( + "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = PlaceholderLike::new(universe, br); + self.mapped_regions.insert(p, br); + Region::new_placeholder(self.cx(), p) + } + _ => r, + } + } + + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + match t.kind() { + ty::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + panic!( + "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = PlaceholderLike::new(universe, bound_ty); + self.mapped_types.insert(p, bound_ty); + Ty::new_placeholder(self.cx(), p) + } + _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), + _ => t, + } + } + + fn fold_const(&mut self, ct: I::Const) -> I::Const { + match ct.kind() { + ty::ConstKind::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + panic!( + "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = PlaceholderLike::new(universe, bound_const); + self.mapped_consts.insert(p, bound_const); + Const::new_placeholder(self.cx(), p) + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } +}
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 542e212..0c267fe 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -1014,7 +1014,11 @@ fn characterize_param_env_assumption( return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)); } - match assumption.visit_with(&mut FindParamInClause { ecx: self, param_env }) { + match assumption.visit_with(&mut FindParamInClause { + ecx: self, + param_env, + universes: vec![], + }) { ControlFlow::Break(Err(NoSolution)) => Err(NoSolution), ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)), ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)), @@ -1025,6 +1029,7 @@ fn characterize_param_env_assumption( struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> { ecx: &'a mut EvalCtxt<'b, D>, param_env: I::ParamEnv, + universes: Vec<Option<ty::UniverseIndex>>, } impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I> @@ -1034,31 +1039,42 @@ impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I> { type Result = ControlFlow<Result<(), NoSolution>>; - fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { - self.ecx.enter_forall(t.clone(), |ecx, v| { - v.visit_with(&mut FindParamInClause { ecx, param_env: self.param_env }) - }) + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { + self.universes.push(None); + t.super_visit_with(self)?; + self.universes.pop(); + ControlFlow::Continue(()) } fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { + let ty = self.ecx.replace_bound_vars(ty, &mut self.universes); let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else { return ControlFlow::Break(Err(NoSolution)); }; - if let ty::Placeholder(_) = ty.kind() { - ControlFlow::Break(Ok(())) + if let ty::Placeholder(p) = ty.kind() { + if p.universe() == ty::UniverseIndex::ROOT { + ControlFlow::Break(Ok(())) + } else { + ControlFlow::Continue(()) + } } else { ty.super_visit_with(self) } } fn visit_const(&mut self, ct: I::Const) -> Self::Result { + let ct = self.ecx.replace_bound_vars(ct, &mut self.universes); let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else { return ControlFlow::Break(Err(NoSolution)); }; - if let ty::ConstKind::Placeholder(_) = ct.kind() { - ControlFlow::Break(Ok(())) + if let ty::ConstKind::Placeholder(p) = ct.kind() { + if p.universe() == ty::UniverseIndex::ROOT { + ControlFlow::Break(Ok(())) + } else { + ControlFlow::Continue(()) + } } else { ct.super_visit_with(self) } @@ -1066,10 +1082,17 @@ fn visit_const(&mut self, ct: I::Const) -> Self::Result { fn visit_region(&mut self, r: I::Region) -> Self::Result { match self.ecx.eager_resolve_region(r).kind() { - ty::ReStatic | ty::ReError(_) => ControlFlow::Continue(()), - ty::ReVar(_) | ty::RePlaceholder(_) => ControlFlow::Break(Ok(())), - ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReBound(..) => { - unreachable!() + ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()), + ty::RePlaceholder(p) => { + if p.universe() == ty::UniverseIndex::ROOT { + ControlFlow::Break(Ok(())) + } else { + ControlFlow::Continue(()) + } + } + ty::ReVar(_) => ControlFlow::Break(Ok(())), + ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => { + unreachable!("unexpected region in param-env clause") } } }
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 345ece2..7ead0a6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -19,6 +19,7 @@ use super::has_only_region_constraints; use crate::coherence; use crate::delegate::SolverDelegate; +use crate::placeholder::BoundVarReplacer; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ @@ -1232,6 +1233,14 @@ pub(super) fn is_transmutable( ) -> Result<Certainty, NoSolution> { self.delegate.is_transmutable(dst, src, assume) } + + pub(super) fn replace_bound_vars<T: TypeFoldable<I>>( + &self, + t: T, + universes: &mut Vec<Option<ty::UniverseIndex>>, + ) -> T { + BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0 + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate`
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1f221b4b..f6e0b08 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl
@@ -299,10 +299,12 @@ parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async` .label = `async` because of this .suggestion = remove the `async` qualifier + .note = allowed qualifiers are: `unsafe` and `extern` parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const` .label = `const` because of this .suggestion = remove the `const` qualifier + .note = allowed qualifiers are: `unsafe` and `extern` parse_fn_ptr_with_generics = function pointer types may not have generic parameters .suggestion = consider moving the lifetime {$arity ->
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 2dba568..0f0c543 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs
@@ -2938,22 +2938,22 @@ pub(crate) struct DynAfterMut { #[derive(Diagnostic)] #[diag(parse_fn_pointer_cannot_be_const)] +#[note] pub(crate) struct FnPointerCannotBeConst { #[primary_span] - pub span: Span, #[label] - pub qualifier: Span, + pub span: Span, #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub suggestion: Span, } #[derive(Diagnostic)] #[diag(parse_fn_pointer_cannot_be_async)] +#[note] pub(crate) struct FnPointerCannotBeAsync { #[primary_span] - pub span: Span, #[label] - pub qualifier: Span, + pub span: Span, #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub suggestion: Span, }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a325c2a..658ed4b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs
@@ -23,7 +23,7 @@ AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing, UsePreAttrPos, }; -use crate::errors::{self, MacroExpandsToAdtField}; +use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField}; use crate::{exp, fluent_generated as fluent}; impl<'a> Parser<'a> { @@ -2402,7 +2402,7 @@ fn parse_fn( case: Case, ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<FnContract>>, Option<P<Block>>)> { let fn_span = self.token.span; - let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn` + let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` let decl = match self.parse_fn_decl( @@ -2658,16 +2658,37 @@ pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> b /// /// `vis` represents the visibility that was already parsed, if any. Use /// `Visibility::Inherited` when no visibility is known. + /// + /// If `parsing_mode` is `FrontMatterParsingMode::FunctionPtrType`, we error on `const` and `async` qualifiers, + /// which are not allowed in function pointer types. pub(super) fn parse_fn_front_matter( &mut self, orig_vis: &Visibility, case: Case, + parsing_mode: FrontMatterParsingMode, ) -> PResult<'a, FnHeader> { let sp_start = self.token.span; let constness = self.parse_constness(case); + if parsing_mode == FrontMatterParsingMode::FunctionPtrType + && let Const::Yes(const_span) = constness + { + self.dcx().emit_err(FnPointerCannotBeConst { + span: const_span, + suggestion: const_span.until(self.token.span), + }); + } let async_start_sp = self.token.span; let coroutine_kind = self.parse_coroutine_kind(case); + if parsing_mode == FrontMatterParsingMode::FunctionPtrType + && let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind + { + self.dcx().emit_err(FnPointerCannotBeAsync { + span: async_span, + suggestion: async_span.until(self.token.span), + }); + } + // FIXME(gen_blocks): emit a similar error for `gen fn()` let unsafe_start_sp = self.token.span; let safety = self.parse_safety(case); @@ -2703,6 +2724,11 @@ pub(super) fn parse_fn_front_matter( enum WrongKw { Duplicated(Span), Misplaced(Span), + /// `MisplacedDisallowedQualifier` is only used instead of `Misplaced`, + /// when the misplaced keyword is disallowed by the current `FrontMatterParsingMode`. + /// In this case, we avoid generating the suggestion to swap around the keywords, + /// as we already generated a suggestion to remove the keyword earlier. + MisplacedDisallowedQualifier, } // We may be able to recover @@ -2716,7 +2742,21 @@ enum WrongKw { Const::Yes(sp) => Some(WrongKw::Duplicated(sp)), Const::No => { recover_constness = Const::Yes(self.token.span); - Some(WrongKw::Misplaced(async_start_sp)) + match parsing_mode { + FrontMatterParsingMode::Function => { + Some(WrongKw::Misplaced(async_start_sp)) + } + FrontMatterParsingMode::FunctionPtrType => { + self.dcx().emit_err(FnPointerCannotBeConst { + span: self.token.span, + suggestion: self + .token + .span + .with_lo(self.prev_token.span.hi()), + }); + Some(WrongKw::MisplacedDisallowedQualifier) + } + } } } } else if self.check_keyword(exp!(Async)) { @@ -2742,7 +2782,21 @@ enum WrongKw { closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID, }); - Some(WrongKw::Misplaced(unsafe_start_sp)) + match parsing_mode { + FrontMatterParsingMode::Function => { + Some(WrongKw::Misplaced(async_start_sp)) + } + FrontMatterParsingMode::FunctionPtrType => { + self.dcx().emit_err(FnPointerCannotBeAsync { + span: self.token.span, + suggestion: self + .token + .span + .with_lo(self.prev_token.span.hi()), + }); + Some(WrongKw::MisplacedDisallowedQualifier) + } + } } } } else if self.check_keyword(exp!(Unsafe)) { @@ -2840,14 +2894,20 @@ enum WrongKw { // FIXME(gen_blocks): add keyword recovery logic for genness - if wrong_kw.is_some() + if let Some(wrong_kw) = wrong_kw && self.may_recover() && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case)) { // Advance past the misplaced keyword and `fn` self.bump(); self.bump(); - err.emit(); + // When we recover from a `MisplacedDisallowedQualifier`, we already emitted an error for the disallowed qualifier + // So we don't emit another error that the qualifier is unexpected. + if matches!(wrong_kw, WrongKw::MisplacedDisallowedQualifier) { + err.cancel(); + } else { + err.emit(); + } return Ok(FnHeader { constness: recover_constness, safety: recover_safety, @@ -3194,3 +3254,12 @@ enum IsMacroRulesItem { Yes { has_bang: bool }, No, } + +#[derive(Copy, Clone, PartialEq, Eq)] +pub(super) enum FrontMatterParsingMode { + /// Parse the front matter of a function declaration + Function, + /// Parse the front matter of a function pointet type. + /// For function pointer types, the `const` and `async` keywords are not permitted. + FunctionPtrType, +}
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 9ddfc17..620a340 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -15,10 +15,11 @@ use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::errors::{ self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, - FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg, - HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, - NestedCVariadicType, ReturnTypesUseThinArrow, + FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword, + LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, + ReturnTypesUseThinArrow, }; +use crate::parser::item::FrontMatterParsingMode; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. @@ -669,62 +670,16 @@ fn parse_ty_bare_fn( tokens: None, }; let span_start = self.token.span; - let ast::FnHeader { ext, safety, constness, coroutine_kind } = - self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?; - let fn_start_lo = self.prev_token.span.lo(); + let ast::FnHeader { ext, safety, .. } = self.parse_fn_front_matter( + &inherited_vis, + Case::Sensitive, + FrontMatterParsingMode::FunctionPtrType, + )?; if self.may_recover() && self.token == TokenKind::Lt { self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?; } let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; - let whole_span = lo.to(self.prev_token.span); - // Order/parsing of "front matter" follows: - // `<constness> <coroutine_kind> <safety> <extern> fn()` - // ^ ^ ^ ^ ^ - // | | | | fn_start_lo - // | | | ext_sp.lo - // | | safety_sp.lo - // | coroutine_sp.lo - // const_sp.lo - if let ast::Const::Yes(const_span) = constness { - let next_token_lo = if let Some( - ast::CoroutineKind::Async { span, .. } - | ast::CoroutineKind::Gen { span, .. } - | ast::CoroutineKind::AsyncGen { span, .. }, - ) = coroutine_kind - { - span.lo() - } else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety { - span.lo() - } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext { - span.lo() - } else { - fn_start_lo - }; - let sugg_span = const_span.with_hi(next_token_lo); - self.dcx().emit_err(FnPointerCannotBeConst { - span: whole_span, - qualifier: const_span, - suggestion: sugg_span, - }); - } - if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind { - let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety - { - span.lo() - } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext { - span.lo() - } else { - fn_start_lo - }; - let sugg_span = async_span.with_hi(next_token_lo); - self.dcx().emit_err(FnPointerCannotBeAsync { - span: whole_span, - qualifier: async_span, - suggestion: sugg_span, - }); - } - // FIXME(gen_blocks): emit a similar error for `gen fn()` let decl_span = span_start.to(self.prev_token.span); Ok(TyKind::BareFn(P(BareFnTy { ext, safety, generic_params: params, decl, decl_span }))) }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 9dd064a..42bd0f5 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs
@@ -29,58 +29,45 @@ pub enum ParseMode { Format, /// An inline assembly template string for `asm!`. InlineAsm, + /// A format string for use in diagnostic attributes. + /// + /// Similar to `format_args!`, however only named ("captured") arguments + /// are allowed, and no format modifiers are permitted. + Diagnostic, } /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. #[derive(Clone, Debug, PartialEq)] -pub enum Piece<'a> { +pub enum Piece<'input> { /// A literal string which should directly be emitted - Lit(&'a str), + Lit(&'input str), /// This describes that formatting should process the next argument (as /// specified inside) for emission. - NextArgument(Box<Argument<'a>>), + NextArgument(Box<Argument<'input>>), } /// Representation of an argument specification. #[derive(Clone, Debug, PartialEq)] -pub struct Argument<'a> { +pub struct Argument<'input> { /// Where to find this argument - pub position: Position<'a>, + pub position: Position<'input>, /// The span of the position indicator. Includes any whitespace in implicit /// positions (`{ }`). pub position_span: Range<usize>, /// How to format the argument - pub format: FormatSpec<'a>, + pub format: FormatSpec<'input>, } -impl<'a> Argument<'a> { +impl<'input> Argument<'input> { pub fn is_identifier(&self) -> bool { - matches!(self.position, Position::ArgumentNamed(_)) - && matches!( - self.format, - FormatSpec { - fill: None, - fill_span: None, - align: AlignUnknown, - sign: None, - alternate: false, - zero_pad: false, - debug_hex: None, - precision: CountImplied, - precision_span: None, - width: CountImplied, - width_span: None, - ty: "", - ty_span: None, - }, - ) + matches!(self.position, Position::ArgumentNamed(_)) && self.format == FormatSpec::default() } } /// Specification for the formatting of an argument in the format string. -#[derive(Clone, Debug, PartialEq)] -pub struct FormatSpec<'a> { +#[derive(Clone, Debug, PartialEq, Default)] +pub struct FormatSpec<'input> { /// Optionally specified character to fill alignment with. pub fill: Option<char>, /// Span of the optionally specified fill character. @@ -96,30 +83,30 @@ pub struct FormatSpec<'a> { /// The `x` or `X` flag. (Only for `Debug`.) pub debug_hex: Option<DebugHex>, /// The integer precision to use. - pub precision: Count<'a>, + pub precision: Count<'input>, /// The span of the precision formatting flag (for diagnostics). pub precision_span: Option<Range<usize>>, /// The string width requested for the resulting format. - pub width: Count<'a>, + pub width: Count<'input>, /// The span of the width formatting flag (for diagnostics). pub width_span: Option<Range<usize>>, /// The descriptor string representing the name of the format desired for /// this argument, this can be empty or any number of characters, although /// it is required to be one word. - pub ty: &'a str, + pub ty: &'input str, /// The span of the descriptor string (for diagnostics). pub ty_span: Option<Range<usize>>, } /// Enum describing where an argument for a format can be located. #[derive(Clone, Debug, PartialEq)] -pub enum Position<'a> { +pub enum Position<'input> { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), /// The argument is located at a specific index given in the format, ArgumentIs(usize), /// The argument has a name. - ArgumentNamed(&'a str), + ArgumentNamed(&'input str), } impl Position<'_> { @@ -132,7 +119,7 @@ pub fn index(&self) -> Option<usize> { } /// Enum of alignments which are supported. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Default)] pub enum Alignment { /// The value will be aligned to the left. AlignLeft, @@ -141,6 +128,7 @@ pub enum Alignment { /// The value will be aligned in the center. AlignCenter, /// The value will take on a default alignment. + #[default] AlignUnknown, } @@ -164,17 +152,18 @@ pub enum DebugHex { /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. -#[derive(Clone, Debug, PartialEq)] -pub enum Count<'a> { +#[derive(Clone, Debug, PartialEq, Default)] +pub enum Count<'input> { /// The count is specified explicitly. CountIs(u16), /// The count is specified by the argument with the given name. - CountIsName(&'a str, Range<usize>), + CountIsName(&'input str, Range<usize>), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index. CountIsStar(usize), /// The count is implied and cannot be explicitly specified. + #[default] CountImplied, } @@ -208,10 +197,10 @@ pub enum Suggestion { /// /// This is a recursive-descent parser for the sake of simplicity, and if /// necessary there's probably lots of room for improvement performance-wise. -pub struct Parser<'a> { +pub struct Parser<'input> { mode: ParseMode, /// Input to be parsed - input: &'a str, + input: &'input str, /// Tuples of the span in the code snippet (input as written before being unescaped), the pos in input, and the char in input input_vec: Vec<(Range<usize>, usize, char)>, /// Index into input_vec @@ -237,15 +226,15 @@ pub struct Parser<'a> { pub line_spans: Vec<Range<usize>>, } -impl<'a> Iterator for Parser<'a> { - type Item = Piece<'a>; +impl<'input> Iterator for Parser<'input> { + type Item = Piece<'input>; - fn next(&mut self) -> Option<Piece<'a>> { - if let Some(&(Range { start, end }, idx, ch)) = self.input_vec.get(self.input_vec_index) { + fn next(&mut self) -> Option<Piece<'input>> { + if let Some((Range { start, end }, idx, ch)) = self.peek() { match ch { '{' => { self.input_vec_index += 1; - if let Some(&(_, i, '{')) = self.input_vec.get(self.input_vec_index) { + if let Some((_, i, '{')) = self.peek() { self.input_vec_index += 1; // double open brace escape: "{{" // next state after this is either end-of-input or seen-a-brace @@ -254,25 +243,21 @@ fn next(&mut self) -> Option<Piece<'a>> { // single open brace self.last_open_brace = Some(start..end); let arg = self.argument(); - if let Some(close_brace_range) = self.consume_closing_brace(&arg) { + self.ws(); + if let Some((close_brace_range, _)) = self.consume_pos('}') { if self.is_source_literal { self.arg_places.push(start..close_brace_range.end); } - } else if let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { - match c { - '?' => self.suggest_format_debug(), - '<' | '^' | '>' => self.suggest_format_align(c), - _ => { - self.suggest_positional_arg_instead_of_captured_arg(arg.clone()) - } - } + } else { + self.missing_closing_brace(&arg); } + Some(Piece::NextArgument(Box::new(arg))) } } '}' => { self.input_vec_index += 1; - if let Some(&(_, i, '}')) = self.input_vec.get(self.input_vec_index) { + if let Some((_, i, '}')) = self.peek() { self.input_vec_index += 1; // double close brace escape: "}}" // next state after this is either end-of-input or start @@ -307,14 +292,14 @@ fn next(&mut self) -> Option<Piece<'a>> { } } -impl<'a> Parser<'a> { +impl<'input> Parser<'input> { /// Creates a new parser for the given unescaped input string and /// optional code snippet (the input as written before being unescaped), /// where `style` is `Some(nr_hashes)` when the snippet is a raw string with that many hashes. /// If the input comes via `println` or `panic`, then it has a newline already appended, /// which is reflected in the `appended_newline` parameter. pub fn new( - input: &'a str, + input: &'input str, style: Option<usize>, snippet: Option<String>, appended_newline: bool, @@ -406,6 +391,16 @@ pub fn new( } } + /// Peeks at the current position, without incrementing the pointer. + pub fn peek(&self) -> Option<(Range<usize>, usize, char)> { + self.input_vec.get(self.input_vec_index).cloned() + } + + /// Peeks at the current position + 1, without incrementing the pointer. + pub fn peek_ahead(&self) -> Option<(Range<usize>, usize, char)> { + self.input_vec.get(self.input_vec_index + 1).cloned() + } + /// Optionally consumes the specified character. If the character is not at /// the current position, then the current iterator isn't moved and `false` is /// returned, otherwise the character is consumed and `true` is returned. @@ -418,27 +413,19 @@ fn consume(&mut self, c: char) -> bool { /// returned, otherwise the character is consumed and the current position is /// returned. fn consume_pos(&mut self, ch: char) -> Option<(Range<usize>, usize)> { - if let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { - if ch == *c { - self.input_vec_index += 1; - return Some((r.clone(), *i)); - } + if let Some((r, i, c)) = self.peek() + && ch == c + { + self.input_vec_index += 1; + return Some((r, i)); } + None } - /// Forces consumption of the specified character. If the character is not - /// found, an error is emitted. - fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option<Range<usize>> { - self.ws(); - - let (range, description) = if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) - { - if *c == '}' { - self.input_vec_index += 1; - return Some(r.clone()); - } - // or r.clone()? + /// Called if a closing brace was not found. + fn missing_closing_brace(&mut self, arg: &Argument<'_>) { + let (range, description) = if let Some((r, _, c)) = self.peek() { (r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug())) } else { ( @@ -471,7 +458,13 @@ fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option<Range<usize>> suggestion: Suggestion::None, }); - None + if let Some((_, _, c)) = self.peek() { + match c { + '?' => self.suggest_format_debug(), + '<' | '^' | '>' => self.suggest_format_align(c), + _ => self.suggest_positional_arg_instead_of_captured_arg(arg), + } + } } /// Consumes all whitespace characters until the first non-whitespace character @@ -483,11 +476,11 @@ fn ws(&mut self) { /// Parses all of a string which is to be considered a "raw literal" in a /// format string. This is everything outside of the braces. - fn string(&mut self, start: usize) -> &'a str { - while let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { + fn string(&mut self, start: usize) -> &'input str { + while let Some((r, i, c)) = self.peek() { match c { '{' | '}' => { - return &self.input[start..*i]; + return &self.input[start..i]; } '\n' if self.is_source_literal => { self.input_vec_index += 1; @@ -507,7 +500,7 @@ fn string(&mut self, start: usize) -> &'a str { } /// Parses an `Argument` structure, or what's contained within braces inside the format string. - fn argument(&mut self) -> Argument<'a> { + fn argument(&mut self) -> Argument<'input> { let start_idx = self.input_vec_index; let position = self.position(); @@ -518,6 +511,7 @@ fn argument(&mut self) -> Argument<'a> { let format = match self.mode { ParseMode::Format => self.format(), ParseMode::InlineAsm => self.inline_asm(), + ParseMode::Diagnostic => self.diagnostic(), }; // Resolve position after parsing format spec. @@ -536,31 +530,27 @@ fn argument(&mut self) -> Argument<'a> { /// integer index of an argument, a named argument, or a blank string. /// Returns `Some(parsed_position)` if the position is not implicitly /// consuming a macro argument, `None` if it's the case. - fn position(&mut self) -> Option<Position<'a>> { + fn position(&mut self) -> Option<Position<'input>> { if let Some(i) = self.integer() { Some(ArgumentIs(i.into())) } else { - match self.input_vec.get(self.input_vec_index) { - Some((range, _, c)) if rustc_lexer::is_id_start(*c) => { + match self.peek() { + Some((range, _, c)) if rustc_lexer::is_id_start(c) => { let start = range.start; let word = self.word(); // Recover from `r#ident` in format strings. - // FIXME: use a let chain - if word == "r" { - if let Some((r, _, '#')) = self.input_vec.get(self.input_vec_index) { - if self - .input_vec - .get(self.input_vec_index + 1) - .is_some_and(|(_, _, c)| rustc_lexer::is_id_start(*c)) - { - self.input_vec_index += 1; - let prefix_end = r.end; - let word = self.word(); - let prefix_span = start..prefix_end; - let full_span = - start..self.input_vec_index2range(self.input_vec_index).start; - self.errors.insert(0, ParseError { + if word == "r" + && let Some((r, _, '#')) = self.peek() + && self.peek_ahead().is_some_and(|(_, _, c)| rustc_lexer::is_id_start(c)) + { + self.input_vec_index += 1; + let prefix_end = r.end; + let word = self.word(); + let prefix_span = start..prefix_end; + let full_span = + start..self.input_vec_index2range(self.input_vec_index).start; + self.errors.insert(0, ParseError { description: "raw identifiers are not supported".to_owned(), note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()), label: "raw identifier used here".to_owned(), @@ -568,9 +558,7 @@ fn position(&mut self) -> Option<Position<'a>> { secondary_label: None, suggestion: Suggestion::RemoveRawIdent(prefix_span), }); - return Some(ArgumentNamed(word)); - } - } + return Some(ArgumentNamed(word)); } Some(ArgumentNamed(word)) @@ -584,7 +572,7 @@ fn position(&mut self) -> Option<Position<'a>> { } fn input_vec_index2pos(&self, index: usize) -> usize { - if let Some(&(_, pos, _)) = self.input_vec.get(index) { pos } else { self.input.len() } + if let Some((_, pos, _)) = self.input_vec.get(index) { *pos } else { self.input.len() } } fn input_vec_index2range(&self, index: usize) -> Range<usize> { @@ -597,33 +585,18 @@ fn input_vec_index2range(&self, index: usize) -> Range<usize> { /// Parses a format specifier at the current position, returning all of the /// relevant information in the `FormatSpec` struct. - fn format(&mut self) -> FormatSpec<'a> { - let mut spec = FormatSpec { - fill: None, - fill_span: None, - align: AlignUnknown, - sign: None, - alternate: false, - zero_pad: false, - debug_hex: None, - precision: CountImplied, - precision_span: None, - width: CountImplied, - width_span: None, - ty: &self.input[..0], - ty_span: None, - }; + fn format(&mut self) -> FormatSpec<'input> { + let mut spec = FormatSpec::default(); + if !self.consume(':') { return spec; } // fill character - if let Some(&(ref r, _, c)) = self.input_vec.get(self.input_vec_index) { - if let Some((_, _, '>' | '<' | '^')) = self.input_vec.get(self.input_vec_index + 1) { - self.input_vec_index += 1; - spec.fill = Some(c); - spec.fill_span = Some(r.clone()); - } + if let (Some((r, _, c)), Some((_, _, '>' | '<' | '^'))) = (self.peek(), self.peek_ahead()) { + self.input_vec_index += 1; + spec.fill = Some(c); + spec.fill_span = Some(r); } // Alignment if self.consume('<') { @@ -701,24 +674,21 @@ fn format(&mut self) -> FormatSpec<'a> { } } else if let Some((range, _)) = self.consume_pos('?') { spec.ty = "?"; - if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) { - match c { - '#' | 'x' | 'X' => self.errors.insert( - 0, - ParseError { - description: format!("expected `}}`, found `{c}`"), - note: None, - label: "expected `'}'`".into(), - span: r.clone(), - secondary_label: None, - suggestion: Suggestion::ReorderFormatParameter( - range.start..r.end, - format!("{c}?"), - ), - }, - ), - _ => (), - } + if let Some((r, _, c @ ('#' | 'x' | 'X'))) = self.peek() { + self.errors.insert( + 0, + ParseError { + description: format!("expected `}}`, found `{c}`"), + note: None, + label: "expected `'}'`".into(), + span: r.clone(), + secondary_label: None, + suggestion: Suggestion::ReorderFormatParameter( + range.start..r.end, + format!("{c}?"), + ), + }, + ); } } else { spec.ty = self.word(); @@ -733,22 +703,9 @@ fn format(&mut self) -> FormatSpec<'a> { /// Parses an inline assembly template modifier at the current position, returning the modifier /// in the `ty` field of the `FormatSpec` struct. - fn inline_asm(&mut self) -> FormatSpec<'a> { - let mut spec = FormatSpec { - fill: None, - fill_span: None, - align: AlignUnknown, - sign: None, - alternate: false, - zero_pad: false, - debug_hex: None, - precision: CountImplied, - precision_span: None, - width: CountImplied, - width_span: None, - ty: &self.input[..0], - ty_span: None, - }; + fn inline_asm(&mut self) -> FormatSpec<'input> { + let mut spec = FormatSpec::default(); + if !self.consume(':') { return spec; } @@ -764,10 +721,26 @@ fn inline_asm(&mut self) -> FormatSpec<'a> { spec } + /// Always returns an empty `FormatSpec` + fn diagnostic(&mut self) -> FormatSpec<'input> { + let mut spec = FormatSpec::default(); + + let Some((Range { start, .. }, start_idx)) = self.consume_pos(':') else { + return spec; + }; + + spec.ty = self.string(start_idx); + spec.ty_span = { + let end = self.input_vec_index2range(self.input_vec_index).start; + Some(start..end) + }; + spec + } + /// Parses a `Count` parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. - fn count(&mut self) -> Count<'a> { + fn count(&mut self) -> Count<'input> { if let Some(i) = self.integer() { if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } } else { @@ -786,10 +759,10 @@ fn count(&mut self) -> Count<'a> { /// Parses a word starting at the current position. A word is the same as a /// Rust identifier, except that it can't start with `_` character. - fn word(&mut self) -> &'a str { + fn word(&mut self) -> &'input str { let index = self.input_vec_index; - match self.input_vec.get(self.input_vec_index) { - Some(&(ref r, i, c)) if rustc_lexer::is_id_start(c) => { + match self.peek() { + Some((ref r, i, c)) if rustc_lexer::is_id_start(c) => { self.input_vec_index += 1; (r.start, i) } @@ -798,7 +771,7 @@ fn word(&mut self) -> &'a str { } }; let (err_end, end): (usize, usize) = loop { - if let Some(&(ref r, i, c)) = self.input_vec.get(self.input_vec_index) { + if let Some((ref r, i, c)) = self.peek() { if rustc_lexer::is_id_continue(c) { self.input_vec_index += 1; } else { @@ -828,7 +801,7 @@ fn integer(&mut self) -> Option<u16> { let mut found = false; let mut overflow = false; let start_index = self.input_vec_index; - while let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { + while let Some((_, _, c)) = self.peek() { if let Some(i) = c.to_digit(10) { self.input_vec_index += 1; let (tmp, mul_overflow) = cur.overflowing_mul(10); @@ -897,7 +870,7 @@ fn suggest_format_align(&mut self, alignment: char) { } } - fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { + fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: &Argument<'_>) { // If the argument is not an identifier, it is not a field access. if !arg.is_identifier() { return;
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index e6a7f24..a6c7e18 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs
@@ -553,3 +553,45 @@ fn asm_concat() { assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]); assert_eq!(parser.line_spans, &[]); } + +#[test] +fn diagnostic_format_flags() { + let lit = "{thing:blah}"; + let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic); + assert!(!parser.is_source_literal); + + let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() }; + + assert_eq!( + **arg, + Argument { + position: ArgumentNamed("thing"), + position_span: 2..7, + format: FormatSpec { ty: ":blah", ty_span: Some(7..12), ..Default::default() }, + } + ); + + assert_eq!(parser.line_spans, &[]); + assert!(parser.errors.is_empty()); +} + +#[test] +fn diagnostic_format_mod() { + let lit = "{thing:+}"; + let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic); + assert!(!parser.is_source_literal); + + let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() }; + + assert_eq!( + **arg, + Argument { + position: ArgumentNamed("thing"), + position_span: 2..7, + format: FormatSpec { ty: ":+", ty_span: Some(7..9), ..Default::default() }, + } + ); + + assert_eq!(parser.line_spans, &[]); + assert!(parser.errors.is_empty()); +}
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index a4ef065..7c237d7 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl
@@ -290,6 +290,9 @@ .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_enum_variant_same_name = + it is impossible to refer to the {$descr} `{$dead_name}` because it is shadowed by this enum variant with the same name + passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static @@ -716,6 +719,9 @@ passes_unknown_feature = unknown feature `{$feature}` +passes_unknown_feature_alias = + feature `{$alias}` has been renamed to `{$feature}` + passes_unknown_lang_item = definition of an unknown lang item: `{$name}` .label = definition of unknown lang item `{$name}`
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index e597c81..4257d8e 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs
@@ -14,7 +14,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Node, PatKind, QPath, TyKind}; +use rustc_hir::{self as hir, ImplItem, ImplItemKind, Node, PatKind, QPath, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; @@ -936,7 +936,9 @@ enum ShouldWarnAboutField { #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum ReportOn { + /// Report on something that hasn't got a proper name to refer to TupleField, + /// Report on something that has got a name, which could be a field but also a method NamedField, } @@ -1061,6 +1063,31 @@ fn get_parent_if_enum_variant<'tcx>( None }; + let enum_variants_with_same_name = dead_codes + .iter() + .filter_map(|dead_item| { + if let Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(..) | ImplItemKind::Const(..), + .. + }) = tcx.hir_node_by_def_id(dead_item.def_id) + && let Some(impl_did) = tcx.opt_parent(dead_item.def_id.to_def_id()) + && let DefKind::Impl { of_trait: false } = tcx.def_kind(impl_did) + && let ty::Adt(maybe_enum, _) = tcx.type_of(impl_did).skip_binder().kind() + && maybe_enum.is_enum() + && let Some(variant) = + maybe_enum.variants().iter().find(|i| i.name == dead_item.name) + { + Some(crate::errors::EnumVariantSameName { + descr: tcx.def_descr(dead_item.def_id.to_def_id()), + dead_name: dead_item.name, + variant_span: tcx.def_span(variant.def_id), + }) + } else { + None + } + }) + .collect(); + let diag = match report_on { ReportOn::TupleField => { let tuple_fields = if let Some(parent_id) = parent_item @@ -1114,6 +1141,7 @@ fn get_parent_if_enum_variant<'tcx>( name_list, parent_info, ignored_derived_impls, + enum_variants_with_same_name, }, };
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 74ce926..f0d4b61 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs
@@ -1435,6 +1435,15 @@ pub(crate) struct UnknownFeature { } #[derive(Diagnostic)] +#[diag(passes_unknown_feature_alias, code = E0635)] +pub(crate) struct RenamedFeature { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub alias: Symbol, +} + +#[derive(Diagnostic)] #[diag(passes_implied_feature_not_exist)] pub(crate) struct ImpliedFeatureNotExist { #[primary_span] @@ -1478,6 +1487,9 @@ pub(crate) enum MultipleDeadCodes<'tcx> { participle: &'tcx str, name_list: DiagSymbolList, #[subdiagnostic] + // only on DeadCodes since it's never a problem for tuple struct fields + enum_variants_with_same_name: Vec<EnumVariantSameName<'tcx>>, + #[subdiagnostic] parent_info: Option<ParentInfo<'tcx>>, #[subdiagnostic] ignored_derived_impls: Option<IgnoredDerivedImpls>, @@ -1499,6 +1511,15 @@ pub(crate) enum MultipleDeadCodes<'tcx> { } #[derive(Subdiagnostic)] +#[note(passes_enum_variant_same_name)] +pub(crate) struct EnumVariantSameName<'tcx> { + #[primary_span] + pub variant_span: Span, + pub dead_name: Symbol, + pub descr: &'tcx str, +} + +#[derive(Subdiagnostic)] #[label(passes_parent_info)] pub(crate) struct ParentInfo<'tcx> { pub num: usize,
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 6852153..46e6c0b 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs
@@ -5,7 +5,7 @@ use rustc_ast::visit::BoundKind; use rustc_ast::{self as ast, NodeId, visit as ast_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::thousands::format_with_underscores; +use rustc_data_structures::thousands::usize_with_underscores; use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -140,10 +140,10 @@ fn print(&self, title: &str, prefix: &str) { "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}", prefix, label, - format_with_underscores(size), + usize_with_underscores(size), percent(size, total_size), - format_with_underscores(node.stats.count), - format_with_underscores(node.stats.size) + usize_with_underscores(node.stats.count), + usize_with_underscores(node.stats.size) ); if !node.subnodes.is_empty() { // We will soon sort, so the initial order does not matter. @@ -159,9 +159,9 @@ fn print(&self, title: &str, prefix: &str) { "{} - {:<18}{:>10} ({:4.1}%){:>14}", prefix, label, - format_with_underscores(size), + usize_with_underscores(size), percent(size, total_size), - format_with_underscores(subnode.count), + usize_with_underscores(subnode.count), ); } } @@ -171,8 +171,8 @@ fn print(&self, title: &str, prefix: &str) { "{} {:<18}{:>10} {:>14}", prefix, "Total", - format_with_underscores(total_size), - format_with_underscores(total_count), + usize_with_underscores(total_size), + usize_with_underscores(total_count), ); eprintln!("{prefix}"); }
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index b3e6ee9..127e0df 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs
@@ -40,7 +40,7 @@ fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, Span)> }; let feature_stability = match level { - StabilityLevel::Unstable { .. } => FeatureStability::Unstable, + StabilityLevel::Unstable { old_name, .. } => FeatureStability::Unstable { old_name }, StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since { StableSince::Version(v) => Symbol::intern(&v.to_string()), StableSince::Current => sym::env_CFG_RELEASE, @@ -71,7 +71,7 @@ fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span }); } } - (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable, _))) => { + (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable { .. }, _))) => { self.tcx.dcx().emit_err(FeaturePreviouslyDeclared { span, feature, @@ -79,7 +79,7 @@ fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span prev_declared: "unstable", }); } - (FeatureStability::Unstable, Some((FeatureStability::AcceptedSince(_), _))) => { + (FeatureStability::Unstable { .. }, Some((FeatureStability::AcceptedSince(_), _))) => { self.tcx.dcx().emit_err(FeaturePreviouslyDeclared { span, feature, @@ -88,7 +88,7 @@ fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span }); } // duplicate `unstable` feature is ok. - (FeatureStability::Unstable, Some((FeatureStability::Unstable, _))) => {} + (FeatureStability::Unstable { .. }, Some((FeatureStability::Unstable { .. }, _))) => {} } } }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 45e26c8..56d9f5b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs
@@ -718,6 +718,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { issue: NonZero::new(27812), is_soft: false, implied_by: None, + old_name: None, }, feature: sym::rustc_private, }; @@ -1161,8 +1162,8 @@ fn check_features<'tcx>( defined_features: &LibFeatures, all_implications: &UnordMap<Symbol, Symbol>, ) { - for (feature, since) in defined_features.to_sorted_vec() { - if let FeatureStability::AcceptedSince(since) = since + for (feature, stability) in defined_features.to_sorted_vec() { + if let FeatureStability::AcceptedSince(since) = stability && let Some(span) = remaining_lib_features.get(&feature) { // Warn if the user has enabled an already-stable lib feature. @@ -1181,6 +1182,12 @@ fn check_features<'tcx>( // implications from this crate. remaining_implications.remove(&feature); + if let FeatureStability::Unstable { old_name: Some(alias) } = stability { + if let Some(span) = remaining_lib_features.swap_remove(&alias) { + tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias }); + } + } + if remaining_lib_features.is_empty() && remaining_implications.is_empty() { break; }
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index e1b6adc..96d0c02 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -1,5 +1,3 @@ -use std::sync::Arc; - use rustc_ast as ast; use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -7,7 +5,9 @@ use rustc_session::Session; use rustc_session::cstore::Untracked; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, CachingSourceMapView, DUMMY_SP, SourceFile, Span, SpanData, Symbol}; +use rustc_span::{ + BytePos, CachingSourceMapView, DUMMY_SP, Span, SpanData, StableSourceFileId, Symbol, +}; use crate::ich; @@ -118,7 +118,7 @@ fn def_span(&self, def_id: LocalDefId) -> Span { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(Arc<SourceFile>, usize, BytePos, usize, BytePos)> { + ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { self.source_map().span_data_to_lines_and_cols(span) }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c30ed78..650a827 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1098,22 +1098,20 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> boo self.r.potentially_unused_imports.push(import); module.for_each_child(self, |this, ident, ns, binding| { if ns == MacroNS { - let imported_binding = - if this.r.is_accessible_from(binding.vis, this.parent_scope.module) { - this.r.import(binding, import) - } else if !this.r.is_builtin_macro(binding.res()) - && !this.r.macro_use_prelude.contains_key(&ident.name) - { - // - `!r.is_builtin_macro(res)` excluding the built-in macros such as `Debug` or `Hash`. - // - `!r.macro_use_prelude.contains_key(name)` excluding macros defined in other extern - // crates such as `std`. - // FIXME: This branch should eventually be removed. - let import = macro_use_import(this, span, true); - this.r.import(binding, import) - } else { + let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module) + { + import + } else { + // FIXME: This branch is used for reporting the `private_macro_use` lint + // and should eventually be removed. + if this.r.macro_use_prelude.contains_key(&ident.name) { + // Do not override already existing entries with compatibility entries. return; - }; - this.add_macro_use_binding(ident.name, imported_binding, span, allow_shadowing); + } + macro_use_import(this, span, true) + }; + let import_binding = this.r.import(binding, import); + this.add_macro_use_binding(ident.name, import_binding, span, allow_shadowing); } }); } else {
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index dc16fe2..f8e0a69 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -128,7 +128,7 @@ fn visit_item(&mut self, i: &'a Item) { // FIXME(jdonszelmann) make one of these in the resolver? // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. // Does that prevents errors from happening? maybe - let parser = AttributeParser::new( + let mut parser = AttributeParser::new_early( &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), @@ -136,8 +136,14 @@ fn visit_item(&mut self, i: &'a Item) { let attrs = parser.parse_attribute_list( &i.attrs, i.span, + i.id, OmitDoc::Skip, std::convert::identity, + |_l| { + // FIXME(jdonszelmann): emit lints here properly + // NOTE that before new attribute parsing, they didn't happen either + // but it would be nice if we could change that. + }, ); let macro_data =
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 201b1c0..9149974 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -7,7 +7,7 @@ use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{self as attr, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::unord::UnordSet; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, @@ -1054,6 +1054,7 @@ fn early_lookup_typo_candidate( false, false, None, + None, ) else { continue; }; @@ -1482,7 +1483,35 @@ pub(crate) fn unresolved_macro_suggestions( parent_scope: &ParentScope<'ra>, ident: Ident, krate: &Crate, + sugg_span: Option<Span>, ) { + // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used + // for suggestions. + self.visit_scopes( + ScopeSet::Macro(MacroKind::Derive), + &parent_scope, + ident.span.ctxt(), + |this, scope, _use_prelude, _ctxt| { + let Scope::Module(m, _) = scope else { + return None; + }; + for (_, resolution) in this.resolutions(m).borrow().iter() { + let Some(binding) = resolution.borrow().binding else { + continue; + }; + let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = + binding.res() + else { + continue; + }; + // By doing this all *imported* macros get added to the `macro_map` even if they + // are *unused*, which makes the later suggestions find them and work. + let _ = this.get_macro_by_def_id(def_id); + } + None::<()> + }, + ); + let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); let suggestion = self.early_lookup_typo_candidate( ScopeSet::Macro(macro_kind), @@ -1490,7 +1519,9 @@ pub(crate) fn unresolved_macro_suggestions( ident, is_expected, ); - self.add_typo_suggestion(err, suggestion, ident.span); + if !self.add_typo_suggestion(err, suggestion, ident.span) { + self.detect_derive_attribute(err, ident, parent_scope, sugg_span); + } let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); @@ -1623,6 +1654,105 @@ pub(crate) fn unresolved_macro_suggestions( } } + /// Given an attribute macro that failed to be resolved, look for `derive` macros that could + /// provide it, either as-is or with small typos. + fn detect_derive_attribute( + &self, + err: &mut Diag<'_>, + ident: Ident, + parent_scope: &ParentScope<'ra>, + sugg_span: Option<Span>, + ) { + // Find all of the `derive`s in scope and collect their corresponding declared + // attributes. + // FIXME: this only works if the crate that owns the macro that has the helper_attr + // has already been imported. + let mut derives = vec![]; + let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default(); + // We're collecting these in a hashmap, and handle ordering the output further down. + #[allow(rustc::potential_query_instability)] + for (def_id, data) in &self.macro_map { + for helper_attr in &data.ext.helper_attrs { + let item_name = self.tcx.item_name(*def_id); + all_attrs.entry(*helper_attr).or_default().push(item_name); + if helper_attr == &ident.name { + derives.push(item_name); + } + } + } + let kind = MacroKind::Derive.descr(); + if !derives.is_empty() { + // We found an exact match for the missing attribute in a `derive` macro. Suggest it. + let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect(); + derives.sort(); + derives.dedup(); + let msg = match &derives[..] { + [derive] => format!(" `{derive}`"), + [start @ .., last] => format!( + "s {} and `{last}`", + start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ") + ), + [] => unreachable!("we checked for this to be non-empty 10 lines above!?"), + }; + let msg = format!( + "`{}` is an attribute that can be used by the {kind}{msg}, you might be \ + missing a `derive` attribute", + ident.name, + ); + let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind + { + let span = self.def_span(id); + if span.from_expansion() { + None + } else { + // For enum variants sugg_span is empty but we can get the enum's Span. + Some(span.shrink_to_lo()) + } + } else { + // For items this `Span` will be populated, everything else it'll be None. + sugg_span + }; + match sugg_span { + Some(span) => { + err.span_suggestion_verbose( + span, + msg, + format!("#[derive({})]\n", derives.join(", ")), + Applicability::MaybeIncorrect, + ); + } + None => { + err.note(msg); + } + } + } else { + // We didn't find an exact match. Look for close matches. If any, suggest fixing typo. + let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord(); + if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None) + && let Some(macros) = all_attrs.get(&best_match) + { + let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect(); + macros.sort(); + macros.dedup(); + let msg = match ¯os[..] { + [] => return, + [name] => format!(" `{name}` accepts"), + [start @ .., end] => format!( + "s {} and `{end}` accept", + start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "), + ), + }; + let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute"); + err.span_suggestion_verbose( + ident.span, + msg, + best_match, + Applicability::MaybeIncorrect, + ); + } + } + } + pub(crate) fn add_typo_suggestion( &self, err: &mut Diag<'_>,
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 180d6af..68fbe48 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs
@@ -460,6 +460,7 @@ struct Flags: u8 { true, force, ignore_import, + None, ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 816efd0..e989209 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs
@@ -133,7 +133,9 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { .field("target", target) .field("id", id) .finish(), - MacroUse { .. } => f.debug_struct("MacroUse").finish(), + MacroUse { warn_private } => { + f.debug_struct("MacroUse").field("warn_private", warn_private).finish() + } MacroExport => f.debug_struct("MacroExport").finish(), } }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3dc285f..fa4b024 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs
@@ -4509,7 +4509,7 @@ fn resolve_qpath_anywhere( let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; if let Ok((_, res)) = - self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None) + self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None) { return Ok(Some(PartialRes::new(res))); }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9ba70ab..f054072 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs
@@ -1139,7 +1139,7 @@ pub struct Resolver<'ra, 'tcx> { proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>)>, + Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>, multi_segment_macro_resolutions: Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, @@ -1934,12 +1934,26 @@ fn record_use_inner( } if let NameBindingKind::Import { import, binding } = used_binding.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { - self.lint_buffer().buffer_lint( - PRIVATE_MACRO_USE, - import.root_id, - ident.span, - BuiltinLintDiag::MacroIsPrivate(ident), - ); + // Do not report the lint if the macro name resolves in stdlib prelude + // even without the problematic `macro_use` import. + let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| { + self.maybe_resolve_ident_in_module( + ModuleOrUniformRoot::Module(prelude), + ident, + MacroNS, + &ParentScope::module(self.empty_module, self), + None, + ) + .is_ok() + }); + if !found_in_stdlib_prelude { + self.lint_buffer().buffer_lint( + PRIVATE_MACRO_USE, + import.root_id, + ident.span, + BuiltinLintDiag::MacroIsPrivate(ident), + ); + } } // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope.
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ee90506..1b82e9c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs
@@ -12,7 +12,8 @@ use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ - DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, + Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, + SyntaxExtensionKind, }; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ @@ -294,6 +295,14 @@ fn resolve_macro_invocation( && self.tcx.def_kind(mod_def_id) == DefKind::Mod }) .map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id); + let sugg_span = match &invoc.kind { + InvocationKind::Attr { item: Annotatable::Item(item), .. } + if !item.span.from_expansion() => + { + Some(item.span.shrink_to_lo()) + } + _ => None, + }; let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -304,6 +313,7 @@ fn resolve_macro_invocation( force, deleg_impl, looks_like_invoc_in_mod_inert_attr, + sugg_span, )?; let span = invoc.span(); @@ -386,6 +396,7 @@ fn resolve_derives( true, force, None, + None, ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { @@ -528,6 +539,7 @@ fn smart_resolve_macro_path( force: bool, deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<LocalDefId>, + suggestion_span: Option<Span>, ) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> { let (ext, res) = match self.resolve_macro_or_delegation_path( path, @@ -538,6 +550,7 @@ fn smart_resolve_macro_path( deleg_impl, invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)), None, + suggestion_span, ) { Ok((Some(ext), res)) => (ext, res), Ok((None, res)) => (self.dummy_ext(kind), res), @@ -681,6 +694,7 @@ pub(crate) fn resolve_macro_path( trace: bool, force: bool, ignore_import: Option<Import<'ra>>, + suggestion_span: Option<Span>, ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { self.resolve_macro_or_delegation_path( path, @@ -691,6 +705,7 @@ pub(crate) fn resolve_macro_path( None, None, ignore_import, + suggestion_span, ) } @@ -704,6 +719,7 @@ fn resolve_macro_or_delegation_path( deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, ignore_import: Option<Import<'ra>>, + suggestion_span: Option<Span>, ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { let path_span = ast_path.span; let mut path = Segment::from_path(ast_path); @@ -768,6 +784,7 @@ fn resolve_macro_or_delegation_path( kind, *parent_scope, binding.ok(), + suggestion_span, )); } @@ -905,7 +922,7 @@ pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { } let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); - for (ident, kind, parent_scope, initial_binding) in macro_resolutions { + for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { match self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), @@ -946,7 +963,14 @@ pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { expected, ident, }); - self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); + self.unresolved_macro_suggestions( + &mut err, + kind, + &parent_scope, + ident, + krate, + sugg_span, + ); err.emit(); } } @@ -974,7 +998,8 @@ fn check_stability_and_deprecation( ) { let span = path.span; if let Some(stability) = &ext.stability { - if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level + if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } = + stability.level { let feature = stability.feature;
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 528c52e..6195361 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl
@@ -40,6 +40,11 @@ session_file_write_fail = failed to write `{$path}` due to error `{$err}` +session_forbidden_ctarget_feature = + target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} + .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models @@ -132,6 +137,9 @@ session_unleashed_feature_help_named = skipping check for `{$gate}` feature session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate +session_unstable_ctarget_feature = + unstable feature specified for `-Ctarget-feature`: `{$feature}` + .note = this feature is not stably supported; its behavior can change in the future session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` session_unsupported_crate_type_for_target =
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 60e1b46..406a6bd 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs
@@ -2649,6 +2649,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches); + // -Zretpoline-external-thunk also requires -Zretpoline + if unstable_opts.retpoline_external_thunk { + unstable_opts.retpoline = true; + target_modifiers.insert( + OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline), + "true".to_string(), + ); + } + let cg = cg; let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); @@ -3057,7 +3066,7 @@ pub(crate) mod dep_tracking { use rustc_target::spec::{ CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple, - TlsModel, WasmCAbi, + TlsModel, }; use super::{ @@ -3168,7 +3177,6 @@ fn hash( Polonius, InliningThreshold, FunctionReturn, - WasmCAbi, Align, );
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index bf95014..9c591dc 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs
@@ -501,3 +501,20 @@ pub(crate) struct FailedToCreateProfiler { #[note] #[note(session_soft_float_deprecated_issue)] pub(crate) struct SoftFloatDeprecated; + +#[derive(Diagnostic)] +#[diag(session_forbidden_ctarget_feature)] +#[note] +#[note(session_forbidden_ctarget_feature_issue)] +pub(crate) struct ForbiddenCTargetFeature<'a> { + pub feature: &'a str, + pub enabled: &'a str, + pub reason: &'a str, +} + +#[derive(Diagnostic)] +#[diag(session_unstable_ctarget_feature)] +#[note] +pub(crate) struct UnstableCTargetFeature<'a> { + pub feature: &'a str, +}
diff --git a/compiler/rustc_session/src/features.rs b/compiler/rustc_session/src/features.rs new file mode 100644 index 0000000..70a088a --- /dev/null +++ b/compiler/rustc_session/src/features.rs
@@ -0,0 +1,59 @@ +use rustc_target::target_features::Stability; + +use crate::Session; +use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature}; + +pub trait StabilityExt { + /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. + /// Otherwise, some features also may only be enabled by flag (target modifier). + /// (It might still be nightly-only even if this returns `true`, so make sure to also check + /// `requires_nightly`.) + fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>; + + /// Check that feature is correctly enabled/disabled by command line flag (emits warnings) + fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str); +} + +impl StabilityExt for Stability { + fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> { + match self { + Stability::Forbidden { reason } => Err(reason), + Stability::TargetModifierOnly { reason, flag } => { + if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) } + } + _ => Ok(()), + } + } + fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) { + if let Err(reason) = self.is_toggle_permitted(sess) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if self.requires_nightly().is_some() { + // An unstable feature. Warn about using it. It makes little sense + // to hard-error here since we just warn about fully unknown + // features above. + sess.dcx().emit_warn(UnstableCTargetFeature { feature }); + } + } +} + +pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) { + // -Zretpoline without -Zretpoline-external-thunk enables + // retpoline-indirect-branches and retpoline-indirect-calls target features + let unstable_opts = &sess.opts.unstable_opts; + if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk { + features.push("+retpoline-indirect-branches"); + features.push("+retpoline-indirect-calls"); + } + // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables + // retpoline-external-thunk, retpoline-indirect-branches and + // retpoline-indirect-calls target features + if unstable_opts.retpoline_external_thunk { + features.push("+retpoline-external-thunk"); + features.push("+retpoline-indirect-branches"); + features.push("+retpoline-indirect-calls"); + } +}
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 5e5872e..4added1 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs
@@ -29,6 +29,7 @@ pub mod output; pub use getopts; +pub mod features; rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 12fa051..f76f258 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs
@@ -16,7 +16,7 @@ use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, - TargetTuple, TlsModel, WasmCAbi, + TargetTuple, TlsModel, }; use crate::config::*; @@ -290,6 +290,14 @@ pub fn gather_target_modifiers(&self) -> Vec<TargetModifier> { mods.sort_by(|a, b| a.opt.cmp(&b.opt)); mods } + + pub fn target_feature_flag_enabled(&self, flag: &str) -> bool { + match flag { + "retpoline" => self.unstable_opts.retpoline, + "retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk, + _ => false, + } + } } ); } @@ -794,7 +802,6 @@ mod desc { "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub(crate) const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`"; - pub(crate) const parse_wasm_c_abi: &str = "`legacy` or `spec`"; pub(crate) const parse_mir_include_spans: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)"; pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29"; @@ -1890,16 +1897,6 @@ pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) true } - pub(crate) fn parse_wasm_c_abi(slot: &mut WasmCAbi, v: Option<&str>) -> bool { - match v { - Some("spec") => *slot = WasmCAbi::Spec, - // Explicitly setting the `-Z` flag suppresses the lint. - Some("legacy") => *slot = WasmCAbi::Legacy { with_lint: false }, - _ => return false, - } - true - } - pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool { *slot = match v { Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On, @@ -2305,6 +2302,8 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool { (space separated)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], "show macro backtraces (default: no)"), + macro_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about macro expansions (default: no)"), maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED], "save as much information as possible about the correspondence between MIR and HIR \ as source scopes (default: no)"), @@ -2446,6 +2445,11 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool { remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], "directory into which to write optimization remarks (if not specified, they will be \ written to standard error output)"), + retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"), + retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \ + target features (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED], @@ -2627,8 +2631,6 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool { Requires `-Clto[=[fat,yes]]`"), wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED], "whether to build a wasi command or reactor"), - wasm_c_abi: WasmCAbi = (WasmCAbi::Legacy { with_lint: true }, parse_wasm_c_abi, [TRACKED], - "use spec-compliant C ABI for `wasm32-unknown-unknown` (default: legacy)"), write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED], "whether long type names should be written to files instead of being printed in errors"), // tidy-alphabetical-end
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 1fe521b..87c848c 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs
@@ -17,7 +17,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use crate::Session; use crate::config::{Cfg, CheckCfg}; @@ -192,8 +192,11 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( } else { err.subdiagnostic(FeatureDiagnosticHelp { feature }); } - - if sess.opts.unstable_opts.ui_testing { + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { err.subdiagnostic(suggestion);
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 6b85e0a..b8b4518 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs
@@ -215,13 +215,6 @@ pub struct Session { pub invocation_temp: Option<String>, } -#[derive(PartialEq, Eq, PartialOrd, Ord)] -pub enum MetadataKind { - None, - Uncompressed, - Compressed, -} - #[derive(Clone, Copy)] pub enum CodegenUnits { /// Specified by the user. In this case we try fairly hard to produce the
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 6e13b87..a4c6f18 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -496,6 +496,7 @@ fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self:: Abi::RustCold => rustc_abi::ExternAbi::RustCold, Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, + Abi::Custom => rustc_abi::ExternAbi::Custom, } } }
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index ef8c883..baa4c06 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -12,7 +12,8 @@ }; use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; use rustc_middle::ty::{ - GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, + CoroutineArgsExt, GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, + ValTree, }; use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; @@ -22,9 +23,9 @@ use stable_mir::mir::{BinOp, Body, Place, UnOp}; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef, - ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, Ty, - TyConst, TyKind, UintTy, VariantDef, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef, + ForeignDef, ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, + Span, Ty, TyConst, TyKind, UintTy, VariantDef, VariantIdx, }; use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol}; @@ -447,6 +448,30 @@ pub fn adt_variants_len(&self, def: AdtDef) -> usize { def.internal(&mut *tables, tcx).variants().len() } + /// Discriminant for a given variant index of AdtDef + pub fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let adt = adt.internal(&mut *tables, tcx); + let variant = variant.internal(&mut *tables, tcx); + adt.discriminant_for_variant(tcx, variant).stable(&mut *tables) + } + + /// Discriminant for a given variand index and args of a coroutine + pub fn coroutine_discr_for_variant( + &self, + coroutine: CoroutineDef, + args: &GenericArgs, + variant: VariantIdx, + ) -> Discr { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let coroutine = coroutine.def_id().internal(&mut *tables, tcx); + let args = args.internal(&mut *tables, tcx); + let variant = variant.internal(&mut *tables, tcx); + args.as_coroutine().discriminant_for_variant(coroutine, tcx, variant).stable(&mut *tables) + } + /// The name of a variant. pub fn variant_name(&self, def: VariantDef) -> Symbol { let mut tables = self.0.borrow_mut();
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 46f1ca6..35d5b7f 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -101,6 +101,7 @@ fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { CanonAbi::C => CallConvention::C, CanonAbi::Rust => CallConvention::Rust, CanonAbi::RustCold => CallConvention::Cold, + CanonAbi::Custom => CallConvention::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => CallConvention::ArmAapcs, ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b0c9dba..b4239dd 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -879,6 +879,7 @@ fn stable(&self, _: &mut Tables<'_>) -> Self::T { ExternAbi::RustCold => Abi::RustCold, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, + ExternAbi::Custom => Abi::Custom, } } } @@ -959,3 +960,11 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T { } } } + +impl<'tcx> Stable<'tcx> for rustc_middle::ty::util::Discr<'tcx> { + type T = stable_mir::ty::Discr; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + stable_mir::ty::Discr { val: self.val, ty: self.ty.stable(tables) } + } +}
diff --git a/compiler/rustc_smir/src/stable_mir/abi.rs b/compiler/rustc_smir/src/stable_mir/abi.rs index 347c6ed..d8a2b97 100644 --- a/compiler/rustc_smir/src/stable_mir/abi.rs +++ b/compiler/rustc_smir/src/stable_mir/abi.rs
@@ -430,6 +430,8 @@ pub enum CallConvention { PreserveMost, PreserveAll, + Custom, + // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall,
diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs index 3967ad1..2668fba 100644 --- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs +++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
@@ -13,10 +13,10 @@ use stable_mir::mir::{BinOp, Body, Place, UnOp}; use stable_mir::target::MachineInfo; use stable_mir::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef, - ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics, - ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, TraitDecl, - TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef, + ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, + Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, + TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx, }; use stable_mir::{ AssocItems, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, @@ -230,6 +230,21 @@ pub(crate) fn adt_variants_len(&self, def: AdtDef) -> usize { self.cx.adt_variants_len(def) } + /// Discriminant for a given variant index of AdtDef + pub(crate) fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr { + self.cx.adt_discr_for_variant(adt, variant) + } + + /// Discriminant for a given variand index and args of a coroutine + pub(crate) fn coroutine_discr_for_variant( + &self, + coroutine: CoroutineDef, + args: &GenericArgs, + variant: VariantIdx, + ) -> Discr { + self.cx.coroutine_discr_for_variant(coroutine, args, variant) + } + /// The name of a variant. pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol { self.cx.variant_name(def)
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 4593685..4415cd6 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -756,6 +756,12 @@ pub fn body(&self) -> Option<Body> { pub CoroutineDef; } +impl CoroutineDef { + pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr { + with(|cx| cx.coroutine_discr_for_variant(*self, args, idx)) + } +} + crate_def! { #[derive(Serialize)] pub CoroutineClosureDef; @@ -831,6 +837,15 @@ pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> { pub fn repr(&self) -> ReprOptions { with(|cx| cx.adt_repr(*self)) } + + pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr { + with(|cx| cx.adt_discr_for_variant(*self, idx)) + } +} + +pub struct Discr { + pub val: u128, + pub ty: Ty, } /// Definition of a variant, which can be either a struct / union field or an enum variant. @@ -1111,6 +1126,7 @@ pub enum Abi { RustCold, RiscvInterruptM, RiscvInterruptS, + Custom, } /// A binder represents a possibly generic type and its bound vars.
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index d8a4cc2..a887b50 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -2,7 +2,7 @@ use std::sync::Arc; use crate::source_map::SourceMap; -use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData}; +use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData, StableSourceFileId}; #[derive(Clone)] struct CacheEntry { @@ -114,7 +114,7 @@ pub fn byte_pos_to_line_and_col( pub fn span_data_to_lines_and_cols( &mut self, span_data: &SpanData, - ) -> Option<(Arc<SourceFile>, usize, BytePos, usize, BytePos)> { + ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { self.time_stamp += 1; // Check if lo and hi are in the cached lines. @@ -132,7 +132,7 @@ pub fn span_data_to_lines_and_cols( } ( - Arc::clone(&lo.file), + lo.file.stable_id, lo.line_number, span_data.lo - lo.line.start, hi.line_number, @@ -226,7 +226,7 @@ pub fn span_data_to_lines_and_cols( assert_eq!(lo.file_index, hi.file_index); Some(( - Arc::clone(&lo.file), + lo.file.stable_id, lo.line_number, span_data.lo - lo.line.start, hi.line_number,
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index b621920..315dede 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs
@@ -1135,7 +1135,7 @@ pub fn descr(&self) -> String { } /// The kind of macro invocation or definition. -#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum MacroKind { /// A bang macro `foo!()`.
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ed74dea..c8a29a2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs
@@ -2600,7 +2600,7 @@ pub trait HashStableContext { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(Arc<SourceFile>, usize, BytePos, usize, BytePos)>; + ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)>; fn hashing_controls(&self) -> HashingControls; } @@ -2657,7 +2657,7 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { }; Hash::hash(&TAG_VALID_SPAN, hasher); - Hash::hash(&file.stable_id, hasher); + Hash::hash(&file, hasher); // Hash both the length and the end location (line/column) of a span. If we // hash only the length, for example, then two otherwise equal spans with
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d66f988..cb9ccf4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs
@@ -407,6 +407,7 @@ abi_amdgpu_kernel, abi_avr_interrupt, abi_c_cmse_nonsecure_call, + abi_custom, abi_efiapi, abi_gpu_kernel, abi_msp430_interrupt, @@ -429,6 +430,8 @@ aggregate_raw_ptr, alias, align, + align_of, + align_of_val, alignment, all, alloc, @@ -1353,8 +1356,6 @@ message, meta, metadata_type, - min_align_of, - min_align_of_val, min_const_fn, min_const_generics, min_const_unsafe_fn, @@ -1512,6 +1513,7 @@ offset_of_nested, offset_of_slice, ok_or_else, + old_name, omit_gdb_pretty_printer_section, on, on_unimplemented, @@ -2288,6 +2290,7 @@ usize_legacy_fn_max_value, usize_legacy_fn_min_value, usize_legacy_mod, + v1, v8plus, va_arg, va_copy, @@ -2675,7 +2678,7 @@ fn prefill(init: &[&'static str], extra: &[&'static str]) -> Self { assert_eq!( strings.len(), init.len() + extra.len(), - "`init` or `extra` contain duplicate symbols", + "there are duplicate symbols in the rustc symbol list and the extra symbols added by the driver", ); Interner(Lock::new(InternerInner { arena: Default::default(), strings })) }
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs index b4ea6fc..51e7ee8 100644 --- a/compiler/rustc_target/src/asm/loongarch.rs +++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -34,11 +34,15 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> { pub fn supported_types( self, - _arch: InlineAsmArch, + arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option<Symbol>)] { - match self { - Self::reg => types! { _: I8, I16, I32, I64, F32, F64; }, - Self::freg => types! { f: F32; d: F64; }, + match (self, arch) { + (Self::reg, InlineAsmArch::LoongArch64) => { + types! { _: I8, I16, I32, I64, F16, F32, F64; } + } + (Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F16, F32; }, + (Self::freg, _) => types! { f: F16, F32; d: F64; }, + _ => unreachable!("unsupported register class"), } } }
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index f9ecf02..2ff7a71 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -7,7 +7,7 @@ use rustc_macros::HashStable_Generic; pub use crate::spec::AbiMap; -use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; +use crate::spec::{HasTargetSpec, HasX86AbiOpt}; mod aarch64; mod amdgpu; @@ -593,7 +593,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { pub fn adjust_for_foreign_abi<C>(&mut self, cx: &C, abi: ExternAbi) where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt, + C: HasDataLayout + HasTargetSpec + HasX86AbiOpt, { if abi == ExternAbi::X86Interrupt { if let Some(arg) = self.args.first_mut() { @@ -669,14 +669,7 @@ pub fn adjust_for_foreign_abi<C>(&mut self, cx: &C, abi: ExternAbi) "hexagon" => hexagon::compute_abi_info(self), "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), - "wasm32" => { - if spec.os == "unknown" && matches!(cx.wasm_c_abi_opt(), WasmCAbi::Legacy { .. }) { - wasm::compute_wasm_abi_info(self) - } else { - wasm::compute_c_abi_info(cx, self) - } - } - "wasm64" => wasm::compute_c_abi_info(cx, self), + "wasm32" | "wasm64" => wasm::compute_abi_info(cx, self), "bpf" => bpf::compute_abi_info(self), arch => panic!("no lowering implemented for {arch}"), }
diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs index 881168c..a308f37 100644 --- a/compiler/rustc_target/src/callconv/wasm.rs +++ b/compiler/rustc_target/src/callconv/wasm.rs
@@ -59,7 +59,7 @@ fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) } /// The purpose of this ABI is to match the C ABI (aka clang) exactly. -pub(crate) fn compute_c_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, @@ -75,43 +75,3 @@ pub(crate) fn compute_c_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) classify_arg(cx, arg); } } - -/// The purpose of this ABI is for matching the WebAssembly standard. This -/// intentionally diverges from the C ABI and is specifically crafted to take -/// advantage of LLVM's support of multiple returns in WebAssembly. -/// -/// This ABI is *bad*! It uses `PassMode::Direct` for `abi::Aggregate` types, which leaks LLVM -/// implementation details into the ABI. It's just hard to fix because ABIs are hard to change. -/// Also see <https://github.com/rust-lang/rust/issues/115666>. -pub(crate) fn compute_wasm_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) { - if !fn_abi.ret.is_ignore() { - classify_ret_wasm_abi(&mut fn_abi.ret); - } - - for arg in fn_abi.args.iter_mut() { - if arg.is_ignore() { - continue; - } - classify_arg_wasm_abi(arg); - } - - fn classify_ret_wasm_abi<Ty>(ret: &mut ArgAbi<'_, Ty>) { - if !ret.layout.is_sized() { - // Not touching this... - return; - } - // FIXME: this is bad! https://github.com/rust-lang/rust/issues/115666 - ret.make_direct_deprecated(); - ret.extend_integer_width_to(32); - } - - fn classify_arg_wasm_abi<Ty>(arg: &mut ArgAbi<'_, Ty>) { - if !arg.layout.is_sized() { - // Not touching this... - return; - } - // FIXME: this is bad! https://github.com/rust-lang/rust/issues/115666 - arg.make_direct_deprecated(); - arg.extend_integer_width_to(32); - } -}
diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 300b19f..700ee73 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs
@@ -7,6 +7,7 @@ }; use crate::callconv::{ArgAbi, CastTarget, FnAbi}; +use crate::spec::HasTargetSpec; /// Classification of "eightbyte" components. // N.B., the order of the variants is from general to specific, @@ -175,7 +176,7 @@ fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget { pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout, + C: HasDataLayout + HasTargetSpec, { let mut int_regs = MAX_INT_REGS; let mut sse_regs = MAX_SSE_REGS; @@ -236,7 +237,7 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) if arg.layout.is_aggregate() { let size = arg.layout.size; arg.cast_to(cast_target(cls, size)); - } else { + } else if is_arg || cx.target_spec().is_like_darwin { arg.extend_integer_width_to(32); } }
diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index c4978a8..4659bbd 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs
@@ -71,6 +71,8 @@ pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMap (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, (ExternAbi::RustCold, _) => CanonAbi::RustCold, + (ExternAbi::Custom, _) => CanonAbi::Custom, + (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => { CanonAbi::X86(X86Call::Stdcall) }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c360fe6..010355a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2233,22 +2233,6 @@ fn target_spec(&self) -> &Target { } } -/// Which C ABI to use for `wasm32-unknown-unknown`. -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum WasmCAbi { - /// Spec-compliant C ABI. - Spec, - /// Legacy ABI. Which is non-spec-compliant. - Legacy { - /// Indicates whether the `wasm_c_abi` lint should be emitted. - with_lint: bool, - }, -} - -pub trait HasWasmCAbiOpt { - fn wasm_c_abi_opt(&self) -> WasmCAbi; -} - /// x86 (32-bit) abi options. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct X86Abi {
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 5d1182f..a1eac1f 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs
@@ -34,6 +34,9 @@ pub enum Stability { /// particular for features are actually ABI configuration flags (not all targets are as nice as /// RISC-V and have an explicit way to set the ABI separate from target features). Forbidden { reason: &'static str }, + /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set + /// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules. + TargetModifierOnly { reason: &'static str, flag: &'static str }, } use Stability::*; @@ -49,6 +52,7 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { Stability::Forbidden { reason } => { reason.hash_stable(hcx, hasher); } + Stability::TargetModifierOnly { .. } => {} } } } @@ -74,16 +78,7 @@ pub fn requires_nightly(&self) -> Option<Symbol> { Stability::Unstable(nightly_feature) => Some(nightly_feature), Stability::Stable { .. } => None, Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), - } - } - - /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. - /// (It might still be nightly-only even if this returns `true`, so make sure to also check - /// `requires_nightly`.) - pub fn toggle_allowed(&self) -> Result<(), &'static str> { - match self { - Stability::Forbidden { reason } => Err(reason), - _ => Ok(()), + Stability::TargetModifierOnly { .. } => None, } } } @@ -453,6 +448,30 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> { ("prfchw", Unstable(sym::prfchw_target_feature), &[]), ("rdrand", Stable, &[]), ("rdseed", Stable, &[]), + ( + "retpoline-external-thunk", + Stability::TargetModifierOnly { + reason: "use `retpoline-external-thunk` target modifier flag instead", + flag: "retpoline-external-thunk", + }, + &[], + ), + ( + "retpoline-indirect-branches", + Stability::TargetModifierOnly { + reason: "use `retpoline` target modifier flag instead", + flag: "retpoline", + }, + &[], + ), + ( + "retpoline-indirect-calls", + Stability::TargetModifierOnly { + reason: "use `retpoline` target modifier flag instead", + flag: "retpoline", + }, + &[], + ), ("rtm", Unstable(sym::rtm_target_feature), &[]), ("sha", Stable, &["sse2"]), ("sha512", Stable, &["avx2"]),
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 3796838..89dab90 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
@@ -810,7 +810,8 @@ fn verify(&self, tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> Result<(), ErrorGuar let mut result = Ok(()); - match FormatString::parse(self.symbol, self.span, &ctx) { + let snippet = tcx.sess.source_map().span_to_snippet(self.span).ok(); + match FormatString::parse(self.symbol, snippet, self.span, &ctx) { // Warnings about format specifiers, deprecated parameters, wrong parameters etc. // In other words we'd like to let the author know, but we can still try to format the string later Ok(FormatString { warnings, .. }) => { @@ -848,34 +849,27 @@ fn verify(&self, tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> Result<(), ErrorGuar } } } - // Errors from the underlying `rustc_parse_format::Parser` - Err(errors) => { + // Error from the underlying `rustc_parse_format::Parser` + Err(e) => { // we cannot return errors from processing the format string as hard error here // as the diagnostic namespace guarantees that malformed input cannot cause an error // // if we encounter any error while processing we nevertheless want to show it as warning // so that users are aware that something is not correct - for e in errors { - if self.is_diagnostic_namespace_variant { - if let Some(trait_def_id) = trait_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(trait_def_id), - self.span, - WrappedParserError { description: e.description, label: e.label }, - ); - } - } else { - let reported = struct_span_code_err!( - tcx.dcx(), + if self.is_diagnostic_namespace_variant { + if let Some(trait_def_id) = trait_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(trait_def_id), self.span, - E0231, - "{}", - e.description, - ) - .emit(); - result = Err(reported); + WrappedParserError { description: e.description, label: e.label }, + ); } + } else { + let reported = + struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,) + .emit(); + result = Err(reported); } } } @@ -896,7 +890,8 @@ pub fn format( Ctx::RustcOnUnimplemented { tcx, trait_def_id } }; - if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) { + // No point passing a snippet here, we already did that in `verify` + if let Ok(s) = FormatString::parse(self.symbol, None, self.span, &ctx) { s.format(args) } else { // we cannot return errors from processing the format string as hard error here
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index e8ea9f2..171d052 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
@@ -198,7 +198,7 @@ enum LitOrArg { impl FilterFormatString { fn parse(input: Symbol) -> Self { - let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format) + let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic) .map(|p| match p { Piece::Lit(s) => LitOrArg::Lit(s.to_owned()), // We just ignore formatspecs here
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index 7c1dfc1..3e8b906 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
@@ -5,12 +5,11 @@ use rustc_middle::ty::print::TraitRefPrintSugared; use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ - Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, - Position, + Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, }; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::def_id::DefId; -use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym}; +use rustc_span::{InnerSpan, Span, Symbol, kw, sym}; /// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces", /// either as string pieces or dynamic arguments. @@ -160,32 +159,32 @@ pub fn span(&self) -> Span { pub fn parse<'tcx>( input: Symbol, + snippet: Option<String>, span: Span, ctx: &Ctx<'tcx>, - ) -> Result<Self, Vec<ParseError>> { + ) -> Result<Self, ParseError> { let s = input.as_str(); - let mut parser = Parser::new(s, None, None, false, ParseMode::Format); - let mut pieces = Vec::new(); + let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic); + let pieces: Vec<_> = parser.by_ref().collect(); + + if let Some(err) = parser.errors.into_iter().next() { + return Err(err); + } let mut warnings = Vec::new(); - for piece in &mut parser { - match piece { - RpfPiece::Lit(lit) => { - pieces.push(Piece::Lit(lit.into())); - } + let pieces = pieces + .into_iter() + .map(|piece| match piece { + RpfPiece::Lit(lit) => Piece::Lit(lit.into()), RpfPiece::NextArgument(arg) => { - warn_on_format_spec(arg.format.clone(), &mut warnings, span); - let arg = parse_arg(&arg, ctx, &mut warnings, span); - pieces.push(Piece::Arg(arg)); + warn_on_format_spec(&arg.format, &mut warnings, span, parser.is_source_literal); + let arg = parse_arg(&arg, ctx, &mut warnings, span, parser.is_source_literal); + Piece::Arg(arg) } - } - } + }) + .collect(); - if parser.errors.is_empty() { - Ok(FormatString { input, pieces, span, warnings }) - } else { - Err(parser.errors) - } + Ok(FormatString { input, pieces, span, warnings }) } pub fn format(&self, args: &FormatArgs<'_>) -> String { @@ -229,11 +228,12 @@ fn parse_arg<'tcx>( ctx: &Ctx<'tcx>, warnings: &mut Vec<FormatWarning>, input_span: Span, + is_source_literal: bool, ) -> FormatArg { let (Ctx::RustcOnUnimplemented { tcx, trait_def_id } | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; - let span = slice_span(input_span, arg.position_span.clone()); + let span = slice_span(input_span, arg.position_span.clone(), is_source_literal); match arg.position { // Something like "hello {name}" @@ -283,39 +283,24 @@ fn parse_arg<'tcx>( /// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything /// with specifiers, so emit a warning if they are used. -fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) { - if !matches!( - spec, - FormatSpec { - fill: None, - fill_span: None, - align: Alignment::AlignUnknown, - sign: None, - alternate: false, - zero_pad: false, - debug_hex: None, - precision: Count::CountImplied, - precision_span: None, - width: Count::CountImplied, - width_span: None, - ty: _, - ty_span: _, - }, - ) { - let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span); +fn warn_on_format_spec( + spec: &FormatSpec<'_>, + warnings: &mut Vec<FormatWarning>, + input_span: Span, + is_source_literal: bool, +) { + if spec.ty != "" { + let span = spec + .ty_span + .as_ref() + .map(|inner| slice_span(input_span, inner.clone(), is_source_literal)) + .unwrap_or(input_span); warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() }) } } -fn slice_span(input: Span, range: Range<usize>) -> Span { - let span = input.data(); - - Span::new( - span.lo + BytePos::from_usize(range.start), - span.lo + BytePos::from_usize(range.end), - span.ctxt, - span.parent, - ) +fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span { + if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input } } pub mod errors {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 68bd944..ee5a5b2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2995,9 +2995,6 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>( if local { err.note("all local variables must have a statically known size"); } - if !tcx.features().unsized_locals() { - err.help("unsized locals are gated as an unstable feature"); - } } ObligationCauseCode::SizedArgumentType(hir_id) => { let mut ty = None;
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index d5d318e..b0c8fa1 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -11,7 +11,8 @@ use std::assert_matches::assert_matches; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::Obligation; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; @@ -20,7 +21,7 @@ use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; use tracing::instrument; use crate::solve::delegate::SolverDelegate; @@ -60,28 +61,29 @@ impl<'tcx> NormalizesToTermHack<'tcx> { /// Relate the `term` with the new `unconstrained_term` created /// when computing the proof tree for this `NormalizesTo` goals. /// This handles nested obligations. - fn constrain( - self, + fn constrain_and( + &self, infcx: &InferCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, + f: impl FnOnce(&ObligationCtxt<'_, 'tcx>), ) -> Result<Certainty, NoSolution> { - infcx - .at(&ObligationCause::dummy_with_span(span), param_env) - .eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term) - .map_err(|_| NoSolution) - .and_then(|InferOk { value: (), obligations }| { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations); - let errors = ocx.select_all_or_error(); - if errors.is_empty() { - Ok(Certainty::Yes) - } else if errors.iter().all(|e| !e.is_true_error()) { - Ok(Certainty::AMBIGUOUS) - } else { - Err(NoSolution) - } - }) + let ocx = ObligationCtxt::new(infcx); + ocx.eq( + &ObligationCause::dummy_with_span(span), + param_env, + self.term, + self.unconstrained_term, + )?; + f(&ocx); + let errors = ocx.select_all_or_error(); + if errors.is_empty() { + Ok(Certainty::Yes) + } else if errors.iter().all(|e| !e.is_true_error()) { + Ok(Certainty::AMBIGUOUS) + } else { + Err(NoSolution) + } } } @@ -160,11 +162,11 @@ pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> let () = instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); - if let Some(term_hack) = self.goal.normalizes_to_term_hack { + if let Some(term_hack) = &self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals // when computing the result of its candidates. This is // scuffed. - let _ = term_hack.constrain(infcx, span, param_env); + let _ = term_hack.constrain_and(infcx, span, param_env, |_| {}); } instantiated_goals @@ -240,13 +242,39 @@ pub fn instantiate_proof_tree_for_nested_goal( // building their proof tree, the expected term was unconstrained, but when // instantiating the candidate it is already constrained to the result of another // candidate. - let proof_tree = infcx - .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None).1); + let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term }; + let (proof_tree, nested_goals_result) = infcx.probe(|_| { + // Here, if we have any nested goals, then we make sure to apply them + // considering the constrained RHS, and pass the resulting certainty to + // `InspectGoal::new` so that the goal has the right result (and maintains + // the impression that we don't do this normalizes-to infer hack at all). + let (nested, proof_tree) = + infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None); + let proof_tree = proof_tree.unwrap(); + let nested_goals_result = nested.and_then(|(nested, _)| { + normalizes_to_term_hack.constrain_and( + infcx, + span, + proof_tree.uncanonicalized_goal.param_env, + |ocx| { + ocx.register_obligations(nested.0.into_iter().map(|(_, goal)| { + Obligation::new( + infcx.tcx, + ObligationCause::dummy_with_span(span), + goal.param_env, + goal.predicate, + ) + })); + }, + ) + }); + (proof_tree, nested_goals_result) + }); InspectGoal::new( infcx, self.goal.depth + 1, - proof_tree.unwrap(), - Some(NormalizesToTermHack { term, unconstrained_term }), + proof_tree, + Some((normalizes_to_term_hack, nested_goals_result)), source, ) } @@ -393,20 +421,21 @@ fn new( infcx: &'a InferCtxt<'tcx>, depth: usize, root: inspect::GoalEvaluation<TyCtxt<'tcx>>, - normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, + term_hack_and_nested_certainty: Option<( + NormalizesToTermHack<'tcx>, + Result<Certainty, NoSolution>, + )>, source: GoalSource, ) -> Self { let infcx = <&SolverDelegate<'tcx>>::from(infcx); let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; + // If there's a normalizes-to goal, AND the evaluation result with the result of + // constraining the normalizes-to RHS and computing the nested goals. let result = evaluation.result.and_then(|ok| { - if let Some(term_hack) = normalizes_to_term_hack { - infcx - .probe(|_| term_hack.constrain(infcx, DUMMY_SP, uncanonicalized_goal.param_env)) - .map(|certainty| ok.value.certainty.and(certainty)) - } else { - Ok(ok.value.certainty) - } + let nested_goals_certainty = + term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?; + Ok(ok.value.certainty.and(nested_goals_certainty)) }); InspectGoal { @@ -416,7 +445,7 @@ fn new( goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, evaluation_kind: evaluation.kind, - normalizes_to_term_hack, + normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n), source, } }
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 220a847..47d207e 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -414,8 +414,8 @@ fn virtual_call_violations_for_method<'tcx>( let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0)); - // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. - // However, this is already considered dyn compatible. We allow it as a special case here. + // `self: Self` can't be dispatched on. + // However, this is considered dyn compatible. We allow it as a special case here. // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows // `Receiver: Unsize<Receiver[Self => dyn Trait]>`. if receiver_ty != tcx.types.self_param {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index eb34cb1..a54eb80 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -9,7 +9,7 @@ pub use rustc_middle::traits::query::NormalizationResult; use rustc_middle::ty::{ self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitableExt, TypeVisitor, TypingMode, + TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_span::DUMMY_SP; use tracing::{debug, info, instrument}; @@ -127,7 +127,7 @@ struct MaxEscapingBoundVarVisitor { } impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor { - fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) { + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) { self.outer_index.shift_in(1); t.super_visit_with(self); self.outer_index.shift_out(1);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3a2f9e8..1b9b68f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1919,12 +1919,23 @@ fn winnow_candidates( // impl `impl<T: ?Sized> Any for T { .. }`. This really shouldn't exist but is // necessary due to #57893. We again arbitrarily prefer the applicable candidate // with the lowest index. + // + // We do not want to use these impls to guide inference in case a user-written impl + // may also apply. let object_bound = candidates .iter() .filter_map(|c| if let ObjectCandidate(i) = c.candidate { Some(i) } else { None }) .try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) }); match object_bound { - Some(Some(index)) => return Some(ObjectCandidate(index)), + Some(Some(index)) => { + return if has_non_region_infer + && candidates.iter().any(|c| matches!(c.candidate, ImplCandidate(_))) + { + None + } else { + Some(ObjectCandidate(index)) + }; + } Some(None) => {} None => return None, }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 035fd38..0723aeb 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, VecDeque}; +use std::collections::VecDeque; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::LangItem; @@ -9,6 +9,7 @@ use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +pub use rustc_next_trait_solver::placeholder::BoundVarReplacer; use rustc_span::Span; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -212,158 +213,12 @@ pub fn with_replaced_escaping_bound_vars< } } -pub struct BoundVarReplacer<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, - // These three maps track the bound variable that were replaced by placeholders. It might be - // nice to remove these since we already have the `kind` in the placeholder; we really just need - // the `var` (but we *could* bring that into scope if we were to track them as we pass them). - mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, - mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, - // The current depth relative to *this* folding, *not* the entire normalization. In other words, - // the depth of binders we've passed here. - current_index: ty::DebruijnIndex, - // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: - // we don't actually create a universe until we see a bound var we have to replace. - universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, -} - -impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> { - /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that - /// use a binding level above `universe_indices.len()`, we fail. - pub fn replace_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>( - infcx: &'a InferCtxt<'tcx>, - universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, - value: T, - ) -> ( - T, - FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, - FxIndexMap<ty::PlaceholderType, ty::BoundTy>, - BTreeMap<ty::PlaceholderConst, ty::BoundVar>, - ) { - let mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion> = - FxIndexMap::default(); - let mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy> = FxIndexMap::default(); - let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = BTreeMap::new(); - - let mut replacer = BoundVarReplacer { - infcx, - mapped_regions, - mapped_types, - mapped_consts, - current_index: ty::INNERMOST, - universe_indices, - }; - - let value = value.fold_with(&mut replacer); - - (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) - } - - fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { - let infcx = self.infcx; - let index = - self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; - let universe = self.universe_indices[index].unwrap_or_else(|| { - for i in self.universe_indices.iter_mut().take(index + 1) { - *i = i.or_else(|| Some(infcx.create_next_universe())) - } - self.universe_indices[index].unwrap() - }); - universe - } -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match r.kind() { - ty::ReBound(debruijn, _) - if debruijn.as_usize() - >= self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderRegion { universe, bound: br }; - self.mapped_regions.insert(p, br); - ty::Region::new_placeholder(self.infcx.tcx, p) - } - _ => r, - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Bound(debruijn, _) - if debruijn.as_usize() + 1 - > self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderType { universe, bound: bound_ty }; - self.mapped_types.insert(p, bound_ty); - Ty::new_placeholder(self.infcx.tcx, p) - } - _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), - _ => t, - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - match ct.kind() { - ty::ConstKind::Bound(debruijn, _) - if debruijn.as_usize() + 1 - > self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderConst { universe, bound: bound_const }; - self.mapped_consts.insert(p, bound_const); - ty::Const::new_placeholder(self.infcx.tcx, p) - } - _ => ct.super_fold_with(self), - } - } - - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } - } -} - /// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. pub struct PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, + mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>, universe_indices: &'a [Option<ty::UniverseIndex>], current_index: ty::DebruijnIndex, } @@ -373,7 +228,7 @@ pub fn replace_placeholders<T: TypeFoldable<TyCtxt<'tcx>>>( infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, + mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>, universe_indices: &'a [Option<ty::UniverseIndex>], value: T, ) -> T {
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index bb5187e..f0ff503 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -403,28 +403,18 @@ fn fn_arg_sanity_check<'tcx>( // For an unsized type we'd only pass the sized prefix, so there is no universe // in which we ever want to allow this. assert!(sized, "`PassMode::Direct` for unsized type in ABI: {:#?}", fn_abi); + // This really shouldn't happen even for sized aggregates, since // `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an // LLVM type. This means all sorts of Rust type details leak into the ABI. - // However wasm sadly *does* currently use this mode for it's "C" ABI so we - // have to allow it -- but we absolutely shouldn't let any more targets do - // that. (Also see <https://github.com/rust-lang/rust/issues/115666>.) - // - // The unadjusted ABI also uses Direct for all args and is ill-specified, + // The unadjusted ABI however uses Direct for all args. It is ill-specified, // but unfortunately we need it for calling certain LLVM intrinsics. - - match spec_abi { - ExternAbi::Unadjusted => {} - ExternAbi::C { unwind: _ } - if matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64") => {} - _ => { - panic!( - "`PassMode::Direct` for aggregates only allowed for \"unadjusted\" functions and on wasm\n\ - Problematic type: {:#?}", - arg.layout, - ); - } - } + assert!( + matches!(spec_abi, ExternAbi::Unadjusted), + "`PassMode::Direct` for aggregates only allowed for \"unadjusted\"\n\ + Problematic type: {:#?}", + arg.layout, + ); } } }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 79ac622..11becea 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -7,8 +7,7 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, - fold_regions, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, fold_regions, }; use rustc_span::DUMMY_SP; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -186,7 +185,7 @@ struct ImplTraitInTraitFinder<'a, 'tcx> { } impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { - fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, binder: &ty::Binder<'tcx, T>) { + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, binder: &ty::Binder<'tcx, T>) { self.depth.shift_in(1); binder.super_visit_with(self); self.depth.shift_out(1);
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 83d3d78..4bd7bfe 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml
@@ -9,7 +9,7 @@ derive-where = "1.2.7" ena = "0.14.3" indexmap = "2.0.0" -rustc-hash = "1.1.0" +rustc-hash = "2.0.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false }
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 55c0a3b..927a2ce 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs
@@ -128,7 +128,7 @@ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self { } } -impl<I: Interner, T: TypeFoldable<I>> TypeVisitable<I> for Binder<I, T> { +impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Binder<I, T> { fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { visitor.visit_binder(self) } @@ -147,7 +147,7 @@ fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self { } } -impl<I: Interner, T: TypeFoldable<I>> TypeSuperVisitable<I> for Binder<I, T> { +impl<I: Interner, T: TypeVisitable<I>> TypeSuperVisitable<I> for Binder<I, T> { fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { self.as_ref().skip_binder().visit_with(visitor) } @@ -292,7 +292,7 @@ pub fn new(bound_vars: I::BoundVarKinds) -> Self { impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { type Result = ControlFlow<()>; - fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1);
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 615d077..fa5e8d4 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -237,9 +237,6 @@ pub fn args_may_unify( } pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool { - if lhs == rhs { - return true; - } self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH) } @@ -268,6 +265,10 @@ fn args_may_unify_inner( } fn types_may_unify_inner(self, lhs: I::Ty, rhs: I::Ty, depth: usize) -> bool { + if lhs == rhs { + return true; + } + match rhs.kind() { // Start by checking whether the `rhs` type may unify with // pretty much everything. Just return `true` in that case.
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index fa88bcb..436ab9f 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -228,6 +228,8 @@ pub trait Region<I: Interner<Region = Self>>: fn new_static(interner: I) -> Self; + fn new_placeholder(interner: I, var: I::PlaceholderRegion) -> Self; + fn is_bound(self) -> bool { matches!(self.kind(), ty::ReBound(..)) } @@ -254,6 +256,8 @@ pub trait Const<I: Interner<Const = Self>>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_placeholder(interner: I, param: I::PlaceholderConst) -> Self; + fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self; fn new_expr(interner: I, expr: I::ExprConst) -> Self; @@ -524,13 +528,14 @@ pub trait Clauses<I: Interner<Clauses = Self>>: } /// Common capabilities of placeholder kinds -pub trait PlaceholderLike: Copy + Debug + Hash + Eq { +pub trait PlaceholderLike<I: Interner>: Copy + Debug + Hash + Eq { fn universe(self) -> ty::UniverseIndex; fn var(self) -> ty::BoundVar; + type Bound: BoundVarLike<I>; + fn new(ui: ty::UniverseIndex, bound: Self::Bound) -> Self; + fn new_anon(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self; fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self; - - fn new(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self; } pub trait IntoKind { @@ -539,13 +544,13 @@ pub trait IntoKind { fn kind(self) -> Self::Kind; } -pub trait BoundVarLike<I: Interner> { +pub trait BoundVarLike<I: Interner>: Copy + Debug + Hash + Eq { fn var(self) -> ty::BoundVar; fn assert_eq(self, var: I::BoundVarKind); } -pub trait ParamLike { +pub trait ParamLike: Copy + Debug + Hash + Eq { fn index(self) -> u32; }
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index cc0925b..033d257 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs
@@ -103,9 +103,9 @@ fn mk_tracked<T: Debug + Clone>( type Ty: Ty<Self>; type Tys: Tys<Self>; type FnInputTys: Copy + Debug + Hash + Eq + SliceLike<Item = Self::Ty> + TypeVisitable<Self>; - type ParamTy: Copy + Debug + Hash + Eq + ParamLike; - type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>; - type PlaceholderTy: PlaceholderLike; + type ParamTy: ParamLike; + type BoundTy: BoundVarLike<Self>; + type PlaceholderTy: PlaceholderLike<Self, Bound = Self::BoundTy>; // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; @@ -131,19 +131,19 @@ fn mk_tracked<T: Debug + Clone>( // Kinds of consts type Const: Const<Self>; - type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq + ParamLike; - type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; + type BoundConst: BoundVarLike<Self>; + type PlaceholderConst: PlaceholderLike<Self, Bound = Self::BoundConst>; type ValueConst: ValueConst<Self>; type ExprConst: ExprConst<Self>; type ValTree: Copy + Debug + Hash + Eq; // Kinds of regions type Region: Region<Self>; - type EarlyParamRegion: Copy + Debug + Hash + Eq + ParamLike; + type EarlyParamRegion: ParamLike; type LateParamRegion: Copy + Debug + Hash + Eq; - type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>; - type PlaceholderRegion: PlaceholderLike; + type BoundRegion: BoundVarLike<Self>; + type PlaceholderRegion: PlaceholderLike<Self, Bound = Self::BoundRegion>; // Predicates type ParamEnv: ParamEnv<Self>;
diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index 0ce927b..a244266 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs
@@ -4,7 +4,7 @@ use crate::data_structures::HashMap; struct Success<X: Cx> { - additional_depth: usize, + required_depth: usize, nested_goals: NestedGoals<X>, result: X::Tracked<X::Result>, } @@ -28,7 +28,7 @@ struct CacheEntry<X: Cx> { #[derive_where(Debug; X: Cx)] pub(super) struct CacheData<'a, X: Cx> { pub(super) result: X::Result, - pub(super) additional_depth: usize, + pub(super) required_depth: usize, pub(super) encountered_overflow: bool, pub(super) nested_goals: &'a NestedGoals<X>, } @@ -47,7 +47,7 @@ pub(super) fn insert( origin_result: X::Result, dep_node: X::DepNodeIndex, - additional_depth: usize, + required_depth: usize, encountered_overflow: bool, nested_goals: NestedGoals<X>, ) { @@ -55,13 +55,13 @@ pub(super) fn insert( let entry = self.map.entry(input).or_default(); if encountered_overflow { let with_overflow = WithOverflow { nested_goals, result }; - let prev = entry.with_overflow.insert(additional_depth, with_overflow); + let prev = entry.with_overflow.insert(required_depth, with_overflow); if let Some(prev) = &prev { assert!(cx.evaluation_is_concurrent()); assert_eq!(cx.get_tracked(&prev.result), origin_result); } } else { - let prev = entry.success.replace(Success { additional_depth, nested_goals, result }); + let prev = entry.success.replace(Success { required_depth, nested_goals, result }); if let Some(prev) = &prev { assert!(cx.evaluation_is_concurrent()); assert_eq!(cx.get_tracked(&prev.result), origin_result); @@ -81,13 +81,13 @@ pub(super) fn get<'a>( mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool, ) -> Option<CacheData<'a, X>> { let entry = self.map.get(&input)?; - if let Some(Success { additional_depth, ref nested_goals, ref result }) = entry.success { - if available_depth.cache_entry_is_applicable(additional_depth) + if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success { + if available_depth.cache_entry_is_applicable(required_depth) && candidate_is_applicable(nested_goals) { return Some(CacheData { result: cx.get_tracked(&result), - additional_depth, + required_depth, encountered_overflow: false, nested_goals, }); @@ -101,7 +101,7 @@ pub(super) fn get<'a>( if candidate_is_applicable(nested_goals) { return Some(CacheData { result: cx.get_tracked(result), - additional_depth, + required_depth: additional_depth, encountered_overflow: true, nested_goals, });
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 1acd5d5..f0eb96b 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -19,13 +19,14 @@ use std::marker::PhantomData; use derive_where::derive_where; -use rustc_index::{Idx, IndexVec}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use tracing::debug; use crate::data_structures::HashMap; +mod stack; +use stack::{Stack, StackDepth, StackEntry}; mod global_cache; use global_cache::CacheData; pub use global_cache::GlobalCache; @@ -225,9 +226,9 @@ impl AvailableDepth { /// in case there is exponential blowup. fn allowed_depth_for_nested<D: Delegate>( root_depth: AvailableDepth, - stack: &IndexVec<StackDepth, StackEntry<D::Cx>>, + stack: &Stack<D::Cx>, ) -> Option<AvailableDepth> { - if let Some(last) = stack.raw.last() { + if let Some(last) = stack.last() { if last.available_depth.0 == 0 { return None; } @@ -433,50 +434,6 @@ fn contains(&self, input: X::Input) -> bool { } } -rustc_index::newtype_index! { - #[orderable] - #[gate_rustc_only] - pub struct StackDepth {} -} - -/// Stack entries of the evaluation stack. Its fields tend to be lazily -/// when popping a child goal or completely immutable. -#[derive_where(Debug; X: Cx)] -struct StackEntry<X: Cx> { - input: X::Input, - - /// Whether proving this goal is a coinductive step. - /// - /// This is used when encountering a trait solver cycle to - /// decide whether the initial provisional result of the cycle. - step_kind_from_parent: PathKind, - - /// The available depth of a given goal, immutable. - available_depth: AvailableDepth, - - /// The maximum depth reached by this stack entry, only up-to date - /// for the top of the stack and lazily updated for the rest. - reached_depth: StackDepth, - - /// All cycle heads this goal depends on. Lazily updated and only - /// up-to date for the top of the stack. - heads: CycleHeads, - - /// Whether evaluating this goal encountered overflow. Lazily updated. - encountered_overflow: bool, - - /// Whether this goal has been used as the root of a cycle. This gets - /// eagerly updated when encountering a cycle. - has_been_used: Option<UsageKind>, - - /// The nested goals of this goal, see the doc comment of the type. - nested_goals: NestedGoals<X>, - - /// Starts out as `None` and gets set when rerunning this - /// goal in case we encounter a cycle. - provisional_result: Option<X::Result>, -} - /// A provisional result of an already computed goals which depends on other /// goals still on the stack. #[derive_where(Debug; X: Cx)] @@ -498,7 +455,7 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. - stack: IndexVec<StackDepth, StackEntry<X>>, + stack: Stack<X>, /// The provisional cache contains entries for already computed goals which /// still depend on goals higher-up in the stack. We don't move them to the /// global cache and track them locally instead. A provisional cache entry @@ -537,16 +494,16 @@ pub fn new(root_depth: usize) -> SearchGraph<D> { /// and using existing global cache entries to make sure they /// have the same impact on the remaining evaluation. fn update_parent_goal( - stack: &mut IndexVec<StackDepth, StackEntry<X>>, + stack: &mut Stack<X>, step_kind_from_parent: PathKind, - reached_depth: StackDepth, + required_depth_for_nested: usize, heads: &CycleHeads, encountered_overflow: bool, context: UpdateParentGoalCtxt<'_, X>, ) { if let Some(parent_index) = stack.last_index() { let parent = &mut stack[parent_index]; - parent.reached_depth = parent.reached_depth.max(reached_depth); + parent.required_depth = parent.required_depth.max(required_depth_for_nested + 1); parent.encountered_overflow |= encountered_overflow; parent.heads.extend_from_child(parent_index, step_kind_from_parent, heads); @@ -588,13 +545,11 @@ pub fn debug_current_depth(&self) -> usize { /// the stack which completes the cycle. This given an inductive step AB which then cycles /// coinductively with A, we need to treat this cycle as coinductive. fn cycle_path_kind( - stack: &IndexVec<StackDepth, StackEntry<X>>, + stack: &Stack<X>, step_kind_to_head: PathKind, head: StackDepth, ) -> PathKind { - stack.raw[head.index() + 1..] - .iter() - .fold(step_kind_to_head, |curr, entry| curr.extend(entry.step_kind_from_parent)) + stack.cycle_step_kinds(head).fold(step_kind_to_head, |curr, step| curr.extend(step)) } /// Probably the most involved method of the whole solver. @@ -656,20 +611,18 @@ pub fn with_new_goal( return result; } - // Unfortunate, it looks like we actually have to compute this goalrar. - let depth = self.stack.next_index(); - let entry = StackEntry { + // Unfortunate, it looks like we actually have to compute this goal. + self.stack.push(StackEntry { input, step_kind_from_parent, available_depth, - reached_depth: depth, + required_depth: 0, heads: Default::default(), encountered_overflow: false, has_been_used: None, nested_goals: Default::default(), provisional_result: None, - }; - assert_eq!(self.stack.push(entry), depth); + }); // This is for global caching, so we properly track query dependencies. // Everything that affects the `result` should be performed within this @@ -686,7 +639,7 @@ pub fn with_new_goal( Self::update_parent_goal( &mut self.stack, final_entry.step_kind_from_parent, - final_entry.reached_depth, + final_entry.required_depth, &final_entry.heads, final_entry.encountered_overflow, UpdateParentGoalCtxt::Ordinary(&final_entry.nested_goals), @@ -700,7 +653,7 @@ pub fn with_new_goal( // the global cache. assert_eq!(result, expected, "input={input:?}"); } else if D::inspect_is_noop(inspect) { - self.insert_global_cache(cx, input, final_entry, result, dep_node) + self.insert_global_cache(cx, final_entry, result, dep_node) } } else if D::ENABLE_PROVISIONAL_CACHE { debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}"); @@ -728,7 +681,7 @@ fn handle_overflow( input: X::Input, inspect: &mut D::ProofTreeBuilder, ) -> X::Result { - if let Some(last) = self.stack.raw.last_mut() { + if let Some(last) = self.stack.last_mut() { last.encountered_overflow = true; // If computing a goal `B` depends on another goal `A` and // `A` has a nested goal which overflows, then computing `B` @@ -859,7 +812,7 @@ fn lookup_provisional_cache( // apply provisional cache entries which encountered overflow once the // current goal is already part of the same cycle. This check could be // improved but seems to be good enough for now. - let last = self.stack.raw.last().unwrap(); + let last = self.stack.last().unwrap(); if last.heads.opt_lowest_cycle_head().is_none_or(|lowest| lowest > head) { continue; } @@ -868,14 +821,10 @@ fn lookup_provisional_cache( // A provisional cache entry is only valid if the current path from its // highest cycle head to the goal is the same. if path_from_head == Self::cycle_path_kind(&self.stack, step_kind_from_parent, head) { - // While we don't have to track the full depth of the provisional cache entry, - // we do have to increment the required depth by one as we'd have already failed - // with overflow otherwise - let next_index = self.stack.next_index(); Self::update_parent_goal( &mut self.stack, step_kind_from_parent, - next_index, + 0, heads, encountered_overflow, UpdateParentGoalCtxt::ProvisionalCacheHit, @@ -893,7 +842,7 @@ fn lookup_provisional_cache( /// evaluating this entry would not have ended up depending on either a goal /// already on the stack or a provisional cache entry. fn candidate_is_applicable( - stack: &IndexVec<StackDepth, StackEntry<X>>, + stack: &Stack<X>, step_kind_from_parent: PathKind, provisional_cache: &HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>, nested_goals: &NestedGoals<X>, @@ -991,7 +940,7 @@ fn lookup_global_cache( available_depth: AvailableDepth, ) -> Option<X::Result> { cx.with_global_cache(|cache| { - let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache + let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( &self.stack, @@ -1001,23 +950,19 @@ fn lookup_global_cache( ) })?; - // Update the reached depth of the current goal to make sure - // its state is the same regardless of whether we've used the - // global cache or not. - let reached_depth = self.stack.next_index().plus(additional_depth); // We don't move cycle participants to the global cache, so the // cycle heads are always empty. let heads = Default::default(); Self::update_parent_goal( &mut self.stack, step_kind_from_parent, - reached_depth, + required_depth, &heads, encountered_overflow, UpdateParentGoalCtxt::Ordinary(nested_goals), ); - debug!(?additional_depth, "global cache hit"); + debug!(?required_depth, "global cache hit"); Some(result) }) } @@ -1028,7 +973,7 @@ fn check_cycle_on_stack( input: X::Input, step_kind_from_parent: PathKind, ) -> Option<X::Result> { - let (head, _stack_entry) = self.stack.iter_enumerated().find(|(_, e)| e.input == input)?; + let head = self.stack.find(input)?; // We have a nested goal which directly relies on a goal deeper in the stack. // // We start by tagging all cycle participants, as that's necessary for caching. @@ -1043,10 +988,9 @@ fn check_cycle_on_stack( // Subtle: when encountering a cyclic goal, we still first checked for overflow, // so we have to update the reached depth. - let next_index = self.stack.next_index(); let last_index = self.stack.last_index().unwrap(); let last = &mut self.stack[last_index]; - last.reached_depth = last.reached_depth.max(next_index); + last.required_depth = last.required_depth.max(1); last.nested_goals.insert(input, step_kind_from_parent.into()); last.nested_goals.insert(last.input, PathsToNested::EMPTY); @@ -1095,7 +1039,7 @@ fn evaluate_goal_in_task( let mut i = 0; loop { let result = evaluate_goal(self, inspect); - let stack_entry = self.stack.pop().unwrap(); + let stack_entry = self.stack.pop(); debug_assert_eq!(stack_entry.input, input); // If the current goal is not the root of a cycle, we are done. @@ -1176,20 +1120,18 @@ fn evaluate_goal_in_task( fn insert_global_cache( &mut self, cx: X, - input: X::Input, final_entry: StackEntry<X>, result: X::Result, dep_node: X::DepNodeIndex, ) { - let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len(); debug!(?final_entry, ?result, "insert global cache"); cx.with_global_cache(|cache| { cache.insert( cx, - input, + final_entry.input, result, dep_node, - additional_depth, + final_entry.required_depth, final_entry.encountered_overflow, final_entry.nested_goals, )
diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs new file mode 100644 index 0000000..8bb247b --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs
@@ -0,0 +1,113 @@ +use std::ops::{Index, IndexMut}; + +use derive_where::derive_where; +use rustc_index::IndexVec; + +use super::{AvailableDepth, Cx, CycleHeads, NestedGoals, PathKind, UsageKind}; + +rustc_index::newtype_index! { + #[orderable] + #[gate_rustc_only] + pub(super) struct StackDepth {} +} + +/// Stack entries of the evaluation stack. Its fields tend to be lazily +/// when popping a child goal or completely immutable. +#[derive_where(Debug; X: Cx)] +pub(super) struct StackEntry<X: Cx> { + pub input: X::Input, + + /// Whether proving this goal is a coinductive step. + /// + /// This is used when encountering a trait solver cycle to + /// decide whether the initial provisional result of the cycle. + pub step_kind_from_parent: PathKind, + + /// The available depth of a given goal, immutable. + pub available_depth: AvailableDepth, + + /// The maximum depth required while evaluating this goal. + pub required_depth: usize, + + /// All cycle heads this goal depends on. Lazily updated and only + /// up-to date for the top of the stack. + pub heads: CycleHeads, + + /// Whether evaluating this goal encountered overflow. Lazily updated. + pub encountered_overflow: bool, + + /// Whether this goal has been used as the root of a cycle. This gets + /// eagerly updated when encountering a cycle. + pub has_been_used: Option<UsageKind>, + + /// The nested goals of this goal, see the doc comment of the type. + pub nested_goals: NestedGoals<X>, + + /// Starts out as `None` and gets set when rerunning this + /// goal in case we encounter a cycle. + pub provisional_result: Option<X::Result>, +} + +#[derive_where(Default; X: Cx)] +pub(super) struct Stack<X: Cx> { + entries: IndexVec<StackDepth, StackEntry<X>>, +} + +impl<X: Cx> Stack<X> { + pub(super) fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + pub(super) fn len(&self) -> usize { + self.entries.len() + } + + pub(super) fn last_index(&self) -> Option<StackDepth> { + self.entries.last_index() + } + + pub(super) fn last(&self) -> Option<&StackEntry<X>> { + self.entries.raw.last() + } + + pub(super) fn last_mut(&mut self) -> Option<&mut StackEntry<X>> { + self.entries.raw.last_mut() + } + + pub(super) fn next_index(&self) -> StackDepth { + self.entries.next_index() + } + + pub(super) fn push(&mut self, entry: StackEntry<X>) -> StackDepth { + self.entries.push(entry) + } + + pub(super) fn pop(&mut self) -> StackEntry<X> { + self.entries.pop().unwrap() + } + + pub(super) fn cycle_step_kinds(&self, head: StackDepth) -> impl Iterator<Item = PathKind> { + self.entries.raw[head.index() + 1..].iter().map(|entry| entry.step_kind_from_parent) + } + + pub(super) fn iter(&self) -> impl Iterator<Item = &StackEntry<X>> { + self.entries.iter() + } + + pub(super) fn find(&self, input: X::Input) -> Option<StackDepth> { + self.entries.iter_enumerated().find(|(_, e)| e.input == input).map(|(idx, _)| idx) + } +} + +impl<X: Cx> Index<StackDepth> for Stack<X> { + type Output = StackEntry<X>; + fn index(&self, index: StackDepth) -> &StackEntry<X> { + &self.entries[index] + } +} + +impl<X: Cx> IndexMut<StackDepth> for Stack<X> { + fn index_mut(&mut self, index: StackDepth) -> &mut Self::Output { + &mut self.entries[index] + } +}
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 2e05c23..ba777c7 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -236,6 +236,14 @@ pub struct ExternalConstraintsData<I: Interner> { pub normalization_nested_goals: NestedNormalizationGoals<I>, } +impl<I: Interner> ExternalConstraintsData<I> { + pub fn is_empty(&self) -> bool { + self.region_constraints.is_empty() + && self.opaque_types.is_empty() + && self.normalization_nested_goals.is_empty() + } +} + #[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 8ba985d..d1ca9bd 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -342,7 +342,7 @@ struct HasRegionsBoundAt { // FIXME: Could be optimized to not walk into components with no escaping bound vars. impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt { type Result = ControlFlow<()>; - fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { self.binder.shift_in(1); t.super_visit_with(self)?; self.binder.shift_out(1);
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index fc3864d..a96ac97 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs
@@ -52,7 +52,7 @@ use thin_vec::ThinVec; use crate::inherent::*; -use crate::{self as ty, Interner, TypeFlags, TypeFoldable}; +use crate::{self as ty, Interner, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -94,7 +94,7 @@ pub trait TypeVisitor<I: Interner>: Sized { #[cfg(not(feature = "nightly"))] type Result: VisitorResult; - fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { t.super_visit_with(self) } @@ -401,7 +401,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { type Result = ControlFlow<FoundFlags>; - fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { // If we're looking for the HAS_BINDER_VARS flag, check if the // binder has vars. This won't be present in the binder's bound // value, so we need to check here too. @@ -510,7 +510,7 @@ struct HasEscapingVarsVisitor { impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor { type Result = ControlFlow<FoundEscapingVars>; - fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1);
diff --git a/library/Cargo.lock b/library/Cargo.lock index 862d093..1bd97e7 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock
@@ -4,11 +4,10 @@ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ - "compiler_builtins", "gimli", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -16,11 +15,10 @@ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -51,11 +49,10 @@ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -81,12 +78,11 @@ [[package]] name = "dlmalloc" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7" +checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-core", "windows-sys", @@ -104,9 +100,9 @@ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", @@ -115,11 +111,10 @@ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -136,11 +131,10 @@ [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -156,33 +150,30 @@ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "object" -version = "0.36.7" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" dependencies = [ - "compiler_builtins", "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -273,11 +264,10 @@ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -352,7 +342,6 @@ version = "0.1.5" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -380,11 +369,10 @@ [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", "rustc-std-workspace-std", ] @@ -402,9 +390,9 @@ [[package]] name = "unwinding" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" +checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751" dependencies = [ "compiler_builtins", "gimli", @@ -413,11 +401,10 @@ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ]
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 5141803..aa9e5fc 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs
@@ -1220,11 +1220,11 @@ pub fn split_off<Q: ?Sized + Ord>(&mut self, value: &Q) -> Self /// assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]); /// ``` #[unstable(feature = "btree_extract_if", issue = "70530")] - pub fn extract_if<'a, F, R>(&'a mut self, range: R, pred: F) -> ExtractIf<'a, T, R, F, A> + pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A> where T: Ord, R: RangeBounds<T>, - F: 'a + FnMut(&T) -> bool, + F: FnMut(&T) -> bool, { let (inner, alloc) = self.map.extract_if_inner(range); ExtractIf { pred, inner, alloc } @@ -1585,11 +1585,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<'a, T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> +impl<T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, R: RangeBounds<T>, - F: 'a + FnMut(&T) -> bool, + F: FnMut(&T) -> bool, { type Item = T;
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 8b448a1..48849bf 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs
@@ -714,6 +714,8 @@ fn deref(&self) -> &CStr { } } +/// Delegates to the [`CStr`] implementation of [`fmt::Debug`], +/// showing invalid UTF-8 as hex escapes. #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ce73215..5bd8256 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs
@@ -109,6 +109,11 @@ mod partial_eq; +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub use self::peek_mut::PeekMut; + +mod peek_mut; + #[cfg(not(no_global_oom_handling))] use self::spec_from_elem::SpecFromElem; @@ -729,6 +734,33 @@ pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Sel pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } + + /// Returns a mutable reference to the last item in the vector, or + /// `None` if it is empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(vec_peek_mut)] + /// let mut vec = Vec::new(); + /// assert!(vec.peek_mut().is_none()); + /// + /// vec.push(1); + /// vec.push(5); + /// vec.push(2); + /// assert_eq!(vec.last(), Some(&2)); + /// if let Some(mut val) = vec.peek_mut() { + /// *val = 0; + /// } + /// assert_eq!(vec.last(), Some(&0)); + /// ``` + #[inline] + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> { + PeekMut::new(self) + } } impl<T, A: Allocator> Vec<T, A> {
diff --git a/library/alloc/src/vec/peek_mut.rs b/library/alloc/src/vec/peek_mut.rs new file mode 100644 index 0000000..c0dd941 --- /dev/null +++ b/library/alloc/src/vec/peek_mut.rs
@@ -0,0 +1,55 @@ +use core::ops::{Deref, DerefMut}; + +use super::Vec; +use crate::fmt; + +/// Structure wrapping a mutable reference to the last item in a +/// `Vec`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See +/// its documentation for more. +/// +/// [`peek_mut`]: Vec::peek_mut +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub struct PeekMut<'a, T> { + vec: &'a mut Vec<T>, +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PeekMut").field(self.deref()).finish() + } +} + +impl<'a, T> PeekMut<'a, T> { + pub(crate) fn new(vec: &'a mut Vec<T>) -> Option<Self> { + if vec.is_empty() { None } else { Some(Self { vec }) } + } + + /// Removes the peeked value from the vector and returns it. + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn pop(self) -> T { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.pop().unwrap_unchecked() } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> Deref for PeekMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked(self.vec.len() - 1) } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> DerefMut for PeekMut<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + let idx = self.vec.len() - 1; + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked_mut(idx) } + } +}
diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 3830958..a41162e 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs
@@ -40,6 +40,7 @@ #![feature(vec_deque_truncate_front)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] +#![feature(vec_peek_mut)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/alloctests/tests/slice.rs b/library/alloctests/tests/slice.rs index 2516563..1e15d54 100644 --- a/library/alloctests/tests/slice.rs +++ b/library/alloctests/tests/slice.rs
@@ -1636,6 +1636,19 @@ fn test_chunk_by() { assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next_back(), None); + + let mut iter = slice.chunk_by(|a, b| a == b); + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next(), Some(&[3, 3][..])); + let mut iter_clone = iter.clone(); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[0][..])); + assert_eq!(iter.next(), None); + assert_eq!(iter_clone.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter_clone.next(), Some(&[1][..])); + assert_eq!(iter_clone.next(), Some(&[0][..])); + assert_eq!(iter_clone.next(), None); } #[test]
diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index f430d97..51b49b8 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs
@@ -2698,6 +2698,23 @@ fn test_pop_if_mutates() { assert_eq!(v, [2]); } +#[test] +fn test_peek_mut() { + let mut vec = Vec::new(); + assert!(vec.peek_mut().is_none()); + vec.push(1); + vec.push(2); + if let Some(mut p) = vec.peek_mut() { + assert_eq!(*p, 2); + *p = 0; + assert_eq!(*p, 0); + p.pop(); + assert_eq!(vec.len(), 1); + } else { + unreachable!() + } +} + /// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments /// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but /// `vec.insert(usize::MAX, val)` once slipped by!
diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml deleted file mode 100644 index 8023ade..0000000 --- a/library/compiler-builtins/.release-plz.toml +++ /dev/null
@@ -1,13 +0,0 @@ -[workspace] -# As part of the release process, we delete `libm/Cargo.toml`. Since -# this is only run in CI, we shouldn't need to worry about it. -allow_dirty = true -publish_allow_dirty = true - -[[package]] -name = "compiler_builtins" -semver_check = false -changelog_include = ["libm"] # libm is included as part of builtins - -[[package]] -name = "libm"
diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fb638f2..41350c6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml
@@ -1,8 +1,8 @@ [workspace] resolver = "2" members = [ + "builtins-shim", "builtins-test", - "compiler-builtins", "crates/josh-sync", "crates/libm-macros", "crates/musl-math-sys", @@ -14,8 +14,8 @@ ] default-members = [ + "builtins-shim", "builtins-test", - "compiler-builtins", "crates/libm-macros", "libm", "libm-test", @@ -26,6 +26,10 @@ # and `mangled-names` disabled, which is the opposite of what is needed for # other tests, so it makes sense to keep it out of the workspace. "builtins-test-intrinsics", + # We test via the `builtins-shim` crate, so exclude the `compiler-builtins` + # that has a dependency on `core`. See `builtins-shim/Cargo.toml` for more + # details. + "compiler-builtins", ] [profile.release]
diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml new file mode 100644 index 0000000..8eb880c --- /dev/null +++ b/library/compiler-builtins/builtins-shim/Cargo.toml
@@ -0,0 +1,63 @@ +# NOTE: Must be kept in sync with `../compiler-builtins/Cargo.toml`. +# +# The manifest at `../compiler-builtins` is what actually gets used in the +# rust-lang/rust tree; however, we can't build it out of tree because it +# depends on `core` by path, and even optional Cargo dependencies need to be +# available at build time. So, we work around this by having this "shim" +# manifest that is identical except for the `core` dependency and forwards +# to the same sources, which acts as the `compiler-builtins` Cargo entrypoint +# for out of tree testing + +[package] +name = "compiler_builtins" +version = "0.1.160" +authors = ["Jorge Aparicio <japaricious@gmail.com>"] +description = "Compiler intrinsics used by the Rust compiler." +repository = "https://github.com/rust-lang/compiler-builtins" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" +edition = "2024" +publish = false +links = "compiler-rt" + +build = "../compiler-builtins/build.rs" + +[lib] +path = "../compiler-builtins/src/lib.rs" +bench = false +doctest = false +test = false + +[build-dependencies] +cc = { optional = true, version = "1.2" } + +[features] +default = ["compiler-builtins"] + +# Enable compilation of C code in compiler-rt, filling in some more optimized +# implementations and also filling in unimplemented intrinsics +c = ["dep:cc"] + +# Workaround for the Cranelift codegen backend. Disables any implementations +# which use inline assembly and fall back to pure Rust versions (if available). +no-asm = [] + +# Workaround for codegen backends which haven't yet implemented `f16` and +# `f128` support. Disabled any intrinsics which use those types. +no-f16-f128 = [] + +# Flag this library as the unstable compiler-builtins lib +compiler-builtins = [] + +# Generate memory-related intrinsics like memcpy +mem = [] + +# Mangle all names so this can be linked in with other versions or other +# compiler-rt implementations. Also used for testing +mangled-names = [] + +# Only used in the compiler's build system +rustc-dep-of-std = ["compiler-builtins"] + +# This makes certain traits and function specializations public that +# are not normally public but are required by the `builtins-test` +unstable-public-internals = []
diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 064b7ca..e73a1f7 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] -compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"] } +compiler_builtins = { path = "../builtins-shim", features = ["compiler-builtins"] } panic-handler = { path = "../crates/panic-handler" } [features]
diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index c7742aa..093d463 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml
@@ -17,7 +17,7 @@ iai-callgrind = { version = "0.14.1", optional = true } [dependencies.compiler_builtins] -path = "../compiler-builtins" +path = "../builtins-shim" default-features = false features = ["unstable-public-internals"]
diff --git a/library/compiler-builtins/builtins-test/tests/lse.rs b/library/compiler-builtins/builtins-test/tests/lse.rs index 53167d9..0d85228 100644 --- a/library/compiler-builtins/builtins-test/tests/lse.rs +++ b/library/compiler-builtins/builtins-test/tests/lse.rs
@@ -1,4 +1,5 @@ #![feature(decl_macro)] // so we can use pub(super) +#![feature(macro_metavar_expr_concat)] #![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))] /// Translate a byte size to a Rust type. @@ -87,7 +88,7 @@ fn $name() { test_op!(clr, |left, right| left & !right); test_op!(xor, std::ops::BitXor::bitxor); test_op!(or, std::ops::BitOr::bitor); - +use compiler_builtins::{foreach_bytes, foreach_ordering}; compiler_builtins::foreach_cas!(cas::test); compiler_builtins::foreach_cas16!(test_cas16); compiler_builtins::foreach_swp!(swap::test);
diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index 5724955..d2baebb 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh
@@ -57,7 +57,7 @@ # Disregard regressions after merge echo "Benchmarks completed with regressions; ignoring (not in a PR)" else - ./ci/ci-util.py handle-banch-regressions "$PR_NUMBER" + ./ci/ci-util.py handle-bench-regressions "$PR_NUMBER" fi }
diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index df8e964..c5446cd 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml
@@ -1,14 +1,18 @@ +# NOTE: Must be kept in sync with `../builtins-shim/Cargo.toml`. +# +# This manifest is actually used in-tree by rust-lang/rust, +# `../builtins-shim/Cargo.toml` is used by out-of-tree testing. See the other +# manifest for further details. + [package] -authors = ["Jorge Aparicio <japaricious@gmail.com>"] name = "compiler_builtins" version = "0.1.160" -license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" -readme = "README.md" -repository = "https://github.com/rust-lang/compiler-builtins" -homepage = "https://github.com/rust-lang/compiler-builtins" -documentation = "https://docs.rs/compiler_builtins" -edition = "2024" +authors = ["Jorge Aparicio <japaricious@gmail.com>"] description = "Compiler intrinsics used by the Rust compiler." +repository = "https://github.com/rust-lang/compiler-builtins" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" +edition = "2024" +publish = false links = "compiler-rt" [lib] @@ -53,7 +57,3 @@ # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] - -[lints.rust] -# The cygwin config can be dropped after our benchmark toolchain is bumped -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)', 'cfg(target_os, values("cygwin"))'] }
diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 7c8da02..018899f 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs
@@ -1,9 +1,6 @@ mod configure; -use std::collections::BTreeMap; use std::env; -use std::path::PathBuf; -use std::sync::atomic::Ordering; use configure::{Target, configure_aliases, configure_f16_f128}; @@ -86,10 +83,6 @@ fn main() { { println!("cargo:rustc-cfg=kernel_user_helpers") } - - if llvm_target[0].starts_with("aarch64") { - generate_aarch64_outlined_atomics(); - } } /// Run configuration for `libm` since it is included directly. @@ -132,61 +125,6 @@ fn configure_libm(target: &Target) { println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\""); } -fn aarch64_symbol(ordering: Ordering) -> &'static str { - match ordering { - Ordering::Relaxed => "relax", - Ordering::Acquire => "acq", - Ordering::Release => "rel", - Ordering::AcqRel => "acq_rel", - _ => panic!("unknown symbol for {ordering:?}"), - } -} - -/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items. -/// Define them from the build script instead. -/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros. -fn generate_aarch64_outlined_atomics() { - use std::fmt::Write; - // #[macro_export] so that we can use this in tests - let gen_macro = - |name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n"); - - // Generate different macros for add/clr/eor/set so that we can test them separately. - let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; - let mut macros = BTreeMap::new(); - for sym in sym_names { - macros.insert(sym, gen_macro(sym)); - } - - // Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. - let mut cas16 = gen_macro("cas16"); - - for ordering in [ - Ordering::Relaxed, - Ordering::Acquire, - Ordering::Release, - Ordering::AcqRel, - ] { - let sym_ordering = aarch64_symbol(ordering); - for size in [1, 2, 4, 8] { - for (sym, macro_) in &mut macros { - let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); - writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); - } - } - let name = format!("__aarch64_cas16_{sym_ordering}"); - writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap(); - } - - let mut buf = String::new(); - for macro_def in macros.values().chain(std::iter::once(&cas16)) { - buf += macro_def; - buf += "}; }\n"; - } - let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap(); -} - /// Emit directives for features we expect to support that aren't in `Cargo.toml`. /// /// These are mostly cfg elements emitted by this `build.rs`.
diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs index 2261212..38fcab1 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs
@@ -262,8 +262,78 @@ macro_rules! or { }; } -// See `generate_aarch64_outlined_atomics` in build.rs. -include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); +#[macro_export] +macro_rules! foreach_ordering { + ($macro:path, $bytes:tt, $name:ident) => { + $macro!( Relaxed, $bytes, ${concat($name, _relax)} ); + $macro!( Acquire, $bytes, ${concat($name, _acq)} ); + $macro!( Release, $bytes, ${concat($name, _rel)} ); + $macro!( AcqRel, $bytes, ${concat($name, _acq_rel)} ); + }; + ($macro:path, $name:ident) => { + $macro!( Relaxed, ${concat($name, _relax)} ); + $macro!( Acquire, ${concat($name, _acq)} ); + $macro!( Release, ${concat($name, _rel)} ); + $macro!( AcqRel, ${concat($name, _acq_rel)} ); + }; +} + +#[macro_export] +macro_rules! foreach_bytes { + ($macro:path, $name:ident) => { + foreach_ordering!( $macro, 1, ${concat(__aarch64_, $name, "1")} ); + foreach_ordering!( $macro, 2, ${concat(__aarch64_, $name, "2")} ); + foreach_ordering!( $macro, 4, ${concat(__aarch64_, $name, "4")} ); + foreach_ordering!( $macro, 8, ${concat(__aarch64_, $name, "8")} ); + }; +} + +/// Generate different macros for cas/swp/add/clr/eor/set so that we can test them separately. +#[macro_export] +macro_rules! foreach_cas { + ($macro:path) => { + foreach_bytes!($macro, cas); + }; +} + +/// Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. +#[macro_export] +macro_rules! foreach_cas16 { + ($macro:path) => { + foreach_ordering!($macro, __aarch64_cas16); + }; +} +#[macro_export] +macro_rules! foreach_swp { + ($macro:path) => { + foreach_bytes!($macro, swp); + }; +} +#[macro_export] +macro_rules! foreach_ldadd { + ($macro:path) => { + foreach_bytes!($macro, ldadd); + }; +} +#[macro_export] +macro_rules! foreach_ldclr { + ($macro:path) => { + foreach_bytes!($macro, ldclr); + }; +} +#[macro_export] +macro_rules! foreach_ldeor { + ($macro:path) => { + foreach_bytes!($macro, ldeor); + }; +} +#[macro_export] +macro_rules! foreach_ldset { + ($macro:path) => { + foreach_bytes!($macro, ldset); + }; +} + foreach_cas!(compare_and_swap); foreach_cas16!(compare_and_swap_i128); foreach_swp!(swap);
diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 6549d4c..1cec39d 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs
@@ -8,6 +8,7 @@ #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] +#![feature(macro_metavar_expr_concat)] #![feature(rustc_attrs)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))]
diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index b6fb5ef..63b4d3c 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml
@@ -1,14 +1,12 @@ [package] -authors = ["Jorge Aparicio <jorge@japaric.io>"] -categories = ["no-std"] -description = "libm in pure Rust" -documentation = "https://docs.rs/libm" -keywords = ["libm", "math"] -license = "MIT" name = "libm" -readme = "README.md" -repository = "https://github.com/rust-lang/compiler-builtins" version = "0.2.15" +authors = ["Jorge Aparicio <jorge@japaric.io>"] +description = "libm in pure Rust" +categories = ["no-std"] +keywords = ["libm", "math"] +repository = "https://github.com/rust-lang/compiler-builtins" +license = "MIT" edition = "2021" rust-version = "1.63"
diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs index 2947b78..4813019 100644 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs
@@ -82,22 +82,77 @@ mod tests { fn fmin_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::INFINITY, F::ZERO), + (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ZERO, F::INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::NEG_ONE), + (F::ONE, F::INFINITY, F::ONE), + (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), + (F::NEG_ONE, F::ONE, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::INFINITY, F::ONE, F::ONE), + (F::INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), (F::NAN, F::NAN, F::NAN), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between zeros and NaNs does not matter + assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO); + assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] @@ -125,22 +180,77 @@ fn fmin_spec_tests_f128() { fn fmax_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::INFINITY, F::INFINITY), + (F::ZERO, F::NEG_INFINITY, F::ZERO), (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::ONE), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::INFINITY, F::INFINITY), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ONE), + (F::ONE, F::NEG_ZERO, F::ONE), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::ONE), + (F::ONE, F::INFINITY, F::INFINITY), + (F::ONE, F::NEG_INFINITY, F::ONE), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ONE, F::ONE, F::ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::INFINITY), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::INFINITY, F::NEG_ZERO, F::INFINITY), + (F::INFINITY, F::ONE, F::INFINITY), + (F::INFINITY, F::NEG_ONE, F::INFINITY), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_INFINITY, F::ONE, F::ONE), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::NEG_INFINITY, F::INFINITY, F::INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), (F::NAN, F::NAN, F::NAN), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between zeros and NaNs does not matter + assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO); + assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test]
diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs index b7999e2..8f13086 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs
@@ -74,24 +74,77 @@ mod tests { fn fminimum_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::ZERO, F::ONE, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::ZERO, F::INFINITY, F::ZERO), + (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ZERO, F::NAN, F::NAN), (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ZERO, F::INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ZERO, F::NAN, F::NAN), + (F::ONE, F::ZERO, F::ZERO), + (F::ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::NEG_ONE), + (F::ONE, F::INFINITY, F::ONE), + (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ONE, F::NAN, F::NAN), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), + (F::NEG_ONE, F::ONE, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ONE, F::NAN, F::NAN), + (F::INFINITY, F::ZERO, F::ZERO), + (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::INFINITY, F::ONE, F::ONE), + (F::INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::INFINITY, F::NAN, F::NAN), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NAN), + (F::NAN, F::ZERO, F::NAN), + (F::NAN, F::NEG_ZERO, F::NAN), + (F::NAN, F::ONE, F::NAN), + (F::NAN, F::NEG_ONE, F::NAN), + (F::NAN, F::INFINITY, F::NAN), + (F::NAN, F::NEG_INFINITY, F::NAN), + (F::NAN, F::NAN, F::NAN), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::ONE, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan()); + assert!(f(F::INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::ONE).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan()); + assert!(f(F::NEG_NAN, F::INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] @@ -119,24 +172,77 @@ fn fminimum_spec_tests_f128() { fn fmaximum_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::ZERO, F::ONE, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::ZERO, F::INFINITY, F::INFINITY), + (F::ZERO, F::NEG_INFINITY, F::ZERO), + (F::ZERO, F::NAN, F::NAN), (F::NEG_ZERO, F::ZERO, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::ONE), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::INFINITY, F::INFINITY), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NAN, F::NAN), + (F::ONE, F::ZERO, F::ONE), + (F::ONE, F::NEG_ZERO, F::ONE), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::ONE), + (F::ONE, F::INFINITY, F::INFINITY), + (F::ONE, F::NEG_INFINITY, F::ONE), + (F::ONE, F::NAN, F::NAN), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ONE, F::ONE, F::ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::INFINITY), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NAN, F::NAN), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::INFINITY, F::NEG_ZERO, F::INFINITY), + (F::INFINITY, F::ONE, F::INFINITY), + (F::INFINITY, F::NEG_ONE, F::INFINITY), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::INFINITY), + (F::INFINITY, F::NAN, F::NAN), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_INFINITY, F::ONE, F::ONE), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::NEG_INFINITY, F::INFINITY, F::INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NAN), + (F::NAN, F::ZERO, F::NAN), + (F::NAN, F::NEG_ZERO, F::NAN), + (F::NAN, F::ONE, F::NAN), + (F::NAN, F::NEG_ONE, F::NAN), + (F::NAN, F::INFINITY, F::NAN), + (F::NAN, F::NEG_INFINITY, F::NAN), + (F::NAN, F::NAN, F::NAN), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::ONE, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan()); + assert!(f(F::INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::ONE).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan()); + assert!(f(F::NEG_NAN, F::INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test]
diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs index 180d21f..fadf934 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs
@@ -74,24 +74,77 @@ mod tests { fn fminimum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::ZERO, F::ONE, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::ZERO, F::INFINITY, F::ZERO), + (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ZERO, F::INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::NEG_ONE), + (F::ONE, F::INFINITY, F::ONE), + (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), + (F::NEG_ONE, F::ONE, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::INFINITY, F::ONE, F::ONE), + (F::INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NAN, F::NAN, F::NAN), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + for (x, y, expected) in cases { + let actual = f(x, y); + assert_biteq!(actual, expected, "fminimum_num({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] @@ -119,24 +172,77 @@ fn fminimum_num_spec_tests_f128() { fn fmaximum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::ZERO, F::ONE, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::ZERO, F::INFINITY, F::INFINITY), + (F::ZERO, F::NEG_INFINITY, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), (F::NEG_ZERO, F::ZERO, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::ONE), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::INFINITY, F::INFINITY), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ONE), + (F::ONE, F::NEG_ZERO, F::ONE), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::ONE), + (F::ONE, F::INFINITY, F::INFINITY), + (F::ONE, F::NEG_INFINITY, F::ONE), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ONE, F::ONE, F::ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::INFINITY), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::INFINITY, F::NEG_ZERO, F::INFINITY), + (F::INFINITY, F::ONE, F::INFINITY), + (F::INFINITY, F::NEG_ONE, F::INFINITY), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_INFINITY, F::ONE, F::ONE), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::NEG_INFINITY, F::INFINITY, F::INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NAN, F::NAN, F::NAN), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + for (x, y, expected) in cases { + let actual = f(x, y); + assert_biteq!(actual, expected, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test]
diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 54207e4..b058047 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs
@@ -19,6 +19,5 @@ #[inline] pub fn fmax<F: Float>(x: F, y: F) -> F { let res = if x.is_nan() || x < y { y } else { x }; - // Canonicalize - res * F::ONE + res.canonicalize() }
diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 898828b..55a031e 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs
@@ -4,8 +4,8 @@ //! Per the spec, returns the canonicalized result of: //! - `x` if `x > y` //! - `y` if `y > x` +//! - +0.0 if x and y are zero with opposite signs //! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 //! //! Excluded from our implementation is sNaN handling. @@ -23,6 +23,5 @@ pub fn fmaximum<F: Float>(x: F, y: F) -> F { y }; - // Canonicalize - res * F::ONE + res.canonicalize() }
diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 05df6cb..2dc60b2 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs
@@ -4,10 +4,10 @@ //! Per the spec, returns: //! - `x` if `x > y` //! - `y` if `y > x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 +//! - +0.0 if x and y are zero with opposite signs //! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN +//! - Non-NaN if one operand is NaN +//! - qNaN if both operands are NaNx //! //! Excluded from our implementation is sNaN handling. @@ -15,12 +15,15 @@ #[inline] pub fn fmaximum_num<F: Float>(x: F, y: F) -> F { - let res = if x.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { - y - } else { + let res = if x > y || y.is_nan() { x + } else if y > x || x.is_nan() { + y + } else if x.is_sign_positive() { + x + } else { + y }; - // Canonicalize - res * F::ONE + res.canonicalize() }
diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 0f86364..e2245bf 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs
@@ -19,6 +19,5 @@ #[inline] pub fn fmin<F: Float>(x: F, y: F) -> F { let res = if y.is_nan() || x < y { x } else { y }; - // Canonicalize - res * F::ONE + res.canonicalize() }
diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index 8592ac5..aa68b12 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs
@@ -4,8 +4,8 @@ //! Per the spec, returns the canonicalized result of: //! - `x` if `x < y` //! - `y` if `y < x` +//! - -0.0 if x and y are zero with opposite signs //! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 //! //! Excluded from our implementation is sNaN handling. @@ -23,6 +23,5 @@ pub fn fminimum<F: Float>(x: F, y: F) -> F { y }; - // Canonicalize - res * F::ONE + res.canonicalize() }
diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 6777bbf..265bd46 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs
@@ -4,10 +4,10 @@ //! Per the spec, returns: //! - `x` if `x < y` //! - `y` if `y < x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 +//! - -0.0 if x and y are zero with opposite signs //! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN +//! - Non-NaN if one operand is NaN +//! - qNaN if both operands are NaNx //! //! Excluded from our implementation is sNaN handling. @@ -15,12 +15,15 @@ #[inline] pub fn fminimum_num<F: Float>(x: F, y: F) -> F { - let res = if y.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { - x - } else { + let res = if x > y || x.is_nan() { y + } else if y > x || y.is_nan() { + x + } else if x.is_sign_positive() { + y + } else { + x }; - // Canonicalize - res * F::ONE + res.canonicalize() }
diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index dd9f462..c3e7eee 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs
@@ -190,6 +190,15 @@ fn signum(self) -> Self { Self::ONE.copysign(self) } } + + /// Make a best-effort attempt to canonicalize the number. Note that this is allowed + /// to be a nop and does not always quiet sNaNs. + fn canonicalize(self) -> Self { + // FIXME: LLVM often removes this. We should determine whether we can remove the operation, + // or switch to something based on `llvm.canonicalize` (which has crashes, + // <https://github.com/llvm/llvm-project/issues/32650>). + self * Self::ONE + } } /// Access the associated `Int` type from a float (helper to avoid ambiguous associated types).
diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 2b8fd58..550d2e9 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs
@@ -143,10 +143,12 @@ macro_rules! assert_biteq { let bits = $crate::support::Int::leading_zeros(l.to_bits() - l.to_bits()); assert!( $crate::support::Float::biteq(l, r), - "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + "{}\nl: {l:?} ({lb:#0width$x} {lh})\nr: {r:?} ({rb:#0width$x} {rh})", format_args!($($tt)*), lb = l.to_bits(), + lh = $crate::support::Hexf(l), rb = r.to_bits(), + rh = $crate::support::Hexf(r), width = ((bits / 4) + 2) as usize, );
diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index e05aaa0..7318398 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version
@@ -1 +1 @@ -df8102fe5f24f28a918660b0cd918d7331c3896e +d087f112b7d1323446c7b39a8b616aee7fa56b3d
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 595cc1f..f7a2107 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs
@@ -162,10 +162,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } +/// Shows the underlying bytes as a normal string, with invalid UTF-8 +/// presented as hex escape sequences. #[stable(feature = "cstr_debug", since = "1.3.0")] impl fmt::Debug for CStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"{}\"", self.to_bytes().escape_ascii()) + fmt::Debug::fmt(crate::bstr::ByteStr::from_bytes(self.to_bytes()), f) } }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4434ceb..e0e80fc 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs
@@ -1,5 +1,9 @@ //! Compiler intrinsics. //! +//! The functions in this module are implementation details of `core` and should +//! not be used outside of the standard library. We generally provide access to +//! intrinsics via stable wrapper functions. Use these instead. +//! //! These are the imports making intrinsics available to Rust code. The actual implementations live in the compiler. //! Some of these intrinsics are lowered to MIR in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_transform/src/lower_intrinsics.rs>. //! The remaining intrinsics are implemented for the LLVM backend in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs> @@ -926,8 +930,7 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T { pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T; /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with -/// a size of `count` * `size_of::<T>()` and an alignment of -/// `min_align_of::<T>()` +/// a size of `count` * `size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// This intrinsic does not have a stable counterpart. /// # Safety @@ -941,8 +944,7 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T { #[rustc_nounwind] pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with -/// a size of `count * size_of::<T>()` and an alignment of -/// `min_align_of::<T>()` +/// a size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// The volatile parameter is set to `true`, so it will not be optimized out /// unless size is equal to zero. @@ -952,8 +954,7 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T { #[rustc_nounwind] pub unsafe fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a -/// size of `count * size_of::<T>()` and an alignment of -/// `min_align_of::<T>()`. +/// size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// This intrinsic does not have a stable counterpart. /// # Safety @@ -2649,7 +2650,7 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, re #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn min_align_of<T>() -> usize; +pub const fn align_of<T>() -> usize; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. @@ -2689,7 +2690,7 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, re #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_intrinsic_const_stable_indirect] -pub const unsafe fn min_align_of_val<T: ?Sized>(ptr: *const T) -> usize; +pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize; /// Gets a static string slice containing the name of a type. ///
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 0a5f3ee..73d9a8e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs
@@ -149,8 +149,32 @@ pub const fn forget<T>(t: T) { /// Like [`forget`], but also accepts unsized values. /// -/// This function is just a shim intended to be removed when the `unsized_locals` feature gets -/// stabilized. +/// While Rust does not permit unsized locals since its removal in [#111942] it is +/// still possible to call functions with unsized values from a function argument +/// or in-place construction. +/// +/// ```rust +/// #![feature(unsized_fn_params, forget_unsized)] +/// #![allow(internal_features)] +/// +/// use std::mem::forget_unsized; +/// +/// pub fn in_place() { +/// forget_unsized(*Box::<str>::from("str")); +/// } +/// +/// pub fn param(x: str) { +/// forget_unsized(x); +/// } +/// ``` +/// +/// This works because the compiler will alter these functions to pass the parameter +/// by reference instead. This trick is necessary to support `Box<dyn FnOnce()>: FnOnce()`. +/// See [#68304] and [#71170] for more information. +/// +/// [#111942]: https://github.com/rust-lang/rust/issues/111942 +/// [#68304]: https://github.com/rust-lang/rust/issues/68304 +/// [#71170]: https://github.com/rust-lang/rust/pull/71170 #[inline] #[unstable(feature = "forget_unsized", issue = "none")] pub fn forget_unsized<T: ?Sized>(t: T) { @@ -412,7 +436,7 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize { #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")] pub fn min_align_of<T>() -> usize { - intrinsics::min_align_of::<T>() + intrinsics::align_of::<T>() } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -436,7 +460,7 @@ pub fn min_align_of<T>() -> usize { #[deprecated(note = "use `align_of_val` instead", since = "1.2.0", suggestion = "align_of_val")] pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns the [ABI]-required minimum alignment of a type in bytes. @@ -458,7 +482,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize { #[rustc_promotable] #[rustc_const_stable(feature = "const_align_of", since = "1.24.0")] pub const fn align_of<T>() -> usize { - intrinsics::min_align_of::<T>() + intrinsics::align_of::<T>() } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -477,10 +501,9 @@ pub const fn align_of<T>() -> usize { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")] -#[allow(deprecated)] pub const fn align_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -527,7 +550,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize { #[unstable(feature = "layout_for_ptr", issue = "69835")] pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize { // SAFETY: the caller must provide a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns `true` if dropping values of type `T` matters. @@ -637,8 +660,6 @@ pub const fn needs_drop<T: ?Sized>() -> bool { #[inline(always)] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] -#[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] #[track_caller] #[rustc_const_stable(feature = "const_mem_zeroed", since = "1.75.0")] @@ -677,8 +698,6 @@ pub const fn needs_drop<T: ?Sized>() -> bool { #[must_use] #[deprecated(since = "1.39.0", note = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] -#[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] #[track_caller] pub unsafe fn uninitialized<T>() -> T {
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 65560f6..3a7bc90 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs
@@ -239,7 +239,6 @@ pub const fn isolate_least_significant_one(self) -> Self { /// Basic usage: /// /// ``` - /// #[doc = concat!("let n = -1", stringify!($SelfT), ";")] /// #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")]
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 5c73bdd..ab2fcff 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs
@@ -1053,7 +1053,6 @@ pub const fn is_ascii_control(&self) -> bool { /// # Examples /// /// ``` - /// /// assert_eq!("0", b'0'.escape_ascii().to_string()); /// assert_eq!("\\t", b'\t'.escape_ascii().to_string()); /// assert_eq!("\\r", b'\r'.escape_ascii().to_string());
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index ef7e6f9..26661b2 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs
@@ -98,7 +98,7 @@ pub enum ControlFlow<B, C = ()> { // is a no-op conversion in the `Try` implementation. } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<B, C> ops::Try for ControlFlow<B, C> { type Output = C; type Residual = ControlFlow<B, convert::Infallible>; @@ -117,7 +117,7 @@ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] // Note: manually specifying the residual type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> {
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 1658f0e..87dd873 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs
@@ -194,7 +194,7 @@ #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] pub use self::try_trait::Yeet; pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit}; -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] pub use self::try_trait::{FromResidual, Try}; #[unstable(feature = "coerce_unsized", issue = "18598")] pub use self::unsize::CoerceUnsized;
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index bac8ffb..aebbddb 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs
@@ -112,7 +112,7 @@ /// R::from_output(accum) /// } /// ``` -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_on_unimplemented( on( all(from_desugaring = "TryBlock"), @@ -130,7 +130,7 @@ #[lang = "Try"] pub trait Try: FromResidual { /// The type of the value produced by `?` when *not* short-circuiting. - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] type Output; /// The type of the value passed to [`FromResidual::from_residual`] @@ -154,7 +154,7 @@ pub trait Try: FromResidual { /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual` /// type: that type will have a "hole" in the correct place, and will maintain the /// "foo-ness" of the residual so other types need to opt-in to interconversion. - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] type Residual; /// Constructs the type from its `Output` type. @@ -186,7 +186,7 @@ pub trait Try: FromResidual { /// assert_eq!(r, Some(4)); /// ``` #[lang = "from_output"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn from_output(output: Self::Output) -> Self; /// Used in `?` to decide whether the operator should produce a value @@ -213,7 +213,7 @@ pub trait Try: FromResidual { /// ); /// ``` #[lang = "branch"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; } @@ -303,7 +303,7 @@ pub trait Try: FromResidual { ), )] #[rustc_diagnostic_item = "FromResidual"] -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] pub trait FromResidual<R = <Self as Try>::Residual> { /// Constructs the type from a compatible `Residual` type. /// @@ -326,7 +326,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// ); /// ``` #[lang = "from_residual"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn from_residual(residual: R) -> Self; }
diff --git a/library/core/src/option.rs b/library/core/src/option.rs index c047548..f2a1e90 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs
@@ -2532,7 +2532,7 @@ fn from_iter<I: IntoIterator<Item = Option<A>>>(iter: I) -> Option<V> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T> ops::Try for Option<T> { type Output = T; type Residual = Option<convert::Infallible>; @@ -2551,7 +2551,7 @@ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] // Note: manually specifying the residual type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> {
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 94cfd66..f1eeded 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs
@@ -30,7 +30,7 @@ /// Files are compared as strings, not `Path`, which could be unexpected. /// See [`Location::file`]'s documentation for more discussion. #[lang = "panic_location"] -#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[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 @@ -43,6 +43,17 @@ pub struct Location<'a> { col: u32, } +#[stable(feature = "panic_hooks", since = "1.10.0")] +impl fmt::Debug for Location<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Location") + .field("file", &self.file()) + .field("line", &self.line) + .field("column", &self.col) + .finish() + } +} + impl<'a> Location<'a> { /// Returns the source location of the caller of this function. If that function's caller is /// annotated then its call location will be returned, and so on up the stack to the first call
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index cb1cf81..0ac887f 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs
@@ -1847,6 +1847,8 @@ mod prim_ref {} /// - If `T` is guaranteed to be subject to the [null pointer /// optimization](option/index.html#representation), and `E` is an enum satisfying the following /// requirements, then `T` and `E` are ABI-compatible. Such an enum `E` is called "option-like". +/// - The enum `E` uses the [`Rust` representation], and is not modified by the `align` or +/// `packed` representation modifiers. /// - The enum `E` has exactly two variants. /// - One variant has exactly one field, of type `T`. /// - All fields of the other variant are zero-sized with 1-byte alignment. @@ -1920,6 +1922,7 @@ mod prim_ref {} /// [`Pointer`]: fmt::Pointer /// [`UnwindSafe`]: panic::UnwindSafe /// [`RefUnwindSafe`]: panic::RefUnwindSafe +/// [`Rust` representation]: <https://doc.rust-lang.org/reference/type-layout.html#the-rust-representation> /// /// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because /// these traits are specially known to the compiler.
diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 23e32c2..3a84ea6 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs
@@ -2051,7 +2051,7 @@ fn from_iter<I: IntoIterator<Item = Result<A, E>>>(iter: I) -> Result<V, E> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Result<T, E> { type Output = T; type Residual = Result<convert::Infallible, E>; @@ -2070,7 +2070,7 @@ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> { #[inline] #[track_caller]
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index d91f8bb..b4d9a1b 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs
@@ -128,7 +128,6 @@ pub const fn make_ascii_lowercase(&mut self) { /// # Examples /// /// ``` - /// /// let s = b"0\t\r\n'\"\\\x9d"; /// let escaped = s.escape_ascii().to_string(); /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 85a5e89..6def6ae 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs
@@ -3376,6 +3376,13 @@ fn next_back(&mut self) -> Option<Self::Item> { #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> { + fn clone(&self) -> Self { + Self { slice: self.slice, predicate: self.predicate.clone() } + } +} + #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 4f9f293..04c8d14 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs
@@ -891,6 +891,19 @@ pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> boo /// Err(false)); /// assert_eq!(some_bool.load(Ordering::Relaxed), false); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the + /// [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] @@ -973,6 +986,19 @@ pub fn compare_exchange( /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the + /// [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] @@ -1271,11 +1297,14 @@ pub const fn as_ptr(&self) -> *mut bool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1338,11 +1367,14 @@ pub fn fetch_update<F>( /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1393,11 +1425,14 @@ pub fn try_update( /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1825,6 +1860,20 @@ pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> /// let value = some_ptr.compare_exchange(ptr, other_ptr, /// Ordering::SeqCst, Ordering::Relaxed); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] @@ -1874,6 +1923,20 @@ pub fn compare_exchange( /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] @@ -1917,11 +1980,15 @@ pub fn compare_exchange_weak( /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1992,11 +2059,15 @@ pub fn fetch_update<F>( /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -2057,11 +2128,15 @@ pub fn try_update( /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -2967,6 +3042,20 @@ pub fn compare_and_swap(&self, /// Err(10)); /// assert_eq!(some_var.load(Ordering::Relaxed), 10); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim! This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[$stable_cxchg] #[$cfg_cas] @@ -3016,6 +3105,20 @@ pub fn compare_exchange(&self, /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[$stable_cxchg] #[$cfg_cas] @@ -3246,13 +3349,16 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -3309,13 +3415,16 @@ pub fn fetch_update<F>(&self, /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -3367,13 +3476,17 @@ pub fn try_update( /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples ///
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 6aab221..ca66836 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs
@@ -229,7 +229,7 @@ fn from(t: T) -> Poll<T> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Poll<Result<T, E>> { type Output = Poll<T>; type Residual = Result<convert::Infallible, E>; @@ -249,7 +249,7 @@ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> { #[inline] fn from_residual(x: Result<convert::Infallible, E>) -> Self { @@ -259,7 +259,7 @@ fn from_residual(x: Result<convert::Infallible, E>) -> Self { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Poll<Option<Result<T, E>>> { type Output = Poll<Option<T>>; type Residual = Result<convert::Infallible, E>; @@ -280,7 +280,7 @@ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Option<Result<T, F>>> {
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 9b8fefe..bb7efe5 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs
@@ -104,6 +104,7 @@ pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { /// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot /// be sent across threads. #[stable(feature = "futures_api", since = "1.36.0")] +#[allow(unpredictable_function_pointer_comparisons)] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs index dc34240..7d669cc 100644 --- a/library/coretests/tests/ffi/cstr.rs +++ b/library/coretests/tests/ffi/cstr.rs
@@ -17,7 +17,7 @@ fn compares_as_u8s() { #[test] fn debug() { let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; - assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); + assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n…\xff""#); } #[test]
diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 01770f1..cf78e87 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs
@@ -5,6 +5,8 @@ use std::f128::consts; use std::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + // Note these tolerances make sense around zero, but not for more extreme exponents. /// Default tolerances. Works for values that should be near precise but not exact. Roughly @@ -54,34 +56,6 @@ fn test_num_f128() { // the intrinsics. #[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_min_nan() { - assert_biteq!(f128::NAN.min(2.0), 2.0); - assert_biteq!(2.0f128.min(f128::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_max_nan() { - assert_biteq!(f128::NAN.max(2.0), 2.0); - assert_biteq!(2.0f128.max(f128::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_minimum() { - assert!(f128::NAN.minimum(2.0).is_nan()); - assert!(2.0f128.minimum(f128::NAN).is_nan()); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_maximum() { - assert!(f128::NAN.maximum(2.0).is_nan()); - assert!(2.0f128.maximum(f128::NAN).is_nan()); -} - -#[test] fn test_nan() { let nan: f128 = f128::NAN; assert!(nan.is_nan()); @@ -233,98 +207,6 @@ fn test_classify() { } #[test] -#[cfg(target_has_reliable_f128_math)] -fn test_floor() { - assert_biteq!(1.0f128.floor(), 1.0f128); - assert_biteq!(1.3f128.floor(), 1.0f128); - assert_biteq!(1.5f128.floor(), 1.0f128); - assert_biteq!(1.7f128.floor(), 1.0f128); - assert_biteq!(0.0f128.floor(), 0.0f128); - assert_biteq!((-0.0f128).floor(), -0.0f128); - assert_biteq!((-1.0f128).floor(), -1.0f128); - assert_biteq!((-1.3f128).floor(), -2.0f128); - assert_biteq!((-1.5f128).floor(), -2.0f128); - assert_biteq!((-1.7f128).floor(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_ceil() { - assert_biteq!(1.0f128.ceil(), 1.0f128); - assert_biteq!(1.3f128.ceil(), 2.0f128); - assert_biteq!(1.5f128.ceil(), 2.0f128); - assert_biteq!(1.7f128.ceil(), 2.0f128); - assert_biteq!(0.0f128.ceil(), 0.0f128); - assert_biteq!((-0.0f128).ceil(), -0.0f128); - assert_biteq!((-1.0f128).ceil(), -1.0f128); - assert_biteq!((-1.3f128).ceil(), -1.0f128); - assert_biteq!((-1.5f128).ceil(), -1.0f128); - assert_biteq!((-1.7f128).ceil(), -1.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_round() { - assert_biteq!(2.5f128.round(), 3.0f128); - assert_biteq!(1.0f128.round(), 1.0f128); - assert_biteq!(1.3f128.round(), 1.0f128); - assert_biteq!(1.5f128.round(), 2.0f128); - assert_biteq!(1.7f128.round(), 2.0f128); - assert_biteq!(0.0f128.round(), 0.0f128); - assert_biteq!((-0.0f128).round(), -0.0f128); - assert_biteq!((-1.0f128).round(), -1.0f128); - assert_biteq!((-1.3f128).round(), -1.0f128); - assert_biteq!((-1.5f128).round(), -2.0f128); - assert_biteq!((-1.7f128).round(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_round_ties_even() { - assert_biteq!(2.5f128.round_ties_even(), 2.0f128); - assert_biteq!(1.0f128.round_ties_even(), 1.0f128); - assert_biteq!(1.3f128.round_ties_even(), 1.0f128); - assert_biteq!(1.5f128.round_ties_even(), 2.0f128); - assert_biteq!(1.7f128.round_ties_even(), 2.0f128); - assert_biteq!(0.0f128.round_ties_even(), 0.0f128); - assert_biteq!((-0.0f128).round_ties_even(), -0.0f128); - assert_biteq!((-1.0f128).round_ties_even(), -1.0f128); - assert_biteq!((-1.3f128).round_ties_even(), -1.0f128); - assert_biteq!((-1.5f128).round_ties_even(), -2.0f128); - assert_biteq!((-1.7f128).round_ties_even(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_trunc() { - assert_biteq!(1.0f128.trunc(), 1.0f128); - assert_biteq!(1.3f128.trunc(), 1.0f128); - assert_biteq!(1.5f128.trunc(), 1.0f128); - assert_biteq!(1.7f128.trunc(), 1.0f128); - assert_biteq!(0.0f128.trunc(), 0.0f128); - assert_biteq!((-0.0f128).trunc(), -0.0f128); - assert_biteq!((-1.0f128).trunc(), -1.0f128); - assert_biteq!((-1.3f128).trunc(), -1.0f128); - assert_biteq!((-1.5f128).trunc(), -1.0f128); - assert_biteq!((-1.7f128).trunc(), -1.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_fract() { - assert_biteq!(1.0f128.fract(), 0.0f128); - assert_biteq!(1.3f128.fract(), 0.300000000000000000000000000000000039f128); - assert_biteq!(1.5f128.fract(), 0.5f128); - assert_biteq!(1.7f128.fract(), 0.7f128); - assert_biteq!(0.0f128.fract(), 0.0f128); - assert_biteq!((-0.0f128).fract(), 0.0f128); - assert_biteq!((-1.0f128).fract(), 0.0f128); - assert_biteq!((-1.3f128).fract(), -0.300000000000000000000000000000000039f128); - assert_biteq!((-1.5f128).fract(), -0.5f128); - assert_biteq!((-1.7f128).fract(), -0.699999999999999999999999999999999961f128); -} - -#[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { assert_biteq!(f128::INFINITY.abs(), f128::INFINITY);
diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 4797573..9e91b65 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs
@@ -4,6 +4,8 @@ use std::f16::consts; use std::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Tolerance for results on the order of 10.0e-2 #[allow(unused)] const TOL_N2: f16 = 0.0001; @@ -50,34 +52,6 @@ fn test_num_f16() { // the intrinsics. #[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_min_nan() { - assert_biteq!(f16::NAN.min(2.0), 2.0); - assert_biteq!(2.0f16.min(f16::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_max_nan() { - assert_biteq!(f16::NAN.max(2.0), 2.0); - assert_biteq!(2.0f16.max(f16::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_minimum() { - assert!(f16::NAN.minimum(2.0).is_nan()); - assert!(2.0f16.minimum(f16::NAN).is_nan()); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_maximum() { - assert!(f16::NAN.maximum(2.0).is_nan()); - assert!(2.0f16.maximum(f16::NAN).is_nan()); -} - -#[test] fn test_nan() { let nan: f16 = f16::NAN; assert!(nan.is_nan()); @@ -230,98 +204,6 @@ fn test_classify() { #[test] #[cfg(any(miri, target_has_reliable_f16_math))] -fn test_floor() { - assert_biteq!(1.0f16.floor(), 1.0f16); - assert_biteq!(1.3f16.floor(), 1.0f16); - assert_biteq!(1.5f16.floor(), 1.0f16); - assert_biteq!(1.7f16.floor(), 1.0f16); - assert_biteq!(0.0f16.floor(), 0.0f16); - assert_biteq!((-0.0f16).floor(), -0.0f16); - assert_biteq!((-1.0f16).floor(), -1.0f16); - assert_biteq!((-1.3f16).floor(), -2.0f16); - assert_biteq!((-1.5f16).floor(), -2.0f16); - assert_biteq!((-1.7f16).floor(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_ceil() { - assert_biteq!(1.0f16.ceil(), 1.0f16); - assert_biteq!(1.3f16.ceil(), 2.0f16); - assert_biteq!(1.5f16.ceil(), 2.0f16); - assert_biteq!(1.7f16.ceil(), 2.0f16); - assert_biteq!(0.0f16.ceil(), 0.0f16); - assert_biteq!((-0.0f16).ceil(), -0.0f16); - assert_biteq!((-1.0f16).ceil(), -1.0f16); - assert_biteq!((-1.3f16).ceil(), -1.0f16); - assert_biteq!((-1.5f16).ceil(), -1.0f16); - assert_biteq!((-1.7f16).ceil(), -1.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_round() { - assert_biteq!(2.5f16.round(), 3.0f16); - assert_biteq!(1.0f16.round(), 1.0f16); - assert_biteq!(1.3f16.round(), 1.0f16); - assert_biteq!(1.5f16.round(), 2.0f16); - assert_biteq!(1.7f16.round(), 2.0f16); - assert_biteq!(0.0f16.round(), 0.0f16); - assert_biteq!((-0.0f16).round(), -0.0f16); - assert_biteq!((-1.0f16).round(), -1.0f16); - assert_biteq!((-1.3f16).round(), -1.0f16); - assert_biteq!((-1.5f16).round(), -2.0f16); - assert_biteq!((-1.7f16).round(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_round_ties_even() { - assert_biteq!(2.5f16.round_ties_even(), 2.0f16); - assert_biteq!(1.0f16.round_ties_even(), 1.0f16); - assert_biteq!(1.3f16.round_ties_even(), 1.0f16); - assert_biteq!(1.5f16.round_ties_even(), 2.0f16); - assert_biteq!(1.7f16.round_ties_even(), 2.0f16); - assert_biteq!(0.0f16.round_ties_even(), 0.0f16); - assert_biteq!((-0.0f16).round_ties_even(), -0.0f16); - assert_biteq!((-1.0f16).round_ties_even(), -1.0f16); - assert_biteq!((-1.3f16).round_ties_even(), -1.0f16); - assert_biteq!((-1.5f16).round_ties_even(), -2.0f16); - assert_biteq!((-1.7f16).round_ties_even(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_trunc() { - assert_biteq!(1.0f16.trunc(), 1.0f16); - assert_biteq!(1.3f16.trunc(), 1.0f16); - assert_biteq!(1.5f16.trunc(), 1.0f16); - assert_biteq!(1.7f16.trunc(), 1.0f16); - assert_biteq!(0.0f16.trunc(), 0.0f16); - assert_biteq!((-0.0f16).trunc(), -0.0f16); - assert_biteq!((-1.0f16).trunc(), -1.0f16); - assert_biteq!((-1.3f16).trunc(), -1.0f16); - assert_biteq!((-1.5f16).trunc(), -1.0f16); - assert_biteq!((-1.7f16).trunc(), -1.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_fract() { - assert_biteq!(1.0f16.fract(), 0.0f16); - assert_biteq!(1.3f16.fract(), 0.2998f16); - assert_biteq!(1.5f16.fract(), 0.5f16); - assert_biteq!(1.7f16.fract(), 0.7f16); - assert_biteq!(0.0f16.fract(), 0.0f16); - assert_biteq!((-0.0f16).fract(), 0.0f16); - assert_biteq!((-1.0f16).fract(), 0.0f16); - assert_biteq!((-1.3f16).fract(), -0.2998f16); - assert_biteq!((-1.5f16).fract(), -0.5f16); - assert_biteq!((-1.7f16).fract(), -0.7f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { assert_biteq!(f16::INFINITY.abs(), f16::INFINITY); assert_biteq!(1f16.abs(), 1f16);
diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 98e9695..d2724d1 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs
@@ -2,6 +2,8 @@ use core::f32::consts; use core::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Smallest number const TINY_BITS: u32 = 0x1; @@ -34,30 +36,6 @@ fn test_num_f32() { } #[test] -fn test_min_nan() { - assert_biteq!(f32::NAN.min(2.0), 2.0); - assert_biteq!(2.0f32.min(f32::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_biteq!(f32::NAN.max(2.0), 2.0); - assert_biteq!(2.0f32.max(f32::NAN), 2.0); -} - -#[test] -fn test_minimum() { - assert!(f32::NAN.minimum(2.0).is_nan()); - assert!(2.0f32.minimum(f32::NAN).is_nan()); -} - -#[test] -fn test_maximum() { - assert!(f32::NAN.maximum(2.0).is_nan()); - assert!(2.0f32.maximum(f32::NAN).is_nan()); -} - -#[test] fn test_nan() { let nan: f32 = f32::NAN; assert!(nan.is_nan()); @@ -209,92 +187,6 @@ fn test_classify() { } #[test] -fn test_floor() { - assert_biteq!(f32::math::floor(1.0f32), 1.0f32); - assert_biteq!(f32::math::floor(1.3f32), 1.0f32); - assert_biteq!(f32::math::floor(1.5f32), 1.0f32); - assert_biteq!(f32::math::floor(1.7f32), 1.0f32); - assert_biteq!(f32::math::floor(0.0f32), 0.0f32); - assert_biteq!(f32::math::floor(-0.0f32), -0.0f32); - assert_biteq!(f32::math::floor(-1.0f32), -1.0f32); - assert_biteq!(f32::math::floor(-1.3f32), -2.0f32); - assert_biteq!(f32::math::floor(-1.5f32), -2.0f32); - assert_biteq!(f32::math::floor(-1.7f32), -2.0f32); -} - -#[test] -fn test_ceil() { - assert_biteq!(f32::math::ceil(1.0f32), 1.0f32); - assert_biteq!(f32::math::ceil(1.3f32), 2.0f32); - assert_biteq!(f32::math::ceil(1.5f32), 2.0f32); - assert_biteq!(f32::math::ceil(1.7f32), 2.0f32); - assert_biteq!(f32::math::ceil(0.0f32), 0.0f32); - assert_biteq!(f32::math::ceil(-0.0f32), -0.0f32); - assert_biteq!(f32::math::ceil(-1.0f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.3f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.5f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.7f32), -1.0f32); -} - -#[test] -fn test_round() { - assert_biteq!(f32::math::round(2.5f32), 3.0f32); - assert_biteq!(f32::math::round(1.0f32), 1.0f32); - assert_biteq!(f32::math::round(1.3f32), 1.0f32); - assert_biteq!(f32::math::round(1.5f32), 2.0f32); - assert_biteq!(f32::math::round(1.7f32), 2.0f32); - assert_biteq!(f32::math::round(0.0f32), 0.0f32); - assert_biteq!(f32::math::round(-0.0f32), -0.0f32); - assert_biteq!(f32::math::round(-1.0f32), -1.0f32); - assert_biteq!(f32::math::round(-1.3f32), -1.0f32); - assert_biteq!(f32::math::round(-1.5f32), -2.0f32); - assert_biteq!(f32::math::round(-1.7f32), -2.0f32); -} - -#[test] -fn test_round_ties_even() { - assert_biteq!(f32::math::round_ties_even(2.5f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(1.0f32), 1.0f32); - assert_biteq!(f32::math::round_ties_even(1.3f32), 1.0f32); - assert_biteq!(f32::math::round_ties_even(1.5f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(1.7f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(0.0f32), 0.0f32); - assert_biteq!(f32::math::round_ties_even(-0.0f32), -0.0f32); - assert_biteq!(f32::math::round_ties_even(-1.0f32), -1.0f32); - assert_biteq!(f32::math::round_ties_even(-1.3f32), -1.0f32); - assert_biteq!(f32::math::round_ties_even(-1.5f32), -2.0f32); - assert_biteq!(f32::math::round_ties_even(-1.7f32), -2.0f32); -} - -#[test] -fn test_trunc() { - assert_biteq!(f32::math::trunc(1.0f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.3f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.5f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.7f32), 1.0f32); - assert_biteq!(f32::math::trunc(0.0f32), 0.0f32); - assert_biteq!(f32::math::trunc(-0.0f32), -0.0f32); - assert_biteq!(f32::math::trunc(-1.0f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.3f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.5f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.7f32), -1.0f32); -} - -#[test] -fn test_fract() { - assert_biteq!(f32::math::fract(1.0f32), 0.0f32); - assert_biteq!(f32::math::fract(1.3f32), 0.29999995f32); - assert_biteq!(f32::math::fract(1.5f32), 0.5f32); - assert_biteq!(f32::math::fract(1.7f32), 0.70000005f32); - assert_biteq!(f32::math::fract(0.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-0.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-1.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-1.3f32), -0.29999995f32); - assert_biteq!(f32::math::fract(-1.5f32), -0.5f32); - assert_biteq!(f32::math::fract(-1.7f32), -0.70000005f32); -} - -#[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); assert_biteq!(1f32.abs(), 1f32);
diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index dd5b67c..b2b2393 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs
@@ -2,6 +2,8 @@ use core::f64::consts; use core::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Smallest number const TINY_BITS: u64 = 0x1; @@ -29,18 +31,6 @@ fn test_num_f64() { } #[test] -fn test_min_nan() { - assert_biteq!(f64::NAN.min(2.0), 2.0); - assert_biteq!(2.0f64.min(f64::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_biteq!(f64::NAN.max(2.0), 2.0); - assert_biteq!(2.0f64.max(f64::NAN), 2.0); -} - -#[test] fn test_nan() { let nan: f64 = f64::NAN; assert!(nan.is_nan()); @@ -191,92 +181,6 @@ fn test_classify() { } #[test] -fn test_floor() { - assert_biteq!(f64::math::floor(1.0f64), 1.0f64); - assert_biteq!(f64::math::floor(1.3f64), 1.0f64); - assert_biteq!(f64::math::floor(1.5f64), 1.0f64); - assert_biteq!(f64::math::floor(1.7f64), 1.0f64); - assert_biteq!(f64::math::floor(0.0f64), 0.0f64); - assert_biteq!(f64::math::floor(-0.0f64), -0.0f64); - assert_biteq!(f64::math::floor(-1.0f64), -1.0f64); - assert_biteq!(f64::math::floor(-1.3f64), -2.0f64); - assert_biteq!(f64::math::floor(-1.5f64), -2.0f64); - assert_biteq!(f64::math::floor(-1.7f64), -2.0f64); -} - -#[test] -fn test_ceil() { - assert_biteq!(f64::math::ceil(1.0f64), 1.0f64); - assert_biteq!(f64::math::ceil(1.3f64), 2.0f64); - assert_biteq!(f64::math::ceil(1.5f64), 2.0f64); - assert_biteq!(f64::math::ceil(1.7f64), 2.0f64); - assert_biteq!(f64::math::ceil(0.0f64), 0.0f64); - assert_biteq!(f64::math::ceil(-0.0f64), -0.0f64); - assert_biteq!(f64::math::ceil(-1.0f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.3f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.5f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.7f64), -1.0f64); -} - -#[test] -fn test_round() { - assert_biteq!(f64::math::round(2.5f64), 3.0f64); - assert_biteq!(f64::math::round(1.0f64), 1.0f64); - assert_biteq!(f64::math::round(1.3f64), 1.0f64); - assert_biteq!(f64::math::round(1.5f64), 2.0f64); - assert_biteq!(f64::math::round(1.7f64), 2.0f64); - assert_biteq!(f64::math::round(0.0f64), 0.0f64); - assert_biteq!(f64::math::round(-0.0f64), -0.0f64); - assert_biteq!(f64::math::round(-1.0f64), -1.0f64); - assert_biteq!(f64::math::round(-1.3f64), -1.0f64); - assert_biteq!(f64::math::round(-1.5f64), -2.0f64); - assert_biteq!(f64::math::round(-1.7f64), -2.0f64); -} - -#[test] -fn test_round_ties_even() { - assert_biteq!(f64::math::round_ties_even(2.5f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(1.0f64), 1.0f64); - assert_biteq!(f64::math::round_ties_even(1.3f64), 1.0f64); - assert_biteq!(f64::math::round_ties_even(1.5f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(1.7f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(0.0f64), 0.0f64); - assert_biteq!(f64::math::round_ties_even(-0.0f64), -0.0f64); - assert_biteq!(f64::math::round_ties_even(-1.0f64), -1.0f64); - assert_biteq!(f64::math::round_ties_even(-1.3f64), -1.0f64); - assert_biteq!(f64::math::round_ties_even(-1.5f64), -2.0f64); - assert_biteq!(f64::math::round_ties_even(-1.7f64), -2.0f64); -} - -#[test] -fn test_trunc() { - assert_biteq!(f64::math::trunc(1.0f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.3f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.5f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.7f64), 1.0f64); - assert_biteq!(f64::math::trunc(0.0f64), 0.0f64); - assert_biteq!(f64::math::trunc(-0.0f64), -0.0f64); - assert_biteq!(f64::math::trunc(-1.0f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.3f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.5f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.7f64), -1.0f64); -} - -#[test] -fn test_fract() { - assert_biteq!(f64::math::fract(1.0f64), 0.0f64); - assert_biteq!(f64::math::fract(1.3f64), 0.30000000000000004f64); - assert_biteq!(f64::math::fract(1.5f64), 0.5f64); - assert_biteq!(f64::math::fract(1.7f64), 0.7f64); - assert_biteq!(f64::math::fract(0.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-0.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-1.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-1.3f64), -0.30000000000000004f64); - assert_biteq!(f64::math::fract(-1.5f64), -0.5f64); - assert_biteq!(f64::math::fract(-1.7f64), -0.69999999999999996f64); -} - -#[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); assert_biteq!(1f64.abs(), 1f64);
diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index f9b6c85..6b4f586 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs
@@ -1,9 +1,34 @@ use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. -macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; +/// Set the default tolerance for float comparison based on the type. +trait Approx { + const LIM: Self; +} + +impl Approx for f16 { + const LIM: Self = 1e-3; +} +impl Approx for f32 { + const LIM: Self = 1e-6; +} +impl Approx for f64 { + const LIM: Self = 1e-6; +} +impl Approx for f128 { + const LIM: Self = 1e-9; +} + +/// Determine the tolerance for values of the argument type. +const fn lim_for_ty<T: Approx + Copy>(_x: T) -> T { + T::LIM +} + +// We have runtime ("rt") and const versions of these macros. + +/// Verify that floats are within a tolerance of each other. +macro_rules! assert_approx_eq_rt { + ($a:expr, $b:expr) => {{ assert_approx_eq_rt!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -14,10 +39,18 @@ macro_rules! assert_approx_eq { ); }}; } +macro_rules! assert_approx_eq_const { + ($a:expr, $b:expr) => {{ assert_approx_eq_const!($a, $b, $crate::floats::lim_for_ty($a)) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!(diff <= $lim); + }}; +} /// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0` /// behavior, as well as to ensure exact NaN bitpatterns. -macro_rules! assert_biteq { +macro_rules! assert_biteq_rt { (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ let l = $left; let r = $right; @@ -41,31 +74,49 @@ macro_rules! assert_biteq { if !l.is_nan() && !r.is_nan() { // Also check that standard equality holds, since most tests use `assert_biteq` rather // than `assert_eq`. - assert_eq!(l, r) + assert_eq!(l, r); } }}; ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq!(@inner $left, $right, "\n", $($tt)*) + assert_biteq_rt!(@inner $left, $right, "\n", $($tt)*) }; ($left:expr, $right:expr $(,)?) => { - assert_biteq!(@inner $left, $right, "", "") + assert_biteq_rt!(@inner $left, $right, "", "") + }; +} +macro_rules! assert_biteq_const { + (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ + let l = $left; + let r = $right; + + // Hack to coerce left and right to the same type + let mut _eq_ty = l; + _eq_ty = r; + + assert!(l.to_bits() == r.to_bits()); + + if !l.is_nan() && !r.is_nan() { + // Also check that standard equality holds, since most tests use `assert_biteq` rather + // than `assert_eq`. + assert!(l == r); + } + }}; + ($left:expr, $right:expr , $($tt:tt)*) => { + assert_biteq_const!(@inner $left, $right, "\n", $($tt)*) + }; + ($left:expr, $right:expr $(,)?) => { + assert_biteq_const!(@inner $left, $right, "", "") }; } -mod const_asserts { - // Shadow some assert implementations that would otherwise not compile in a const-context. - // Every macro added here also needs to be added in the `float_test!` macro below. - macro_rules! assert_eq { - ($left:expr, $right:expr $(,)?) => { - std::assert!($left == $right) - }; - ($left:expr, $right:expr, $($arg:tt)+) => { - std::assert!($left == $right, $($arg)+) - }; - } +// Use the runtime version by default. +// This way, they can be shadowed by the const versions. +pub(crate) use {assert_approx_eq_rt as assert_approx_eq, assert_biteq_rt as assert_biteq}; - pub(crate) use assert_eq; -} +// Also make the const version available for re-exports. +#[rustfmt::skip] +pub(crate) use assert_biteq_const; +pub(crate) use assert_approx_eq_const; /// Generate float tests for all our float types, for compile-time and run-time behavior. /// @@ -84,6 +135,7 @@ macro_rules! assert_eq { /// /* write tests here, using `Float` as the type */ /// } /// } +/// ``` macro_rules! float_test { ( name: $name:ident, @@ -101,6 +153,8 @@ macro_rules! float_test { test<$fty:ident> $test:block ) => { mod $name { + use super::*; + #[test] $( $( #[$f16_meta] )+ )? fn test_f16() { @@ -131,7 +185,14 @@ fn test_f128() { $( $( #[$const_meta] )+ )? mod const_ { - use $crate::floats::const_asserts::assert_eq; + #[allow(unused)] + use super::Approx; + // Shadow the runtime versions of the macro with const-compatible versions. + #[allow(unused)] + use $crate::floats::{ + assert_approx_eq_const as assert_approx_eq, + assert_biteq_const as assert_biteq, + }; #[test] $( $( #[$f16_const_meta] )+ )? @@ -196,29 +257,25 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).min(0.0), 0.0); - assert!((0.0 as Float).min(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).min(-0.0), -0.0); - assert!((-0.0 as Float).min(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).min(9.0), 9.0); - assert_eq!((-9.0 as Float).min(0.0), -9.0); - assert_eq!((0.0 as Float).min(9.0), 0.0); - assert!((0.0 as Float).min(9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).min(9.0), -0.0); - assert!((-0.0 as Float).min(9.0).is_sign_negative()); - assert_eq!((-0.0 as Float).min(-9.0), -9.0); - assert_eq!(Float::INFINITY.min(9.0), 9.0); - assert_eq!((9.0 as Float).min(Float::INFINITY), 9.0); - assert_eq!(Float::INFINITY.min(-9.0), -9.0); - assert_eq!((-9.0 as Float).min(Float::INFINITY), -9.0); - assert_eq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); - assert_eq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); - assert_eq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NAN.min(9.0), 9.0); - assert_eq!(Float::NAN.min(-9.0), -9.0); - assert_eq!((9.0 as Float).min(Float::NAN), 9.0); - assert_eq!((-9.0 as Float).min(Float::NAN), -9.0); + assert_biteq!((0.0 as Float).min(0.0), 0.0); + assert_biteq!((-0.0 as Float).min(-0.0), -0.0); + assert_biteq!((9.0 as Float).min(9.0), 9.0); + assert_biteq!((-9.0 as Float).min(0.0), -9.0); + assert_biteq!((0.0 as Float).min(9.0), 0.0); + assert_biteq!((-0.0 as Float).min(9.0), -0.0); + assert_biteq!((-0.0 as Float).min(-9.0), -9.0); + assert_biteq!(Float::INFINITY.min(9.0), 9.0); + assert_biteq!((9.0 as Float).min(Float::INFINITY), 9.0); + assert_biteq!(Float::INFINITY.min(-9.0), -9.0); + assert_biteq!((-9.0 as Float).min(Float::INFINITY), -9.0); + assert_biteq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); + assert_biteq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); + assert_biteq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NAN.min(9.0), 9.0); + assert_biteq!(Float::NAN.min(-9.0), -9.0); + assert_biteq!((9.0 as Float).min(Float::NAN), 9.0); + assert_biteq!((-9.0 as Float).min(Float::NAN), -9.0); assert!(Float::NAN.min(Float::NAN).is_nan()); } } @@ -230,32 +287,26 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).max(0.0), 0.0); - assert!((0.0 as Float).max(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).max(-0.0), -0.0); - assert!((-0.0 as Float).max(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).max(9.0), 9.0); - assert_eq!((-9.0 as Float).max(0.0), 0.0); - assert!((-9.0 as Float).max(0.0).is_sign_positive()); - assert_eq!((-9.0 as Float).max(-0.0), -0.0); - assert!((-9.0 as Float).max(-0.0).is_sign_negative()); - assert_eq!((0.0 as Float).max(9.0), 9.0); - assert_eq!((0.0 as Float).max(-9.0), 0.0); - assert!((0.0 as Float).max(-9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).max(-9.0), -0.0); - assert!((-0.0 as Float).max(-9.0).is_sign_negative()); - assert_eq!(Float::INFINITY.max(9.0), Float::INFINITY); - assert_eq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::INFINITY.max(-9.0), Float::INFINITY); - assert_eq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.max(9.0), 9.0); - assert_eq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); - assert_eq!(Float::NEG_INFINITY.max(-9.0), -9.0); - assert_eq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); - assert_eq!(Float::NAN.max(9.0), 9.0); - assert_eq!(Float::NAN.max(-9.0), -9.0); - assert_eq!((9.0 as Float).max(Float::NAN), 9.0); - assert_eq!((-9.0 as Float).max(Float::NAN), -9.0); + assert_biteq!((0.0 as Float).max(0.0), 0.0); + assert_biteq!((-0.0 as Float).max(-0.0), -0.0); + assert_biteq!((9.0 as Float).max(9.0), 9.0); + assert_biteq!((-9.0 as Float).max(0.0), 0.0); + assert_biteq!((-9.0 as Float).max(-0.0), -0.0); + assert_biteq!((0.0 as Float).max(9.0), 9.0); + assert_biteq!((0.0 as Float).max(-9.0), 0.0); + assert_biteq!((-0.0 as Float).max(-9.0), -0.0); + assert_biteq!(Float::INFINITY.max(9.0), Float::INFINITY); + assert_biteq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::INFINITY.max(-9.0), Float::INFINITY); + assert_biteq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.max(9.0), 9.0); + assert_biteq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); + assert_biteq!(Float::NEG_INFINITY.max(-9.0), -9.0); + assert_biteq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); + assert_biteq!(Float::NAN.max(9.0), 9.0); + assert_biteq!(Float::NAN.max(-9.0), -9.0); + assert_biteq!((9.0 as Float).max(Float::NAN), 9.0); + assert_biteq!((-9.0 as Float).max(Float::NAN), -9.0); assert!(Float::NAN.max(Float::NAN).is_nan()); } } @@ -267,27 +318,22 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).minimum(0.0), 0.0); - assert!((0.0 as Float).minimum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).minimum(0.0), -0.0); - assert!((-0.0 as Float).minimum(0.0).is_sign_negative()); - assert_eq!((-0.0 as Float).minimum(-0.0), -0.0); - assert!((-0.0 as Float).minimum(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).minimum(9.0), 9.0); - assert_eq!((-9.0 as Float).minimum(0.0), -9.0); - assert_eq!((0.0 as Float).minimum(9.0), 0.0); - assert!((0.0 as Float).minimum(9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).minimum(9.0), -0.0); - assert!((-0.0 as Float).minimum(9.0).is_sign_negative()); - assert_eq!((-0.0 as Float).minimum(-9.0), -9.0); - assert_eq!(Float::INFINITY.minimum(9.0), 9.0); - assert_eq!((9.0 as Float).minimum(Float::INFINITY), 9.0); - assert_eq!(Float::INFINITY.minimum(-9.0), -9.0); - assert_eq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); - assert_eq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); - assert_eq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); - assert_eq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!((0.0 as Float).minimum(0.0), 0.0); + assert_biteq!((-0.0 as Float).minimum(0.0), -0.0); + assert_biteq!((-0.0 as Float).minimum(-0.0), -0.0); + assert_biteq!((9.0 as Float).minimum(9.0), 9.0); + assert_biteq!((-9.0 as Float).minimum(0.0), -9.0); + assert_biteq!((0.0 as Float).minimum(9.0), 0.0); + assert_biteq!((-0.0 as Float).minimum(9.0), -0.0); + assert_biteq!((-0.0 as Float).minimum(-9.0), -9.0); + assert_biteq!(Float::INFINITY.minimum(9.0), 9.0); + assert_biteq!((9.0 as Float).minimum(Float::INFINITY), 9.0); + assert_biteq!(Float::INFINITY.minimum(-9.0), -9.0); + assert_biteq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); + assert_biteq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); + assert_biteq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); + assert_biteq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); assert!(Float::NAN.minimum(9.0).is_nan()); assert!(Float::NAN.minimum(-9.0).is_nan()); assert!((9.0 as Float).minimum(Float::NAN).is_nan()); @@ -303,30 +349,23 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).maximum(0.0), 0.0); - assert!((0.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(0.0), 0.0); - assert!((-0.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(-0.0), -0.0); - assert!((-0.0 as Float).maximum(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).maximum(9.0), 9.0); - assert_eq!((-9.0 as Float).maximum(0.0), 0.0); - assert!((-9.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-9.0 as Float).maximum(-0.0), -0.0); - assert!((-9.0 as Float).maximum(-0.0).is_sign_negative()); - assert_eq!((0.0 as Float).maximum(9.0), 9.0); - assert_eq!((0.0 as Float).maximum(-9.0), 0.0); - assert!((0.0 as Float).maximum(-9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(-9.0), -0.0); - assert!((-0.0 as Float).maximum(-9.0).is_sign_negative()); - assert_eq!(Float::INFINITY.maximum(9.0), Float::INFINITY); - assert_eq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); - assert_eq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.maximum(9.0), 9.0); - assert_eq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); - assert_eq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); - assert_eq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); + assert_biteq!((0.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(-0.0), -0.0); + assert_biteq!((9.0 as Float).maximum(9.0), 9.0); + assert_biteq!((-9.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-9.0 as Float).maximum(-0.0), -0.0); + assert_biteq!((0.0 as Float).maximum(9.0), 9.0); + assert_biteq!((0.0 as Float).maximum(-9.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(-9.0), -0.0); + assert_biteq!(Float::INFINITY.maximum(9.0), Float::INFINITY); + assert_biteq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); + assert_biteq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.maximum(9.0), 9.0); + assert_biteq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); + assert_biteq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); + assert_biteq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); assert!(Float::NAN.maximum(9.0).is_nan()); assert!(Float::NAN.maximum(-9.0).is_nan()); assert!((9.0 as Float).maximum(Float::NAN).is_nan()); @@ -342,41 +381,43 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.5 as Float).midpoint(0.5), 0.5); - assert_eq!((0.5 as Float).midpoint(2.5), 1.5); - assert_eq!((3.0 as Float).midpoint(4.0), 3.5); - assert_eq!((-3.0 as Float).midpoint(4.0), 0.5); - assert_eq!((3.0 as Float).midpoint(-4.0), -0.5); - assert_eq!((-3.0 as Float).midpoint(-4.0), -3.5); - assert_eq!((0.0 as Float).midpoint(0.0), 0.0); - assert_eq!((-0.0 as Float).midpoint(-0.0), -0.0); - assert_eq!((-5.0 as Float).midpoint(5.0), 0.0); - assert_eq!(Float::MAX.midpoint(Float::MIN), 0.0); - assert_eq!(Float::MIN.midpoint(Float::MAX), -0.0); - assert_eq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); - assert_eq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); - assert_eq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); - assert_eq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); - assert_eq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); - assert_eq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); - assert_eq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); - assert_eq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); - assert_eq!(Float::MAX.midpoint(Float::MAX), Float::MAX); - assert_eq!( + assert_biteq!((0.5 as Float).midpoint(0.5), 0.5); + assert_biteq!((0.5 as Float).midpoint(2.5), 1.5); + assert_biteq!((3.0 as Float).midpoint(4.0), 3.5); + assert_biteq!((-3.0 as Float).midpoint(4.0), 0.5); + assert_biteq!((3.0 as Float).midpoint(-4.0), -0.5); + assert_biteq!((-3.0 as Float).midpoint(-4.0), -3.5); + assert_biteq!((0.0 as Float).midpoint(0.0), 0.0); + assert_biteq!((-0.0 as Float).midpoint(-0.0), -0.0); + assert_biteq!((-5.0 as Float).midpoint(5.0), 0.0); + assert_biteq!(Float::MAX.midpoint(Float::MIN), 0.0); + assert_biteq!(Float::MIN.midpoint(Float::MAX), 0.0); + assert_biteq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); + assert_biteq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_biteq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); + assert_biteq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_biteq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_biteq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_biteq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_biteq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_biteq!(Float::MAX.midpoint(Float::MAX), Float::MAX); + assert_biteq!( (Float::MIN_POSITIVE).midpoint(Float::MIN_POSITIVE), Float::MIN_POSITIVE ); - assert_eq!( + assert_biteq!( (-Float::MIN_POSITIVE).midpoint(-Float::MIN_POSITIVE), -Float::MIN_POSITIVE ); - assert_eq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); - assert_eq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); - assert_eq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); - assert_eq!( + assert_biteq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); + assert_biteq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); + assert_biteq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); + assert_biteq!( Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), Float::NEG_INFINITY ); + assert!(Float::NEG_INFINITY.midpoint(Float::INFINITY).is_nan()); + assert!(Float::INFINITY.midpoint(Float::NEG_INFINITY).is_nan()); assert!(Float::NAN.midpoint(1.0).is_nan()); assert!((1.0 as Float).midpoint(Float::NAN).is_nan()); assert!(Float::NAN.midpoint(Float::NAN).is_nan()); @@ -410,7 +451,7 @@ pub fn test_num<T>(ten: T, two: T) let naive = (large + small) / 2.0; let midpoint = large.midpoint(small); - assert_eq!(naive, midpoint); + assert_biteq!(naive, midpoint); } } } @@ -423,10 +464,10 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((-1.0 as Float).abs(), 1.0); - assert_eq!((1.0 as Float).abs(), 1.0); - assert_eq!(Float::NEG_INFINITY.abs(), Float::INFINITY); - assert_eq!(Float::INFINITY.abs(), Float::INFINITY); + assert_biteq!((-1.0 as Float).abs(), 1.0); + assert_biteq!((1.0 as Float).abs(), 1.0); + assert_biteq!(Float::NEG_INFINITY.abs(), Float::INFINITY); + assert_biteq!(Float::INFINITY.abs(), Float::INFINITY); } } @@ -437,10 +478,10 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((1.0 as Float).copysign(-2.0), -1.0); - assert_eq!((-1.0 as Float).copysign(2.0), 1.0); - assert_eq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); + assert_biteq!((1.0 as Float).copysign(-2.0), -1.0); + assert_biteq!((-1.0 as Float).copysign(2.0), 1.0); + assert_biteq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); } } @@ -453,7 +494,7 @@ pub fn test_num<T>(ten: T, two: T) }, test<Float> { assert!(Float::INFINITY.rem_euclid(42.0 as Float).is_nan()); - assert_eq!((42.0 as Float).rem_euclid(Float::INFINITY), (42.0 as Float)); + assert_biteq!((42.0 as Float).rem_euclid(Float::INFINITY), 42.0 as Float); assert!((42.0 as Float).rem_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.rem_euclid(Float::INFINITY).is_nan()); assert!(Float::INFINITY.rem_euclid(Float::NAN).is_nan()); @@ -469,7 +510,7 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); + assert_biteq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); assert!((42.0 as Float).div_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan()); assert!(Float::INFINITY.div_euclid(Float::NAN).is_nan()); @@ -484,20 +525,25 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).floor(), 0.0); - assert!((0.0 as Float).floor().is_sign_positive()); - assert_eq!((-0.0 as Float).floor(), -0.0); - assert!((-0.0 as Float).floor().is_sign_negative()); - assert_eq!((0.5 as Float).floor(), 0.0); - assert_eq!((-0.5 as Float).floor(), -1.0); - assert_eq!((1.5 as Float).floor(), 1.0); - assert_eq!(Float::MAX.floor(), Float::MAX); - assert_eq!(Float::MIN.floor(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.floor(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).floor(), -1.0); + assert_biteq!((1.0 as Float).floor(), 1.0); + assert_biteq!((1.3 as Float).floor(), 1.0); + assert_biteq!((1.5 as Float).floor(), 1.0); + assert_biteq!((1.7 as Float).floor(), 1.0); + assert_biteq!((0.5 as Float).floor(), 0.0); + assert_biteq!((0.0 as Float).floor(), 0.0); + assert_biteq!((-0.0 as Float).floor(), -0.0); + assert_biteq!((-0.5 as Float).floor(), -1.0); + assert_biteq!((-1.0 as Float).floor(), -1.0); + assert_biteq!((-1.3 as Float).floor(), -2.0); + assert_biteq!((-1.5 as Float).floor(), -2.0); + assert_biteq!((-1.7 as Float).floor(), -2.0); + assert_biteq!(Float::MAX.floor(), Float::MAX); + assert_biteq!(Float::MIN.floor(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.floor(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).floor(), -1.0); assert!(Float::NAN.floor().is_nan()); - assert_eq!(Float::INFINITY.floor(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.floor(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); } } @@ -508,19 +554,25 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).ceil(), 0.0); - assert!((0.0 as Float).ceil().is_sign_positive()); - assert_eq!((-0.0 as Float).ceil(), 0.0); - assert!((-0.0 as Float).ceil().is_sign_negative()); - assert_eq!((0.5 as Float).ceil(), 1.0); - assert_eq!((-0.5 as Float).ceil(), 0.0); - assert_eq!(Float::MAX.ceil(), Float::MAX); - assert_eq!(Float::MIN.ceil(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.ceil(), 1.0); - assert_eq!((-Float::MIN_POSITIVE).ceil(), 0.0); + assert_biteq!((1.0 as Float).ceil(), 1.0); + assert_biteq!((1.3 as Float).ceil(), 2.0); + assert_biteq!((1.5 as Float).ceil(), 2.0); + assert_biteq!((1.7 as Float).ceil(), 2.0); + assert_biteq!((0.5 as Float).ceil(), 1.0); + assert_biteq!((0.0 as Float).ceil(), 0.0); + assert_biteq!((-0.0 as Float).ceil(), -0.0); + assert_biteq!((-0.5 as Float).ceil(), -0.0); + assert_biteq!((-1.0 as Float).ceil(), -1.0); + assert_biteq!((-1.3 as Float).ceil(), -1.0); + assert_biteq!((-1.5 as Float).ceil(), -1.0); + assert_biteq!((-1.7 as Float).ceil(), -1.0); + assert_biteq!(Float::MAX.ceil(), Float::MAX); + assert_biteq!(Float::MIN.ceil(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.ceil(), 1.0); + assert_biteq!((-Float::MIN_POSITIVE).ceil(), -0.0); assert!(Float::NAN.ceil().is_nan()); - assert_eq!(Float::INFINITY.ceil(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.ceil(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); } } @@ -531,19 +583,26 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).round(), 0.0); - assert!((0.0 as Float).round().is_sign_positive()); - assert_eq!((-0.0 as Float).round(), -0.0); - assert!((-0.0 as Float).round().is_sign_negative()); - assert_eq!((0.5 as Float).round(), 1.0); - assert_eq!((-0.5 as Float).round(), -1.0); - assert_eq!(Float::MAX.round(), Float::MAX); - assert_eq!(Float::MIN.round(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.round(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).round(), 0.0); + assert_biteq!((2.5 as Float).round(), 3.0); + assert_biteq!((1.0 as Float).round(), 1.0); + assert_biteq!((1.3 as Float).round(), 1.0); + assert_biteq!((1.5 as Float).round(), 2.0); + assert_biteq!((1.7 as Float).round(), 2.0); + assert_biteq!((0.5 as Float).round(), 1.0); + assert_biteq!((0.0 as Float).round(), 0.0); + assert_biteq!((-0.0 as Float).round(), -0.0); + assert_biteq!((-0.5 as Float).round(), -1.0); + assert_biteq!((-1.0 as Float).round(), -1.0); + assert_biteq!((-1.3 as Float).round(), -1.0); + assert_biteq!((-1.5 as Float).round(), -2.0); + assert_biteq!((-1.7 as Float).round(), -2.0); + assert_biteq!(Float::MAX.round(), Float::MAX); + assert_biteq!(Float::MIN.round(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.round(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).round(), -0.0); assert!(Float::NAN.round().is_nan()); - assert_eq!(Float::INFINITY.round(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.round(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); } } @@ -554,21 +613,26 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).round_ties_even(), 0.0); - assert!((0.0 as Float).round_ties_even().is_sign_positive()); - assert_eq!((-0.0 as Float).round_ties_even(), -0.0); - assert!((-0.0 as Float).round_ties_even().is_sign_negative()); - assert_eq!((0.5 as Float).round_ties_even(), 0.0); - assert!((0.5 as Float).round_ties_even().is_sign_positive()); - assert_eq!((-0.5 as Float).round_ties_even(), -0.0); - assert!((-0.5 as Float).round_ties_even().is_sign_negative()); - assert_eq!(Float::MAX.round_ties_even(), Float::MAX); - assert_eq!(Float::MIN.round_ties_even(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).round_ties_even(), 0.0); + assert_biteq!((2.5 as Float).round_ties_even(), 2.0); + assert_biteq!((1.0 as Float).round_ties_even(), 1.0); + assert_biteq!((1.3 as Float).round_ties_even(), 1.0); + assert_biteq!((1.5 as Float).round_ties_even(), 2.0); + assert_biteq!((1.7 as Float).round_ties_even(), 2.0); + assert_biteq!((0.5 as Float).round_ties_even(), 0.0); + assert_biteq!((0.0 as Float).round_ties_even(), 0.0); + assert_biteq!((-0.0 as Float).round_ties_even(), -0.0); + assert_biteq!((-0.5 as Float).round_ties_even(), -0.0); + assert_biteq!((-1.0 as Float).round_ties_even(), -1.0); + assert_biteq!((-1.3 as Float).round_ties_even(), -1.0); + assert_biteq!((-1.5 as Float).round_ties_even(), -2.0); + assert_biteq!((-1.7 as Float).round_ties_even(), -2.0); + assert_biteq!(Float::MAX.round_ties_even(), Float::MAX); + assert_biteq!(Float::MIN.round_ties_even(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).round_ties_even(), -0.0); assert!(Float::NAN.round_ties_even().is_nan()); - assert_eq!(Float::INFINITY.round_ties_even(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.round_ties_even(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); } } @@ -579,21 +643,25 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).trunc(), 0.0); - assert!((0.0 as Float).trunc().is_sign_positive()); - assert_eq!((-0.0 as Float).trunc(), -0.0); - assert!((-0.0 as Float).trunc().is_sign_negative()); - assert_eq!((0.5 as Float).trunc(), 0.0); - assert!((0.5 as Float).trunc().is_sign_positive()); - assert_eq!((-0.5 as Float).trunc(), -0.0); - assert!((-0.5 as Float).trunc().is_sign_negative()); - assert_eq!(Float::MAX.trunc(), Float::MAX); - assert_eq!(Float::MIN.trunc(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.trunc(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).trunc(), 0.0); + assert_biteq!((1.0 as Float).trunc(), 1.0); + assert_biteq!((1.3 as Float).trunc(), 1.0); + assert_biteq!((1.5 as Float).trunc(), 1.0); + assert_biteq!((1.7 as Float).trunc(), 1.0); + assert_biteq!((0.5 as Float).trunc(), 0.0); + assert_biteq!((0.0 as Float).trunc(), 0.0); + assert_biteq!((-0.0 as Float).trunc(), -0.0); + assert_biteq!((-0.5 as Float).trunc(), -0.0); + assert_biteq!((-1.0 as Float).trunc(), -1.0); + assert_biteq!((-1.3 as Float).trunc(), -1.0); + assert_biteq!((-1.5 as Float).trunc(), -1.0); + assert_biteq!((-1.7 as Float).trunc(), -1.0); + assert_biteq!(Float::MAX.trunc(), Float::MAX); + assert_biteq!(Float::MIN.trunc(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.trunc(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).trunc(), -0.0); assert!(Float::NAN.trunc().is_nan()); - assert_eq!(Float::INFINITY.trunc(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.trunc(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); } } @@ -604,19 +672,23 @@ pub fn test_num<T>(ten: T, two: T) f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).fract(), 0.0); - assert!((0.0 as Float).fract().is_sign_positive()); - assert_eq!((-0.0 as Float).fract(), 0.0); - assert!((-0.0 as Float).fract().is_sign_positive()); - assert_eq!((0.5 as Float).fract(), 0.5); - assert!((0.5 as Float).fract().is_sign_positive()); - assert_eq!((-0.5 as Float).fract(), -0.5); - assert!((-0.5 as Float).fract().is_sign_negative()); - assert_eq!(Float::MAX.fract(), 0.0); - assert_eq!(Float::MIN.fract(), 0.0); - assert_eq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); + assert_biteq!((1.0 as Float).fract(), 0.0); + assert_approx_eq!((1.3 as Float).fract(), 0.3); // rounding differs between float types + assert_biteq!((1.5 as Float).fract(), 0.5); + assert_approx_eq!((1.7 as Float).fract(), 0.7); + assert_biteq!((0.5 as Float).fract(), 0.5); + assert_biteq!((0.0 as Float).fract(), 0.0); + assert_biteq!((-0.0 as Float).fract(), 0.0); + assert_biteq!((-0.5 as Float).fract(), -0.5); + assert_biteq!((-1.0 as Float).fract(), 0.0); + assert_approx_eq!((-1.3 as Float).fract(), -0.3); // rounding differs between float types + assert_biteq!((-1.5 as Float).fract(), -0.5); + assert_approx_eq!((-1.7 as Float).fract(), -0.7); + assert_biteq!(Float::MAX.fract(), 0.0); + assert_biteq!(Float::MIN.fract(), 0.0); + assert_biteq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); assert!(Float::MIN_POSITIVE.fract().is_sign_positive()); - assert_eq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); + assert_biteq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); assert!((-Float::MIN_POSITIVE).fract().is_sign_negative()); assert!(Float::NAN.fract().is_nan()); assert!(Float::INFINITY.fract().is_nan());
diff --git a/library/coretests/tests/panic/location.rs b/library/coretests/tests/panic/location.rs index d20241d..5ce0b06 100644 --- a/library/coretests/tests/panic/location.rs +++ b/library/coretests/tests/panic/location.rs
@@ -29,3 +29,11 @@ fn location_const_column() { const COLUMN: u32 = CALLER.column(); assert_eq!(COLUMN, 40); } + +#[test] +fn location_debug() { + let f = format!("{:?}", Location::caller()); + assert!(f.contains(&format!("{:?}", file!()))); + assert!(f.contains("35")); + assert!(f.contains("29")); +}
diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index bb60fb0..197a144 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs
@@ -653,7 +653,6 @@ fn thin_box() { // if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added. // * Constructing a `ThinBox` without consuming and deallocating a `Box` // requires either the unstable `Unsize` marker trait, - // or the unstable `unsized_locals` language feature, // or taking `&dyn T` and restricting to `T: Copy`. use std::alloc::*;
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 75d82d7..d60a76f 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs
@@ -7,9 +7,6 @@ //! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). #![deny(unsafe_code)] -// proc_macros anyway don't work on wasm hosts so while both sides of this bridge can -// be built with different versions of rustc, the wasm ABI changes don't really matter. -#![allow(wasm_c_abi)] use std::hash::Hash; use std::ops::{Bound, Range};
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 53d78dc..ae71079 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml
@@ -32,7 +32,7 @@ [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.8.0", optional = true, default-features = false } -addr2line = { version = "0.24.0", optional = true, default-features = false } +addr2line = { version = "0.25.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.172", default-features = false, features = [ @@ -40,7 +40,7 @@ ], public = true } [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'elf', 'macho', @@ -50,7 +50,7 @@ ] } [target.'cfg(target_os = "aix")'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'xcoff', 'unaligned',
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6cbf8301..865ea62 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs
@@ -121,7 +121,7 @@ pub struct File { /// /// [`try_lock`]: File::try_lock /// [`try_lock_shared`]: File::try_lock_shared -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub enum TryLockError { /// The lock could not be acquired due to an I/O error on the file. The standard library will /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`] @@ -153,9 +153,8 @@ pub enum TryLockError { /// dependent. /// /// # Errors -/// -/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent -/// IO error during iteration. +/// This [`io::Result`] will be an [`Err`] if an error occurred while fetching +/// the next entry from the OS. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct ReadDir(fs_imp::ReadDir); @@ -367,10 +366,10 @@ fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { inner(path.as_ref(), contents.as_ref()) } -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl error::Error for TryLockError {} -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -380,7 +379,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl fmt::Display for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -391,7 +390,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl From<TryLockError> for io::Error { fn from(err: TryLockError) -> io::Error { match err { @@ -714,7 +713,6 @@ pub fn sync_data(&self) -> io::Result<()> { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -723,7 +721,7 @@ pub fn sync_data(&self) -> io::Result<()> { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn lock(&self) -> io::Result<()> { self.inner.lock() } @@ -767,7 +765,6 @@ pub fn lock(&self) -> io::Result<()> { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -776,7 +773,7 @@ pub fn lock(&self) -> io::Result<()> { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn lock_shared(&self) -> io::Result<()> { self.inner.lock_shared() } @@ -825,7 +822,6 @@ pub fn lock_shared(&self) -> io::Result<()> { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { @@ -841,7 +837,7 @@ pub fn lock_shared(&self) -> io::Result<()> { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn try_lock(&self) -> Result<(), TryLockError> { self.inner.try_lock() } @@ -889,7 +885,6 @@ pub fn try_lock(&self) -> Result<(), TryLockError> { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { @@ -906,7 +901,7 @@ pub fn try_lock(&self) -> Result<(), TryLockError> { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.inner.try_lock_shared() } @@ -934,7 +929,6 @@ pub fn try_lock_shared(&self) -> Result<(), TryLockError> { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -944,7 +938,7 @@ pub fn try_lock_shared(&self) -> Result<(), TryLockError> { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn unlock(&self) -> io::Result<()> { self.inner.unlock() }
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index cb1246d..fd6fe72 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs
@@ -1,3 +1,4 @@ +use crate::bstr::ByteStr; use crate::ffi::OsStr; #[cfg(any(doc, target_os = "android", target_os = "linux"))] use crate::os::net::linux_ext; @@ -61,7 +62,7 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s enum AddressKind<'a> { Unnamed, Pathname(&'a Path), - Abstract(&'a [u8]), + Abstract(&'a ByteStr), } /// An address associated with a Unix socket. @@ -245,7 +246,7 @@ fn address(&self) -> AddressKind<'_> { { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) + AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) } else { AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) } @@ -260,7 +261,7 @@ impl Sealed for SocketAddr {} #[stable(feature = "unix_socket_abstract", since = "1.70.0")] impl linux_ext::addr::SocketAddrExt for SocketAddr { fn as_abstract_name(&self) -> Option<&[u8]> { - if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } + if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None } } fn from_abstract_name<N>(name: N) -> crate::io::Result<Self> @@ -295,7 +296,7 @@ impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.address() { AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "\"{}\" (abstract)", name.escape_ascii()), + AddressKind::Abstract(name) => write!(fmt, "{name:?} (abstract)"), AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"), } }
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index 0398a53..9a88687 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs
@@ -411,6 +411,15 @@ fn test_unix_datagram_timeout_zero_duration() { assert_eq!(err.kind(), ErrorKind::InvalidInput); } +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn abstract_socket_addr_debug() { + assert_eq!( + r#""\0hello world\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff" (abstract)"#, + format!("{:?}", SocketAddr::from_abstract_name(b"\0hello world\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff").unwrap()), + ); +} + #[test] fn abstract_namespace_not_allowed_connect() { assert!(UnixStream::connect("\0asdf").is_err());
diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 826d9f0..0469db0 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs
@@ -1882,6 +1882,19 @@ fn from_str(s: &str) -> Result<Self, Self::Err> { #[stable(feature = "rust1", since = "1.0.0")] impl<P: AsRef<Path>> FromIterator<P> for PathBuf { + /// Creates a new `PathBuf` from the [`Path`] elements of an iterator. + /// + /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path + /// [components](Components). + /// + /// # Examples + /// ``` + /// # use std::path::PathBuf; + /// let path = PathBuf::from_iter(["/tmp", "foo", "bar"]); + /// assert_eq!(path, PathBuf::from("/tmp/foo/bar")); + /// ``` + /// + /// See documentation for [`push`](Self::push) for more details on how the path is constructed. fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf { let mut buf = PathBuf::new(); buf.extend(iter); @@ -1891,6 +1904,20 @@ fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl<P: AsRef<Path>> Extend<P> for PathBuf { + /// Extends `self` with [`Path`] elements from `iter`. + /// + /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path + /// [components](Components). + /// + /// # Examples + /// ``` + /// # use std::path::PathBuf; + /// let mut path = PathBuf::from("/tmp"); + /// path.extend(["foo", "bar", "file.txt"]); + /// assert_eq!(path, PathBuf::from("/tmp/foo/bar/file.txt")); + /// ``` + /// + /// See documentation for [`push`](Self::push) for more details on how the path is constructed. fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) { iter.into_iter().for_each(move |p| self.push(p.as_ref())); }
diff --git a/library/stdarch b/library/stdarch index 5c1c436..1b4d15d 160000 --- a/library/stdarch +++ b/library/stdarch
@@ -1 +1 @@ -Subproject commit 5c1c436524c0bbc8db83577f42f8bea9006a7b75 +Subproject commit 1b4d15df12079504942d0a3f1030b2039b8a776c
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index ad37342..f8da09f 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml
@@ -22,7 +22,7 @@ libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "xous")'.dependencies] -unwinding = { version = "0.2.6", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } +unwinding = { version = "0.2.7", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } [features]
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 3c7c42f..237efae 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -136,6 +136,19 @@ fn run(mut self, builder: &Builder<'_>) -> ToolBuildResult { _ => panic!("unexpected Mode for tool build"), } + // build.tool.TOOL_NAME.features in bootstrap.toml allows specifying which features to + // enable for a specific tool. `extra_features` instead is not controlled by the toml and + // provides features that are always enabled for a specific tool (e.g. "in-rust-tree" for + // rust-analyzer). Finally, `prepare_tool_cargo` might add more features to adapt the build + // to the chosen flags (e.g. "all-static" for cargo if `cargo_native_static` is true). + let mut features = builder + .config + .tool + .get(self.tool) + .and_then(|tool| tool.features.clone()) + .unwrap_or_default(); + features.extend(self.extra_features.clone()); + let mut cargo = prepare_tool_cargo( builder, self.compiler, @@ -144,7 +157,7 @@ fn run(mut self, builder: &Builder<'_>) -> ToolBuildResult { Kind::Build, path, self.source_type, - &self.extra_features, + &features, ); // The stage0 compiler changes infrequently and does not directly depend on code
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 6aff376..f9980ac 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs
@@ -35,7 +35,7 @@ use crate::core::config::flags::{Color, Flags}; use crate::core::config::target_selection::TargetSelectionList; use crate::core::config::toml::TomlConfig; -use crate::core::config::toml::build::Build; +use crate::core::config::toml::build::{Build, Tool}; use crate::core::config::toml::change_id::ChangeId; use crate::core::config::toml::rust::{ LldMode, RustOptimize, check_incompatible_options_for_ci_rustc, @@ -101,6 +101,9 @@ pub struct Config { pub bootstrap_cache_path: Option<PathBuf>, pub extended: bool, pub tools: Option<HashSet<String>>, + /// Specify build configuration specific for some tool, such as enabled features, see [Tool]. + /// The key in the map is the name of the tool, and the value is tool-specific configuration. + pub tool: HashMap<String, Tool>, pub sanitizers: bool, pub profiler: bool, pub omit_git_hash: bool, @@ -676,6 +679,7 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> { bootstrap_cache_path, extended, tools, + tool, verbose, sanitizers, profiler, @@ -822,6 +826,7 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> { set(&mut config.full_bootstrap, full_bootstrap); set(&mut config.extended, extended); config.tools = tools; + set(&mut config.tool, tool); set(&mut config.verbose, verbose); set(&mut config.sanitizers, sanitizers); set(&mut config.profiler, profiler); @@ -1368,12 +1373,13 @@ pub(crate) fn update_submodule(&self, relative_path: &str) { } println!("Updating submodule {relative_path}"); - self.check_run( - helpers::git(Some(&self.src)) - .run_always() - .args(["submodule", "-q", "sync"]) - .arg(relative_path), - ); + + helpers::git(Some(&self.src)) + .allow_failure() + .run_always() + .args(["submodule", "-q", "sync"]) + .arg(relative_path) + .run(self); // Try passing `--progress` to start, then run git again without if that fails. let update = |progress: bool| { @@ -1402,26 +1408,23 @@ pub(crate) fn update_submodule(&self, relative_path: &str) { git.arg(relative_path); git }; - if !self.check_run(&mut update(true)) { - self.check_run(&mut update(false)); + if !update(true).allow_failure().run(self) { + update(false).allow_failure().run(self); } // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status - let has_local_modifications = !self.check_run(submodule_git().allow_failure().args([ - "diff-index", - "--quiet", - "HEAD", - ])); + let has_local_modifications = + !submodule_git().allow_failure().args(["diff-index", "--quiet", "HEAD"]).run(self); if has_local_modifications { - self.check_run(submodule_git().args(["stash", "push"])); + submodule_git().allow_failure().args(["stash", "push"]).run(self); } - self.check_run(submodule_git().args(["reset", "-q", "--hard"])); - self.check_run(submodule_git().args(["clean", "-qdfx"])); + submodule_git().allow_failure().args(["reset", "-q", "--hard"]).run(self); + submodule_git().allow_failure().args(["clean", "-qdfx"]).run(self); if has_local_modifications { - self.check_run(submodule_git().args(["stash", "pop"])); + submodule_git().allow_failure().args(["stash", "pop"]).run(self); } }
diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 85ded3c..98e1194 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs
@@ -6,6 +6,8 @@ //! various feature flags. These options apply across different stages and components //! unless specifically overridden by other configuration sections or command-line flags. +use std::collections::HashMap; + use serde::{Deserialize, Deserializer}; use crate::core::config::toml::ReplaceOpt; @@ -42,6 +44,7 @@ struct Build { bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path", extended: Option<bool> = "extended", tools: Option<HashSet<String>> = "tools", + tool: Option<HashMap<String, Tool>> = "tool", verbose: Option<usize> = "verbose", sanitizers: Option<bool> = "sanitizers", profiler: Option<bool> = "profiler", @@ -70,3 +73,11 @@ struct Build { exclude: Option<Vec<PathBuf>> = "exclude", } } + +define_config! { + /// Configuration specific for some tool, e.g. which features to enable during build. + #[derive(Default, Clone)] + struct Tool { + features: Option<Vec<String>> = "features", + } +}
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 88a58e5..d7c6d8d 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs
@@ -9,8 +9,8 @@ use crate::core::config::BUILDER_CONFIG_FILENAME; use crate::utils::build_stamp::BuildStamp; -use crate::utils::exec::{BootstrapCommand, command}; -use crate::utils::helpers::{check_run, exe, hex_encode, move_file}; +use crate::utils::exec::command; +use crate::utils::helpers::{exe, hex_encode, move_file}; use crate::{Config, t}; static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock<bool> = OnceLock::new(); @@ -65,17 +65,6 @@ pub(crate) fn tempdir(&self) -> PathBuf { tmp } - /// Runs a command, printing out nice contextual information if it fails. - /// Returns false if do not execute at all, otherwise returns its - /// `status.success()`. - pub(crate) fn check_run(&self, cmd: &mut BootstrapCommand) -> bool { - if self.dry_run() && !cmd.run_always { - return true; - } - self.verbose(|| println!("running: {cmd:?}")); - check_run(cmd, self.is_verbose()) - } - /// Whether or not `fix_bin_or_dylib` needs to be run; can only be true /// on NixOS fn should_fix_bins_and_dylibs(&self) -> bool { @@ -214,7 +203,7 @@ fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: // options should be kept in sync with // src/bootstrap/src/core/download.rs // for consistency - let mut curl = command("curl"); + let mut curl = command("curl").allow_failure(); curl.args([ // follow redirect "--location", @@ -255,7 +244,7 @@ fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: curl.arg("--retry-all-errors"); } curl.arg(url); - if !self.check_run(&mut curl) { + if !curl.run(self) { if self.host_target.contains("windows-msvc") { eprintln!("Fallback to PowerShell"); for _ in 0..3 {
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index ef776e2..493f73b 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs
@@ -200,12 +200,14 @@ pub fn check(build: &mut Build) { .map(|p| cmd_finder.must_have(p)) .or_else(|| cmd_finder.maybe_have("reuse")); - let stage0_supported_target_list: HashSet<String> = crate::utils::helpers::output( - command(&build.config.initial_rustc).args(["--print", "target-list"]).as_command_mut(), - ) - .lines() - .map(|s| s.to_string()) - .collect(); + let stage0_supported_target_list: HashSet<String> = command(&build.config.initial_rustc) + .args(["--print", "target-list"]) + .run_always() + .run_capture_stdout(&build) + .stdout() + .lines() + .map(|s| s.to_string()) + .collect(); // Compiler tools like `cc` and `ar` are not configured for cross-targets on certain subcommands // because they are not needed.
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index fd87460..f1628f3 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs
@@ -21,7 +21,6 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::process::Command; use std::sync::OnceLock; use std::time::SystemTime; use std::{env, fs, io, str}; @@ -39,7 +38,7 @@ use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags}; use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command}; use crate::utils::helpers::{ - self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir, + self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo, symlink_dir, }; mod core; @@ -378,10 +377,13 @@ pub fn new(mut config: Config) -> Build { let in_tree_llvm_info = config.in_tree_llvm_info.clone(); let in_tree_gcc_info = config.in_tree_gcc_info.clone(); - let initial_target_libdir = - output(Command::new(&config.initial_rustc).args(["--print", "target-libdir"])) - .trim() - .to_owned(); + let initial_target_libdir = command(&config.initial_rustc) + .run_always() + .args(["--print", "target-libdir"]) + .run_capture_stdout(&config) + .stdout() + .trim() + .to_owned(); let initial_target_dir = Path::new(&initial_target_libdir) .parent() @@ -482,8 +484,11 @@ pub fn new(mut config: Config) -> Build { // If local-rust is the same major.minor as the current version, then force a // local-rebuild - let local_version_verbose = - output(Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); + let local_version_verbose = command(&build.initial_rustc) + .run_always() + .args(["--version", "--verbose"]) + .run_capture_stdout(&build) + .stdout(); let local_release = local_version_verbose .lines() .filter_map(|x| x.strip_prefix("release:")) @@ -936,9 +941,14 @@ fn rustc_snapshot_libdir(&self) -> PathBuf { fn rustc_snapshot_sysroot(&self) -> &Path { static SYSROOT_CACHE: OnceLock<PathBuf> = OnceLock::new(); SYSROOT_CACHE.get_or_init(|| { - let mut rustc = Command::new(&self.initial_rustc); - rustc.args(["--print", "sysroot"]); - output(&mut rustc).trim().into() + command(&self.initial_rustc) + .run_always() + .args(["--print", "sysroot"]) + .run_capture_stdout(self) + .stdout() + .trim() + .to_owned() + .into() }) }
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index e939a83..93e01a5 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -421,4 +421,9 @@ pub fn human_readable_changes(changes: &[ChangeInfo]) -> String { severity: ChangeSeverity::Info, summary: "Added new bootstrap flag `--skip-std-check-if-no-download-rustc` that skips std checks when download-rustc is unavailable. Mainly intended for developers to reduce RA overhead.", }, + ChangeInfo { + change_id: 142379, + severity: ChangeSeverity::Info, + summary: "Added new option `tool.TOOL_NAME.features` to specify the features to compile a tool with", + }, ];
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 4f361af..f4be22f 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs
@@ -270,24 +270,6 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( } } -// FIXME: get rid of this function -pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool { - let status = match cmd.as_command_mut().status() { - Ok(status) => status, - Err(e) => { - println!("failed to execute command: {cmd:?}\nERROR: {e}"); - return false; - } - }; - if !status.success() && print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {cmd:?}\n\ - expected success, got: {status}\n\n" - ); - } - status.success() -} - pub fn make(host: &str) -> PathBuf { if host.contains("dragonfly") || host.contains("freebsd") @@ -300,25 +282,6 @@ pub fn make(host: &str) -> PathBuf { } } -#[track_caller] -pub fn output(cmd: &mut Command) -> String { - #[cfg(feature = "tracing")] - let _run_span = crate::trace_cmd!(cmd); - - let output = match cmd.stderr(Stdio::inherit()).output() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), - }; - if !output.status.success() { - panic!( - "command did not execute successfully: {:?}\n\ - expected success, got: {}", - cmd, output.status - ); - } - String::from_utf8(output.stdout).unwrap() -} - /// Spawn a process and return a closure that will wait for the process /// to finish and then return its output. This allows the spawned process /// to do work without immediately blocking bootstrap.
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index 006a697..8d2c5e0 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -41,7 +41,9 @@ COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/ +RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' + # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. -ENV SCRIPT TIDY_PRINT_DIFF=1 npm install eslint@$(head -n 1 /tmp/eslint.version) && \ - python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp +ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \ + src/tools/tidy tidyselftest --extra-checks=py,cpp
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 43c77d1..d6d9e0f 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml
@@ -256,7 +256,7 @@ IMAGE: dist-x86_64-linux CODEGEN_BACKENDS: llvm,cranelift DOCKER_SCRIPT: dist-alt.sh - <<: *job-linux-4c-largedisk + <<: *job-linux-8c - name: dist-x86_64-musl env:
diff --git a/src/ci/run.sh b/src/ci/run.sh index e0c00dc..a6721a8 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh
@@ -134,6 +134,11 @@ CODEGEN_BACKENDS="${CODEGEN_BACKENDS:-llvm}" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=$CODEGEN_BACKENDS" + + # Unless explicitly disabled, we want rustc debug assertions on the -alt builds + if [ "$DEPLOY_ALT" != "" ] && [ "$NO_DEBUG_ASSERTIONS" = "" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions" + fi else # We almost always want debug assertions enabled, but sometimes this takes too # long for too little benefit, so we just turn them off.
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index c8721bb..86d35b3 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@ -c31cccb7b5cc098b1a8c1794ed38d7fdbec0ccb0 +14346303d760027e53214e705109a62c0f00b214
diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 8118ddf..8726ddf 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md
@@ -142,7 +142,8 @@ `x` to update the submodules. Alternatively, you might have run `cargo fmt` instead of `x fmt` and modified files in a submodule, then committed the changes. -To fix it, do the following things: +To fix it, do the following things (if you changed a submodule other than cargo, +replace `src/tools/cargo` with the path to that submodule): 1. See which commit has the accidental changes: `git log --stat -n1 src/tools/cargo` 2. Revert the changes to that commit: `git checkout <my-commit>~ src/tools/cargo`. Type `~`
diff --git a/src/doc/rustc-dev-guide/src/implementing_new_features.md b/src/doc/rustc-dev-guide/src/implementing_new_features.md index d7561bb..5d0e875 100644 --- a/src/doc/rustc-dev-guide/src/implementing_new_features.md +++ b/src/doc/rustc-dev-guide/src/implementing_new_features.md
@@ -156,8 +156,8 @@ [`incomplete_features` lint]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#incomplete-features ```rust ignore - /// Allows unsized rvalues at arguments and parameters. - (incomplete, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), None), + /// Allows deref patterns. + (incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None), ``` To avoid [semantic merge conflicts], please use `CURRENT_RUSTC_VERSION` instead of `1.70` or
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 20dd16c..ded3023 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -115,7 +115,7 @@ 2. Run `rustc -Zunpretty=normal` on the output of the previous step. 3. The output of the previous two steps should be the same. 4. Run `rustc -Zno-codegen` on the output to make sure that it can type check - (this is similar to running `cargo check`). + (similar to `cargo check`). If any of the commands above fail, then the test fails.
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index a3939e5..201a550 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md
@@ -113,6 +113,7 @@ - [\*-unknown-openbsd](platform-support/openbsd.md) - [\*-unknown-redox](platform-support/redox.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) + - [\*-unknown-windows-msvc](platform-support/windows-msvc.md) - [\*-uwp-windows-msvc](platform-support/uwp-windows-msvc.md) - [\*-wrs-vxworks](platform-support/vxworks.md) - [wasm32-wasip1](platform-support/wasm32-wasip1.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 559e486..3cab57d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md
@@ -34,11 +34,11 @@ -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+) -`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] +[`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+) -`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+) +[`x86_64-pc-windows-msvc`](platform-support/windows-msvc.md) | 64-bit MSVC (Windows 10+, Windows Server 2016+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue]. @@ -88,7 +88,7 @@ target | notes -------|------- -`aarch64-pc-windows-msvc` | ARM64 Windows MSVC +[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17)
diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md index b67f49c..1e74c47 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
@@ -207,120 +207,3 @@ platforms such as x86\_64 work, and this is due to the fact that WebAssembly binaries must only contain code the engine understands. Native binaries work so long as the CPU doesn't execute unknown code dynamically at runtime. - -## Broken `extern "C"` ABI - -This target has what is considered a broken `extern "C"` ABI implementation at -this time. Notably the same signature in Rust and C will compile to different -WebAssembly functions and be incompatible. This is considered a bug and it will -be fixed in a future version of Rust. - -For example this Rust code: - -```rust,ignore (does-not-link) -#[repr(C)] -struct MyPair { - a: u32, - b: u32, -} - -extern "C" { - fn take_my_pair(pair: MyPair) -> u32; -} - -#[no_mangle] -pub unsafe extern "C" fn call_c() -> u32 { - take_my_pair(MyPair { a: 1, b: 2 }) -} -``` - -compiles to a WebAssembly module that looks like: - -```wasm -(module - (import "env" "take_my_pair" (func $take_my_pair (param i32 i32) (result i32))) - (func $call_c - i32.const 1 - i32.const 2 - call $take_my_pair - ) -) -``` - -The function when defined in C, however, looks like - -```c -struct my_pair { - unsigned a; - unsigned b; -}; - -unsigned take_my_pair(struct my_pair pair) { - return pair.a + pair.b; -} -``` - -```wasm -(module - (import "env" "__linear_memory" (memory 0)) - (func $take_my_pair (param i32) (result i32) - local.get 0 - i32.load offset=4 - local.get 0 - i32.load - i32.add - ) -) -``` - -Notice how Rust thinks `take_my_pair` takes two `i32` parameters but C thinks it -only takes one. - -The correct definition of the `extern "C"` ABI for WebAssembly is located in the -[WebAssembly/tool-conventions](https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md) -repository. The `wasm32-unknown-unknown` target (and only this target, not other -WebAssembly targets Rust support) does not correctly follow this document. - -Example issues in the Rust repository about this bug are: - -* [#115666](https://github.com/rust-lang/rust/issues/115666) -* [#129486](https://github.com/rust-lang/rust/issues/129486) - -This current state of the `wasm32-unknown-unknown` backend is due to an -unfortunate accident which got relied on. The `wasm-bindgen` project prior to -0.2.89 was incompatible with the "correct" definition of `extern "C"` and it was -seen as not worth the tradeoff of breaking `wasm-bindgen` historically to fix -this issue in the compiler. - -Thanks to the heroic efforts of many involved in this, however, `wasm-bindgen` -0.2.89 and later are compatible with the correct definition of `extern "C"` and -the nightly compiler currently supports a `-Zwasm-c-abi` implemented in -[#117919](https://github.com/rust-lang/rust/pull/117919). This nightly-only flag -can be used to indicate whether the spec-defined version of `extern "C"` should -be used instead of the "legacy" version of -whatever-the-Rust-target-originally-implemented. For example using the above -code you can see (lightly edited for clarity): - -```shell -$ rustc +nightly -Zwasm-c-abi=spec foo.rs --target wasm32-unknown-unknown --crate-type lib --emit obj -O -$ wasm-tools print foo.o -(module - (import "env" "take_my_pair" (func $take_my_pair (param i32) (result i32))) - (func $call_c (result i32) - ;; ... - ) - ;; ... -) -``` - -which shows that the C and Rust definitions of the same function now agree like -they should. - -The `-Zwasm-c-abi` compiler flag is tracked in -[#122532](https://github.com/rust-lang/rust/issues/122532) and a lint was -implemented in [#117918](https://github.com/rust-lang/rust/issues/117918) to -help warn users about the transition if they're using `wasm-bindgen` 0.2.88 or -prior. The current plan is to, in the future, switch `-Zwasm-c-api=spec` to -being the default. Some time after that the `-Zwasm-c-abi` flag and the -"legacy" implementation will all be removed. During this process users on a -sufficiently updated version of `wasm-bindgen` should not experience breakage.
diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md new file mode 100644 index 0000000..71dc4dd --- /dev/null +++ b/src/doc/rustc/src/platform-support/windows-msvc.md
@@ -0,0 +1,69 @@ +# `*-pc-windows-msvc` + +Windows MSVC targets. + +**Tier 1 with host tools:** + +- `i686-pc-windows-msvc`: Windows on 32-bit x86. +- `x86_64-pc-windows-msvc`: Windows on 64-bit x86. + +**Tier 2 with host tools:** + +- `aarch64-pc-windows-msvc`: Windows on ARM64. + +## Target maintainers + +[@ChrisDenton](https://github.com/ChrisDenton) +[@dpaoliello](https://github.com/dpaoliello) +[@lambdageek](https://github.com/lambdageek) +[@sivadeilra](https://github.com/sivadeilra) +[@wesleywiser](https://github.com/wesleywiser) + +## Requirements + +### OS version + +Windows 10 or higher is required for client installs, Windows Server 2016 or higher is required for server installs. + +### Host tooling + +The minimum supported Visual Studio version is 2017 but this support is not actively tested in CI. +It is **highly** recommended to use the latest version of VS (currently VS 2022). + +### Platform details + +These targets fully implement the Rust standard library. + +The `extern "C"` calling convention conforms to Microsoft's default calling convention for the given architecture: [`__cdecl`] on `i686`, [`x64`] on `x86_64` and [`ARM64`] on `aarch64`. + +The `*-windows-msvc` targets produce PE/COFF binaries with CodeView debuginfo, the native formats used on Windows. + +[`__cdecl`]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +[`x64`]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 +[`ARM64`]: https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170 + +## Building Rust programs + +These targets are distributed via `rustup` and can be installed via `rustup component add [--toolchain {name}] {target}`. + +For example, adding the 32-bit x86 target to the `nightly` toolchain: + +```text +rustup component add --toolchain nightly i686-pc-windows-msvc +``` + +or adding the ARM64 target to the active toolchain: + +```text +rustup component add aarch64-pc-windows-msvc +``` + +## Testing + +There are no special requirements for testing and running this target. + +## Cross-compilation toolchains and C code + +Architectural cross-compilation from one Windows host to a different Windows platform is natively supported by the MSVC toolchain provided the appropriate components are selected when using the VS Installer. + +Cross-compilation from a non-Windows host to a `*-windows-msvc` target _may_ be possible but is not supported.
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 69e5a5a..27910ad 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md
@@ -581,7 +581,9 @@ ```rust /// ``` +/// #![allow(dead_code)] /// let x = 12; +/// Ok(()) /// ``` pub trait Trait {} ``` @@ -590,10 +592,10 @@ ```json { - "format_version": 1, + "format_version": 2, "doctests": [ { - "file": "foo.rs", + "file": "src/lib.rs", "line": 1, "doctest_attributes": { "original": "", @@ -609,9 +611,17 @@ "added_css_classes": [], "unknown": [] }, - "original_code": "let x = 12;", - "doctest_code": "#![allow(unused)]\nfn main() {\nlet x = 12;\n}", - "name": "foo.rs - Trait (line 1)" + "original_code": "#![allow(dead_code)]\nlet x = 12;\nOk(())", + "doctest_code": { + "crate_level": "#![allow(unused)]\n#![allow(dead_code)]\n\n", + "code": "let x = 12;\nOk(())", + "wrapper": { + "before": "fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n", + "after": "\n} _inner().unwrap() }", + "returns_result": true + } + }, + "name": "src/lib.rs - (line 1)" } ] } @@ -624,6 +634,10 @@ * `doctest_attributes` contains computed information about the attributes used on the doctests. For more information about doctest attributes, take a look [here](write-documentation/documentation-tests.html#attributes). * `original_code` is the code as written in the source code before rustdoc modifies it. * `doctest_code` is the code modified by rustdoc that will be run. If there is a fatal syntax error, this field will not be present. + * `crate_level` is the crate level code (like attributes or `extern crate`) that will be added at the top-level of the generated doctest. + * `code` is "naked" doctest without anything from `crate_level` and `wrapper` content. + * `wrapper` contains extra code that will be added before and after `code`. + * `returns_result` is a boolean. If `true`, it means that the doctest returns a `Result` type. * `name` is the name generated by rustdoc which represents this doctest. ### html
diff --git a/src/doc/unstable-book/src/compiler-flags/macro-stats.md b/src/doc/unstable-book/src/compiler-flags/macro-stats.md new file mode 100644 index 0000000..b2622cf --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/macro-stats.md
@@ -0,0 +1,24 @@ +# `macro-stats` + +This feature is perma-unstable and has no tracking issue. + +---- + +Some macros, especially procedural macros, can generate a surprising amount of +code, which can slow down compile times. This is hard to detect because the +generated code is normally invisible to the programmer. + +This flag helps identify such cases. When enabled, the compiler measures the +effect on code size of all used macros and prints a table summarizing that +effect. For each distinct macro, it counts how many times it is used, and the +net effect on code size (in terms of lines of code, and bytes of code). The +code size evaluation uses the compiler's internal pretty-printing, and so will +be independent of the formatting in the original code. + +Note that the net effect of a macro may be negative. E.g. the `cfg!` and +`#[test]` macros often strip out code. + +If a macro is identified as causing a large increase in code size, it is worth +using `cargo expand` to inspect the post-expansion code, which includes the +code produced by all macros. It may be possible to optimize the macro to +produce smaller code, or it may be possible to avoid using it altogether.
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index d9566c9..121f949 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -19,6 +19,7 @@ - M68k - CSKY - SPARC +- LoongArch32 ## Register classes @@ -53,6 +54,8 @@ | CSKY | `freg` | `f[0-31]` | `f` | | SPARC | `reg` | `r[2-29]` | `r` | | SPARC | `yreg` | `y` | Only clobbers | +| LoongArch32 | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | +| LoongArch32 | `freg` | `$f[0-31]` | `f` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -91,6 +94,8 @@ | CSKY | `freg` | None | `f32`, | | SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) | | SPARC | `yreg` | N/A | Only clobbers | +| LoongArch32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| LoongArch32 | `freg` | None | `f32`, `f64` | ## Register aliases
diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md deleted file mode 100644 index d5b01a3..0000000 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ /dev/null
@@ -1,175 +0,0 @@ -# `unsized_locals` - -The tracking issue for this feature is: [#48055] - -[#48055]: https://github.com/rust-lang/rust/issues/48055 - ------------------------- - -This implements [RFC1909]. When turned on, you can have unsized arguments and locals: - -[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md - -```rust -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] - -use std::any::Any; - -fn main() { - let x: Box<dyn Any> = Box::new(42); - let x: dyn Any = *x; - // ^ unsized local variable - // ^^ unsized temporary - foo(x); -} - -fn foo(_: dyn Any) {} -// ^^^^^^ unsized argument -``` - -The RFC still forbids the following unsized expressions: - -```rust,compile_fail -#![feature(unsized_locals)] - -use std::any::Any; - -struct MyStruct<T: ?Sized> { - content: T, -} - -struct MyTupleStruct<T: ?Sized>(T); - -fn answer() -> Box<dyn Any> { - Box::new(42) -} - -fn main() { - // You CANNOT have unsized statics. - static X: dyn Any = *answer(); // ERROR - const Y: dyn Any = *answer(); // ERROR - - // You CANNOT have struct initialized unsized. - MyStruct { content: *answer() }; // ERROR - MyTupleStruct(*answer()); // ERROR - (42, *answer()); // ERROR - - // You CANNOT have unsized return types. - fn my_function() -> dyn Any { *answer() } // ERROR - - // You CAN have unsized local variables... - let mut x: dyn Any = *answer(); // OK - // ...but you CANNOT reassign to them. - x = *answer(); // ERROR - - // You CANNOT even initialize them separately. - let y: dyn Any; // OK - y = *answer(); // ERROR - - // Not mentioned in the RFC, but by-move captured variables are also Sized. - let x: dyn Any = *answer(); - (move || { // ERROR - let y = x; - })(); - - // You CAN create a closure with unsized arguments, - // but you CANNOT call it. - // This is an implementation detail and may be changed in the future. - let f = |x: dyn Any| {}; - f(*answer()); // ERROR -} -``` - -## By-value trait objects - -With this feature, you can have by-value `self` arguments without `Self: Sized` bounds. - -```rust -#![feature(unsized_fn_params)] - -trait Foo { - fn foo(self) {} -} - -impl<T: ?Sized> Foo for T {} - -fn main() { - let slice: Box<[i32]> = Box::new([1, 2, 3]); - <[i32] as Foo>::foo(*slice); -} -``` - -And `Foo` will also be object-safe. - -```rust -#![feature(unsized_fn_params)] - -trait Foo { - fn foo(self) {} -} - -impl<T: ?Sized> Foo for T {} - -fn main () { - let slice: Box<dyn Foo> = Box::new([1, 2, 3]); - // doesn't compile yet - <dyn Foo as Foo>::foo(*slice); -} -``` - -One of the objectives of this feature is to allow `Box<dyn FnOnce>`. - -## Variable length arrays - -The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`. - -```rust,ignore (not-yet-implemented) -#![feature(unsized_locals)] - -fn mergesort<T: Ord>(a: &mut [T]) { - let mut tmp = [T; dyn a.len()]; - // ... -} - -fn main() { - let mut a = [3, 1, 5, 6]; - mergesort(&mut a); - assert_eq!(a, [1, 3, 5, 6]); -} -``` - -VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`. - -## Advisory on stack usage - -It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are: - -- When you need a by-value trait objects. -- When you really need a fast allocation of small temporary arrays. - -Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code - -```rust -#![feature(unsized_locals)] - -fn main() { - let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); - let _x = {{{{{{{{{{*x}}}}}}}}}}; -} -``` - -and the code - -```rust -#![feature(unsized_locals)] - -fn main() { - for _ in 0..10 { - let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); - let _x = *x; - } -} -``` - -will unnecessarily extend the stack frame.
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index a3762e4..b6ce855 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs
@@ -169,33 +169,36 @@ pub(crate) fn render_short_html(&self) -> String { msg } - /// Renders the configuration for long display, as a long HTML description. - pub(crate) fn render_long_html(&self) -> String { + fn render_long_inner(&self, format: Format) -> String { let on = if self.omit_preposition() { - "" + " " } else if self.should_use_with_in_description() { - "with " + " with " } else { - "on " + " on " }; - let mut msg = format!("Available {on}<strong>{}</strong>", Display(self, Format::LongHtml)); + let mut msg = if matches!(format, Format::LongHtml) { + format!("Available{on}<strong>{}</strong>", Display(self, format)) + } else { + format!("Available{on}{}", Display(self, format)) + }; if self.should_append_only_to_description() { msg.push_str(" only"); } + msg + } + + /// Renders the configuration for long display, as a long HTML description. + pub(crate) fn render_long_html(&self) -> String { + let mut msg = self.render_long_inner(Format::LongHtml); msg.push('.'); msg } /// Renders the configuration for long display, as a long plain text description. pub(crate) fn render_long_plain(&self) -> String { - let on = if self.should_use_with_in_description() { "with" } else { "on" }; - - let mut msg = format!("Available {on} {}", Display(self, Format::LongPlain)); - if self.should_append_only_to_description() { - msg.push_str(" only"); - } - msg + self.render_long_inner(Format::LongPlain) } fn should_capitalize_first_letter(&self) -> bool {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bde1a2e..58e05bd 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs
@@ -2638,7 +2638,7 @@ mod size_asserts { static_assert_size!(GenericParamDef, 40); static_assert_size!(Generics, 16); static_assert_size!(Item, 8); - static_assert_size!(ItemInner, 136); + static_assert_size!(ItemInner, 144); static_assert_size!(ItemKind, 48); static_assert_size!(PathSegment, 32); static_assert_size!(Type, 32);
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a81d602..130fdff 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs
@@ -1053,14 +1053,14 @@ fn doctest_run_fn( let report_unused_externs = |uext| { unused_externs.lock().unwrap().push(uext); }; - let (full_test_code, full_test_line_offset) = doctest.generate_unique_doctest( + let (wrapped, full_test_line_offset) = doctest.generate_unique_doctest( &scraped_test.text, scraped_test.langstr.test_harness, &global_opts, Some(&global_opts.crate_name), ); let runnable_test = RunnableDocTest { - full_test_code, + full_test_code: wrapped.to_string(), full_test_line_offset, test_opts, global_opts,
diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs index ebe6bfd..925fb6f 100644 --- a/src/librustdoc/doctest/extracted.rs +++ b/src/librustdoc/doctest/extracted.rs
@@ -3,8 +3,10 @@ //! This module contains the logic to extract doctests and output a JSON containing this //! information. +use rustc_span::edition::Edition; use serde::Serialize; +use super::make::DocTestWrapResult; use super::{BuildDocTestBuilder, ScrapedDocTest}; use crate::config::Options as RustdocOptions; use crate::html::markdown; @@ -14,7 +16,7 @@ /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob into the `format_version` root field. /// Consuming code should assert that this value matches the format version(s) that it supports. -const FORMAT_VERSION: u32 = 1; +const FORMAT_VERSION: u32 = 2; #[derive(Serialize)] pub(crate) struct ExtractedDocTests { @@ -34,7 +36,16 @@ pub(crate) fn add_test( options: &RustdocOptions, ) { let edition = scraped_test.edition(options); + self.add_test_with_edition(scraped_test, opts, edition) + } + /// This method is used by unit tests to not have to provide a `RustdocOptions`. + pub(crate) fn add_test_with_edition( + &mut self, + scraped_test: ScrapedDocTest, + opts: &super::GlobalTestOptions, + edition: Edition, + ) { let ScrapedDocTest { filename, line, langstr, text, name, global_crate_attrs, .. } = scraped_test; @@ -44,8 +55,7 @@ pub(crate) fn add_test( .edition(edition) .lang_str(&langstr) .build(None); - - let (full_test_code, size) = doctest.generate_unique_doctest( + let (wrapped, _size) = doctest.generate_unique_doctest( &text, langstr.test_harness, opts, @@ -55,11 +65,46 @@ pub(crate) fn add_test( file: filename.prefer_remapped_unconditionaly().to_string(), line, doctest_attributes: langstr.into(), - doctest_code: if size != 0 { Some(full_test_code) } else { None }, + doctest_code: match wrapped { + DocTestWrapResult::Valid { crate_level_code, wrapper, code } => Some(DocTest { + crate_level: crate_level_code, + code, + wrapper: wrapper.map( + |super::make::WrapperInfo { before, after, returns_result, .. }| { + WrapperInfo { before, after, returns_result } + }, + ), + }), + DocTestWrapResult::SyntaxError { .. } => None, + }, original_code: text, name, }); } + + #[cfg(test)] + pub(crate) fn doctests(&self) -> &[ExtractedDocTest] { + &self.doctests + } +} + +#[derive(Serialize)] +pub(crate) struct WrapperInfo { + before: String, + after: String, + returns_result: bool, +} + +#[derive(Serialize)] +pub(crate) struct DocTest { + crate_level: String, + code: String, + /// This field can be `None` if one of the following conditions is true: + /// + /// * The doctest's codeblock has the `test_harness` attribute. + /// * The doctest has a `main` function. + /// * The doctest has the `![no_std]` attribute. + pub(crate) wrapper: Option<WrapperInfo>, } #[derive(Serialize)] @@ -69,7 +114,7 @@ pub(crate) struct ExtractedDocTest { doctest_attributes: LangString, original_code: String, /// `None` if the code syntax is invalid. - doctest_code: Option<String>, + pub(crate) doctest_code: Option<DocTest>, name: String, }
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 5e57161..3ff6828 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs
@@ -196,6 +196,80 @@ pub(crate) struct DocTestBuilder { pub(crate) can_be_merged: bool, } +/// Contains needed information for doctest to be correctly generated with expected "wrapping". +pub(crate) struct WrapperInfo { + pub(crate) before: String, + pub(crate) after: String, + pub(crate) returns_result: bool, + insert_indent_space: bool, +} + +impl WrapperInfo { + fn len(&self) -> usize { + self.before.len() + self.after.len() + } +} + +/// Contains a doctest information. Can be converted into code with the `to_string()` method. +pub(crate) enum DocTestWrapResult { + Valid { + crate_level_code: String, + /// This field can be `None` if one of the following conditions is true: + /// + /// * The doctest's codeblock has the `test_harness` attribute. + /// * The doctest has a `main` function. + /// * The doctest has the `![no_std]` attribute. + wrapper: Option<WrapperInfo>, + /// Contains the doctest processed code without the wrappers (which are stored in the + /// `wrapper` field). + code: String, + }, + /// Contains the original source code. + SyntaxError(String), +} + +impl std::string::ToString for DocTestWrapResult { + fn to_string(&self) -> String { + match self { + Self::SyntaxError(s) => s.clone(), + Self::Valid { crate_level_code, wrapper, code } => { + let mut prog_len = code.len() + crate_level_code.len(); + if let Some(wrapper) = wrapper { + prog_len += wrapper.len(); + if wrapper.insert_indent_space { + prog_len += code.lines().count() * 4; + } + } + let mut prog = String::with_capacity(prog_len); + + prog.push_str(crate_level_code); + if let Some(wrapper) = wrapper { + prog.push_str(&wrapper.before); + + // add extra 4 spaces for each line to offset the code block + if wrapper.insert_indent_space { + write!( + prog, + "{}", + fmt::from_fn(|f| code + .lines() + .map(|line| fmt::from_fn(move |f| write!(f, " {line}"))) + .joined("\n", f)) + ) + .unwrap(); + } else { + prog.push_str(code); + } + prog.push_str(&wrapper.after); + } else { + prog.push_str(code); + } + prog + } + } + } +} + impl DocTestBuilder { fn invalid( global_crate_attrs: Vec<String>, @@ -228,50 +302,49 @@ pub(crate) fn generate_unique_doctest( dont_insert_main: bool, opts: &GlobalTestOptions, crate_name: Option<&str>, - ) -> (String, usize) { + ) -> (DocTestWrapResult, usize) { if self.invalid_ast { // If the AST failed to compile, no need to go generate a complete doctest, the error // will be better this way. debug!("invalid AST:\n{test_code}"); - return (test_code.to_string(), 0); + return (DocTestWrapResult::SyntaxError(test_code.to_string()), 0); } let mut line_offset = 0; - let mut prog = String::new(); - let everything_else = self.everything_else.trim(); - + let mut crate_level_code = String::new(); + let processed_code = self.everything_else.trim(); if self.global_crate_attrs.is_empty() { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in // that case may cause some tests to pass when they shouldn't have. - prog.push_str("#![allow(unused)]\n"); + crate_level_code.push_str("#![allow(unused)]\n"); line_offset += 1; } // Next, any attributes that came from #![doc(test(attr(...)))]. for attr in &self.global_crate_attrs { - prog.push_str(&format!("#![{attr}]\n")); + crate_level_code.push_str(&format!("#![{attr}]\n")); line_offset += 1; } // Now push any outer attributes from the example, assuming they // are intended to be crate attributes. if !self.crate_attrs.is_empty() { - prog.push_str(&self.crate_attrs); + crate_level_code.push_str(&self.crate_attrs); if !self.crate_attrs.ends_with('\n') { - prog.push('\n'); + crate_level_code.push('\n'); } } if !self.maybe_crate_attrs.is_empty() { - prog.push_str(&self.maybe_crate_attrs); + crate_level_code.push_str(&self.maybe_crate_attrs); if !self.maybe_crate_attrs.ends_with('\n') { - prog.push('\n'); + crate_level_code.push('\n'); } } if !self.crates.is_empty() { - prog.push_str(&self.crates); + crate_level_code.push_str(&self.crates); if !self.crates.ends_with('\n') { - prog.push('\n'); + crate_level_code.push('\n'); } } @@ -289,17 +362,20 @@ pub(crate) fn generate_unique_doctest( { // rustdoc implicitly inserts an `extern crate` item for the own crate // which may be unused, so we need to allow the lint. - prog.push_str("#[allow(unused_extern_crates)]\n"); + crate_level_code.push_str("#[allow(unused_extern_crates)]\n"); - prog.push_str(&format!("extern crate r#{crate_name};\n")); + crate_level_code.push_str(&format!("extern crate r#{crate_name};\n")); line_offset += 1; } // FIXME: This code cannot yet handle no_std test cases yet - if dont_insert_main || self.has_main_fn || prog.contains("![no_std]") { - prog.push_str(everything_else); + let wrapper = if dont_insert_main + || self.has_main_fn + || crate_level_code.contains("![no_std]") + { + None } else { - let returns_result = everything_else.ends_with("(())"); + let returns_result = processed_code.ends_with("(())"); // Give each doctest main function a unique name. // This is for example needed for the tooling around `-C instrument-coverage`. let inner_fn_name = if let Some(ref test_id) = self.test_id { @@ -333,28 +409,22 @@ pub(crate) fn generate_unique_doctest( // /// ``` <- end of the inner main line_offset += 1; - prog.push_str(&main_pre); + Some(WrapperInfo { + before: main_pre, + after: main_post, + returns_result, + insert_indent_space: opts.insert_indent_space, + }) + }; - // add extra 4 spaces for each line to offset the code block - if opts.insert_indent_space { - write!( - prog, - "{}", - fmt::from_fn(|f| everything_else - .lines() - .map(|line| fmt::from_fn(move |f| write!(f, " {line}"))) - .joined("\n", f)) - ) - .unwrap(); - } else { - prog.push_str(everything_else); - }; - prog.push_str(&main_post); - } - - debug!("final doctest:\n{prog}"); - - (prog, line_offset) + ( + DocTestWrapResult::Valid { + code: processed_code.to_string(), + wrapper, + crate_level_code, + }, + line_offset, + ) } }
diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index ce2984c..ccc3e55 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs
@@ -1,6 +1,11 @@ use std::path::PathBuf; -use super::{BuildDocTestBuilder, GlobalTestOptions}; +use rustc_span::edition::Edition; +use rustc_span::{DUMMY_SP, FileName}; + +use super::extracted::ExtractedDocTests; +use super::{BuildDocTestBuilder, GlobalTestOptions, ScrapedDocTest}; +use crate::html::markdown::LangString; fn make_test( test_code: &str, @@ -19,9 +24,9 @@ fn make_test( builder = builder.test_id(test_id.to_string()); } let doctest = builder.build(None); - let (code, line_offset) = + let (wrapped, line_offset) = doctest.generate_unique_doctest(test_code, dont_insert_main, opts, crate_name); - (code, line_offset) + (wrapped.to_string(), line_offset) } /// Default [`GlobalTestOptions`] for these unit tests. @@ -461,3 +466,51 @@ pub mod outer_module { let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } + +fn get_extracted_doctests(code: &str) -> ExtractedDocTests { + let opts = default_global_opts(""); + let mut extractor = ExtractedDocTests::new(); + extractor.add_test_with_edition( + ScrapedDocTest::new( + FileName::Custom(String::new()), + 0, + Vec::new(), + LangString::default(), + code.to_string(), + DUMMY_SP, + Vec::new(), + ), + &opts, + Edition::Edition2018, + ); + extractor +} + +// Test that `extracted::DocTest::wrapper` is `None` if the doctest has a `main` function. +#[test] +fn test_extracted_doctest_wrapper_field() { + let extractor = get_extracted_doctests("fn main() {}"); + + assert_eq!(extractor.doctests().len(), 1); + let doctest_code = extractor.doctests()[0].doctest_code.as_ref().unwrap(); + assert!(doctest_code.wrapper.is_none()); +} + +// Test that `ExtractedDocTest::doctest_code` is `None` if the doctest has syntax error. +#[test] +fn test_extracted_doctest_doctest_code_field() { + let extractor = get_extracted_doctests("let x +="); + + assert_eq!(extractor.doctests().len(), 1); + assert!(extractor.doctests()[0].doctest_code.is_none()); +} + +// Test that `extracted::DocTest::wrapper` is `Some` if the doctest needs wrapping. +#[test] +fn test_extracted_doctest_wrapper_field_with_info() { + let extractor = get_extracted_doctests("let x = 12;"); + + assert_eq!(extractor.doctests().len(), 1); + let doctest_code = extractor.doctests()[0].doctest_code.as_ref().unwrap(); + assert!(doctest_code.wrapper.is_some()); +}
diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 5e4e6f2..4862617 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs
@@ -56,7 +56,7 @@ fn init( fn restore_module_data(&mut self, info: Self::ModuleData); /// Renders a single non-module item. This means no recursive sub-item rendering is required. - fn item(&mut self, item: clean::Item) -> Result<(), Error>; + fn item(&mut self, item: &clean::Item) -> Result<(), Error>; /// Renders a module (should not handle recursing into children). fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error>; @@ -67,14 +67,14 @@ fn mod_item_out(&mut self) -> Result<(), Error> { } /// Post processing hook for cleanup and dumping output to files. - fn after_krate(&mut self) -> Result<(), Error>; + fn after_krate(self) -> Result<(), Error>; fn cache(&self) -> &Cache; } fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( cx: &mut T, - item: clean::Item, + item: &clean::Item, prof: &SelfProfilerRef, ) -> Result<(), Error> { if item.is_mod() && T::RUN_ON_MODULE { @@ -84,12 +84,12 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string()); cx.mod_item_in(&item)?; - let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) = - item.inner.kind + let (clean::StrippedItem(box clean::ModuleItem(ref module)) + | clean::ModuleItem(ref module)) = item.inner.kind else { unreachable!() }; - for it in module.items { + for it in module.items.iter() { let info = cx.save_module_data(); run_format_inner(cx, it, prof)?; cx.restore_module_data(info); @@ -101,7 +101,7 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( } else if let Some(item_name) = item.name && !item.is_extern_crate() { - prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(item))?; + prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(&item))?; } Ok(()) } @@ -125,7 +125,7 @@ pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>( } // Render the crate documentation - run_format_inner(&mut format_renderer, krate.module, prof)?; + run_format_inner(&mut format_renderer, &krate.module, prof)?; prof.verbose_generic_activity_with_arg("renderer_after_krate", T::descr()) .run(|| format_renderer.after_krate())
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index d370178..f626e07 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs
@@ -307,7 +307,8 @@ fn next(&mut self) -> Option<Self::Item> { builder = builder.crate_name(krate); } let doctest = builder.build(None); - let (test, _) = doctest.generate_unique_doctest(&test, false, &opts, krate); + let (wrapped, _) = doctest.generate_unique_doctest(&test, false, &opts, krate); + let test = wrapped.to_string(); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let test_escaped = small_url_encode(test);
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 5984dcd..3821445 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs
@@ -609,7 +609,7 @@ fn restore_module_data(&mut self, info: Self::ModuleData) { self.info = info; } - fn after_krate(&mut self) -> Result<(), Error> { + fn after_krate(mut self) -> Result<(), Error> { let crate_name = self.tcx().crate_name(LOCAL_CRATE); let final_file = self.dst.join(crate_name.as_str()).join("all.html"); let settings_file = self.dst.join("settings.html"); @@ -830,7 +830,7 @@ fn mod_item_out(&mut self) -> Result<(), Error> { Ok(()) } - fn item(&mut self, item: clean::Item) -> Result<(), Error> { + fn item(&mut self, item: &clean::Item) -> Result<(), Error> { // Stripped modules survive the rustdoc passes (i.e., `strip-private`) // if they contain impls for public types. These modules can also // contain items such as publicly re-exported structures.
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 3ade409..6bdf3b5 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs
@@ -13,6 +13,7 @@ use rustc_middle::{bug, ty}; use rustc_span::{Pos, Symbol, kw}; use rustdoc_json_types::*; +use thin_vec::ThinVec; use crate::clean::{self, ItemId}; use crate::formats::FormatRenderer; @@ -21,7 +22,7 @@ use crate::passes::collect_intra_doc_links::UrlFragment; impl JsonRenderer<'_> { - pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> { + pub(super) fn convert_item(&self, item: &clean::Item) -> Option<Item> { let deprecation = item.deprecation(self.tcx); let links = self .cache @@ -107,49 +108,54 @@ fn convert_visibility(&self, v: Option<ty::Visibility<DefId>>) -> Visibility { } } - fn ids(&self, items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> { + fn ids(&self, items: &[clean::Item]) -> Vec<Id> { items - .into_iter() - .filter(|x| !x.is_stripped() && !x.is_keyword()) + .iter() + .filter(|i| !i.is_stripped() && !i.is_keyword()) .map(|i| self.id_from_item(&i)) .collect() } - fn ids_keeping_stripped( - &self, - items: impl IntoIterator<Item = clean::Item>, - ) -> Vec<Option<Id>> { + fn ids_keeping_stripped(&self, items: &[clean::Item]) -> Vec<Option<Id>> { items - .into_iter() + .iter() .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(&i))) .collect() } } pub(crate) trait FromClean<T> { - fn from_clean(f: T, renderer: &JsonRenderer<'_>) -> Self; + fn from_clean(f: &T, renderer: &JsonRenderer<'_>) -> Self; } pub(crate) trait IntoJson<T> { - fn into_json(self, renderer: &JsonRenderer<'_>) -> T; + fn into_json(&self, renderer: &JsonRenderer<'_>) -> T; } impl<T, U> IntoJson<U> for T where U: FromClean<T>, { - fn into_json(self, renderer: &JsonRenderer<'_>) -> U { + fn into_json(&self, renderer: &JsonRenderer<'_>) -> U { U::from_clean(self, renderer) } } -impl<I, T, U> FromClean<I> for Vec<U> +impl<T, U> FromClean<Vec<T>> for Vec<U> where - I: IntoIterator<Item = T>, U: FromClean<T>, { - fn from_clean(f: I, renderer: &JsonRenderer<'_>) -> Vec<U> { - f.into_iter().map(|x| x.into_json(renderer)).collect() + fn from_clean(items: &Vec<T>, renderer: &JsonRenderer<'_>) -> Vec<U> { + items.iter().map(|i| i.into_json(renderer)).collect() + } +} + +impl<T, U> FromClean<ThinVec<T>> for Vec<U> +where + U: FromClean<T>, +{ + fn from_clean(items: &ThinVec<T>, renderer: &JsonRenderer<'_>) -> Vec<U> { + items.iter().map(|i| i.into_json(renderer)).collect() } } @@ -165,7 +171,7 @@ pub(crate) fn from_deprecation(deprecation: attrs::Deprecation) -> Deprecation { } impl FromClean<clean::GenericArgs> for GenericArgs { - fn from_clean(args: clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArgs::*; match args { AngleBracketed { args, constraints } => GenericArgs::AngleBracketed { @@ -174,7 +180,7 @@ fn from_clean(args: clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { }, Parenthesized { inputs, output } => GenericArgs::Parenthesized { inputs: inputs.into_json(renderer), - output: output.map(|a| (*a).into_json(renderer)), + output: output.as_ref().map(|a| a.as_ref().into_json(renderer)), }, ReturnTypeNotation => GenericArgs::ReturnTypeNotation, } @@ -182,7 +188,7 @@ fn from_clean(args: clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<clean::GenericArg> for GenericArg { - fn from_clean(arg: clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(arg: &clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArg::*; match arg { Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)), @@ -195,7 +201,7 @@ fn from_clean(arg: clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self { impl FromClean<clean::Constant> for Constant { // FIXME(generic_const_items): Add support for generic const items. - fn from_clean(constant: clean::Constant, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(constant: &clean::Constant, renderer: &JsonRenderer<'_>) -> Self { let tcx = renderer.tcx; let expr = constant.expr(tcx); let value = constant.value(tcx); @@ -206,7 +212,7 @@ fn from_clean(constant: clean::Constant, renderer: &JsonRenderer<'_>) -> Self { impl FromClean<clean::ConstantKind> for Constant { // FIXME(generic_const_items): Add support for generic const items. - fn from_clean(constant: clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(constant: &clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Self { let tcx = renderer.tcx; let expr = constant.expr(tcx); let value = constant.value(tcx); @@ -216,7 +222,7 @@ fn from_clean(constant: clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Sel } impl FromClean<clean::AssocItemConstraint> for AssocItemConstraint { - fn from_clean(constraint: clean::AssocItemConstraint, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(constraint: &clean::AssocItemConstraint, renderer: &JsonRenderer<'_>) -> Self { AssocItemConstraint { name: constraint.assoc.name.to_string(), args: constraint.assoc.args.into_json(renderer), @@ -226,7 +232,7 @@ fn from_clean(constraint: clean::AssocItemConstraint, renderer: &JsonRenderer<'_ } impl FromClean<clean::AssocItemConstraintKind> for AssocItemConstraintKind { - fn from_clean(kind: clean::AssocItemConstraintKind, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(kind: &clean::AssocItemConstraintKind, renderer: &JsonRenderer<'_>) -> Self { use clean::AssocItemConstraintKind::*; match kind { Equality { term } => AssocItemConstraintKind::Equality(term.into_json(renderer)), @@ -235,15 +241,15 @@ fn from_clean(kind: clean::AssocItemConstraintKind, renderer: &JsonRenderer<'_>) } } -fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { +fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { use clean::ItemKind::*; let name = item.name; let is_crate = item.is_crate(); let header = item.fn_header(renderer.tcx); - match item.inner.kind { + match &item.inner.kind { ModuleItem(m) => { - ItemEnum::Module(Module { is_crate, items: renderer.ids(m.items), is_stripped: false }) + ItemEnum::Module(Module { is_crate, items: renderer.ids(&m.items), is_stripped: false }) } ImportItem(i) => ItemEnum::Use(i.into_json(renderer)), StructItem(s) => ItemEnum::Struct(s.into_json(renderer)), @@ -251,27 +257,27 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)), EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)), VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)), - FunctionItem(f) => ItemEnum::Function(from_function(*f, true, header.unwrap(), renderer)), + FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), renderer)), ForeignFunctionItem(f, _) => { - ItemEnum::Function(from_function(*f, false, header.unwrap(), renderer)) + ItemEnum::Function(from_function(f, false, header.unwrap(), renderer)) } - TraitItem(t) => ItemEnum::Trait((*t).into_json(renderer)), + TraitItem(t) => ItemEnum::Trait(t.as_ref().into_json(renderer)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)), - MethodItem(m, _) => ItemEnum::Function(from_function(*m, true, header.unwrap(), renderer)), + MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)), RequiredMethodItem(m) => { - ItemEnum::Function(from_function(*m, false, header.unwrap(), renderer)) + ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)) } - ImplItem(i) => ItemEnum::Impl((*i).into_json(renderer)), - StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)), + ImplItem(i) => ItemEnum::Impl(i.as_ref().into_json(renderer)), + StaticItem(s) => ItemEnum::Static(convert_static(s, &rustc_hir::Safety::Safe, renderer)), ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, safety, renderer)), ForeignTypeItem => ItemEnum::ExternType, - TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_json(renderer)), + TypeAliasItem(t) => ItemEnum::TypeAlias(t.as_ref().into_json(renderer)), // FIXME(generic_const_items): Add support for generic free consts ConstantItem(ci) => ItemEnum::Constant { type_: ci.type_.into_json(renderer), const_: ci.kind.into_json(renderer), }, - MacroItem(m) => ItemEnum::Macro(m.source), + MacroItem(m) => ItemEnum::Macro(m.source.clone()), ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_json(renderer)), PrimitiveItem(p) => { ItemEnum::Primitive(Primitive { @@ -281,7 +287,7 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { } // FIXME(generic_const_items): Add support for generic associated consts. RequiredAssocConstItem(_generics, ty) => { - ItemEnum::AssocConst { type_: (*ty).into_json(renderer), value: None } + ItemEnum::AssocConst { type_: ty.as_ref().into_json(renderer), value: None } } // FIXME(generic_const_items): Add support for generic associated consts. ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst { @@ -296,22 +302,22 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { AssocTypeItem(t, b) => ItemEnum::AssocType { generics: t.generics.into_json(renderer), bounds: b.into_json(renderer), - type_: Some(t.item_type.unwrap_or(t.type_).into_json(renderer)), + type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)), }, // `convert_item` early returns `None` for stripped items and keywords. KeywordItem => unreachable!(), StrippedItem(inner) => { - match *inner { + match inner.as_ref() { ModuleItem(m) => ItemEnum::Module(Module { is_crate, - items: renderer.ids(m.items), + items: renderer.ids(&m.items), is_stripped: true, }), // `convert_item` early returns `None` for stripped items we're not including _ => unreachable!(), } } - ExternCrateItem { ref src } => ItemEnum::ExternCrate { + ExternCrateItem { src } => ItemEnum::ExternCrate { name: name.as_ref().unwrap().to_string(), rename: src.map(|x| x.to_string()), }, @@ -319,17 +325,17 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { } impl FromClean<clean::Struct> for Struct { - fn from_clean(struct_: clean::Struct, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(struct_: &clean::Struct, renderer: &JsonRenderer<'_>) -> Self { let has_stripped_fields = struct_.has_stripped_entries(); let clean::Struct { ctor_kind, generics, fields } = struct_; let kind = match ctor_kind { - Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(fields)), + Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(&fields)), Some(CtorKind::Const) => { assert!(fields.is_empty()); StructKind::Unit } - None => StructKind::Plain { fields: renderer.ids(fields), has_stripped_fields }, + None => StructKind::Plain { fields: renderer.ids(&fields), has_stripped_fields }, }; Struct { @@ -341,13 +347,13 @@ fn from_clean(struct_: clean::Struct, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<clean::Union> for Union { - fn from_clean(union_: clean::Union, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(union_: &clean::Union, renderer: &JsonRenderer<'_>) -> Self { let has_stripped_fields = union_.has_stripped_entries(); let clean::Union { generics, fields } = union_; Union { generics: generics.into_json(renderer), has_stripped_fields, - fields: renderer.ids(fields), + fields: renderer.ids(&fields), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -377,12 +383,12 @@ fn convert_abi(a: ExternAbi) -> Abi { } } -fn convert_lifetime(l: clean::Lifetime) -> String { +fn convert_lifetime(l: &clean::Lifetime) -> String { l.0.to_string() } impl FromClean<clean::Generics> for Generics { - fn from_clean(generics: clean::Generics, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(generics: &clean::Generics, renderer: &JsonRenderer<'_>) -> Self { Generics { params: generics.params.into_json(renderer), where_predicates: generics.where_predicates.into_json(renderer), @@ -391,7 +397,7 @@ fn from_clean(generics: clean::Generics, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<clean::GenericParamDef> for GenericParamDef { - fn from_clean(generic_param: clean::GenericParamDef, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(generic_param: &clean::GenericParamDef, renderer: &JsonRenderer<'_>) -> Self { GenericParamDef { name: generic_param.name.to_string(), kind: generic_param.kind.into_json(renderer), @@ -400,7 +406,7 @@ fn from_clean(generic_param: clean::GenericParamDef, renderer: &JsonRenderer<'_> } impl FromClean<clean::GenericParamDefKind> for GenericParamDefKind { - fn from_clean(kind: clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(kind: &clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericParamDefKind::*; match kind { Lifetime { outlives } => GenericParamDefKind::Lifetime { @@ -408,29 +414,29 @@ fn from_clean(kind: clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> }, Type { bounds, default, synthetic } => GenericParamDefKind::Type { bounds: bounds.into_json(renderer), - default: default.map(|x| (*x).into_json(renderer)), - is_synthetic: synthetic, + default: default.as_ref().map(|x| x.as_ref().into_json(renderer)), + is_synthetic: *synthetic, }, Const { ty, default, synthetic: _ } => GenericParamDefKind::Const { - type_: (*ty).into_json(renderer), - default: default.map(|x| *x), + type_: ty.as_ref().into_json(renderer), + default: default.as_ref().map(|x| x.as_ref().clone()), }, } } } impl FromClean<clean::WherePredicate> for WherePredicate { - fn from_clean(predicate: clean::WherePredicate, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(predicate: &clean::WherePredicate, renderer: &JsonRenderer<'_>) -> Self { use clean::WherePredicate::*; match predicate { BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { type_: ty.into_json(renderer), bounds: bounds.into_json(renderer), generic_params: bound_params - .into_iter() + .iter() .map(|x| { let name = x.name.to_string(); - let kind = match x.kind { + let kind = match &x.kind { clean::GenericParamDefKind::Lifetime { outlives } => { GenericParamDefKind::Lifetime { outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(), @@ -442,14 +448,16 @@ fn from_clean(predicate: clean::WherePredicate, renderer: &JsonRenderer<'_>) -> .into_iter() .map(|bound| bound.into_json(renderer)) .collect(), - default: default.map(|ty| (*ty).into_json(renderer)), - is_synthetic: synthetic, + default: default + .as_ref() + .map(|ty| ty.as_ref().into_json(renderer)), + is_synthetic: *synthetic, } } clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => { GenericParamDefKind::Const { - type_: (*ty).into_json(renderer), - default: default.map(|d| *d), + type_: ty.as_ref().into_json(renderer), + default: default.as_ref().map(|d| d.as_ref().clone()), } } }; @@ -462,7 +470,7 @@ fn from_clean(predicate: clean::WherePredicate, renderer: &JsonRenderer<'_>) -> outlives: bounds .iter() .map(|bound| match bound { - clean::GenericBound::Outlives(lt) => convert_lifetime(*lt), + clean::GenericBound::Outlives(lt) => convert_lifetime(lt), _ => bug!("found non-outlives-bound on lifetime predicate"), }) .collect(), @@ -479,7 +487,7 @@ fn from_clean(predicate: clean::WherePredicate, renderer: &JsonRenderer<'_>) -> } impl FromClean<clean::GenericBound> for GenericBound { - fn from_clean(bound: clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(bound: &clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericBound::*; match bound { TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { @@ -494,7 +502,7 @@ fn from_clean(bound: clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self { args.iter() .map(|arg| match arg { clean::PreciseCapturingArg::Lifetime(lt) => { - PreciseCapturingArg::Lifetime(convert_lifetime(*lt)) + PreciseCapturingArg::Lifetime(convert_lifetime(lt)) } clean::PreciseCapturingArg::Param(param) => { PreciseCapturingArg::Param(param.to_string()) @@ -507,7 +515,7 @@ fn from_clean(bound: clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self { } pub(crate) fn from_trait_bound_modifier( - modifiers: rustc_hir::TraitBoundModifiers, + modifiers: &rustc_hir::TraitBoundModifiers, ) -> TraitBoundModifier { use rustc_hir as hir; let hir::TraitBoundModifiers { constness, polarity } = modifiers; @@ -523,7 +531,7 @@ pub(crate) fn from_trait_bound_modifier( } impl FromClean<clean::Type> for Type { - fn from_clean(ty: clean::Type, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(ty: &clean::Type, renderer: &JsonRenderer<'_>) -> Self { use clean::Type::{ Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath, RawPointer, SelfTy, Slice, Tuple, UnsafeBinder, @@ -532,35 +540,35 @@ fn from_clean(ty: clean::Type, renderer: &JsonRenderer<'_>) -> Self { match ty { clean::Type::Path { path } => Type::ResolvedPath(path.into_json(renderer)), clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { - lifetime: lt.map(convert_lifetime), + lifetime: lt.as_ref().map(convert_lifetime), traits: bounds.into_json(renderer), }), Generic(s) => Type::Generic(s.to_string()), // FIXME: add dedicated variant to json Type? SelfTy => Type::Generic("Self".to_owned()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), - BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_json(renderer))), + BareFunction(f) => Type::FunctionPointer(Box::new(f.as_ref().into_json(renderer))), Tuple(t) => Type::Tuple(t.into_json(renderer)), - Slice(t) => Type::Slice(Box::new((*t).into_json(renderer))), + Slice(t) => Type::Slice(Box::new(t.as_ref().into_json(renderer))), Array(t, s) => { - Type::Array { type_: Box::new((*t).into_json(renderer)), len: s.to_string() } + Type::Array { type_: Box::new(t.as_ref().into_json(renderer)), len: s.to_string() } } clean::Type::Pat(t, p) => Type::Pat { - type_: Box::new((*t).into_json(renderer)), + type_: Box::new(t.as_ref().into_json(renderer)), __pat_unstable_do_not_use: p.to_string(), }, ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { - is_mutable: mutability == ast::Mutability::Mut, - type_: Box::new((*type_).into_json(renderer)), + is_mutable: *mutability == ast::Mutability::Mut, + type_: Box::new(type_.as_ref().into_json(renderer)), }, BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { - lifetime: lifetime.map(convert_lifetime), - is_mutable: mutability == ast::Mutability::Mut, - type_: Box::new((*type_).into_json(renderer)), + lifetime: lifetime.as_ref().map(convert_lifetime), + is_mutable: *mutability == ast::Mutability::Mut, + type_: Box::new(type_.as_ref().into_json(renderer)), }, - QPath(qpath) => (*qpath).into_json(renderer), + QPath(qpath) => qpath.as_ref().into_json(renderer), // FIXME(unsafe_binder): Implement rustdoc-json. UnsafeBinder(_) => todo!(), } @@ -568,30 +576,30 @@ fn from_clean(ty: clean::Type, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<clean::Path> for Path { - fn from_clean(path: clean::Path, renderer: &JsonRenderer<'_>) -> Path { + fn from_clean(path: &clean::Path, renderer: &JsonRenderer<'_>) -> Path { Path { path: path.whole_name(), id: renderer.id_from_item_default(path.def_id().into()), - args: path.segments.last().map(|args| Box::new(args.clone().args.into_json(renderer))), + args: path.segments.last().map(|args| Box::new(args.args.into_json(renderer))), } } } impl FromClean<clean::QPathData> for Type { - fn from_clean(qpath: clean::QPathData, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(qpath: &clean::QPathData, renderer: &JsonRenderer<'_>) -> Self { let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath; Self::QualifiedPath { name: assoc.name.to_string(), args: Box::new(assoc.args.into_json(renderer)), self_type: Box::new(self_type.into_json(renderer)), - trait_: trait_.map(|trait_| trait_.into_json(renderer)), + trait_: trait_.as_ref().map(|trait_| trait_.into_json(renderer)), } } } impl FromClean<clean::Term> for Term { - fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term { + fn from_clean(term: &clean::Term, renderer: &JsonRenderer<'_>) -> Term { match term { clean::Term::Type(ty) => Term::Type(ty.into_json(renderer)), clean::Term::Constant(c) => Term::Constant(c.into_json(renderer)), @@ -600,14 +608,14 @@ fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term { } impl FromClean<clean::BareFunctionDecl> for FunctionPointer { - fn from_clean(bare_decl: clean::BareFunctionDecl, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(bare_decl: &clean::BareFunctionDecl, renderer: &JsonRenderer<'_>) -> Self { let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl; FunctionPointer { header: FunctionHeader { is_unsafe: safety.is_unsafe(), is_const: false, is_async: false, - abi: convert_abi(abi), + abi: convert_abi(*abi), }, generic_params: generic_params.into_json(renderer), sig: decl.into_json(renderer), @@ -616,7 +624,7 @@ fn from_clean(bare_decl: clean::BareFunctionDecl, renderer: &JsonRenderer<'_>) - } impl FromClean<clean::FnDecl> for FunctionSignature { - fn from_clean(decl: clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(decl: &clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self { let clean::FnDecl { inputs, output, c_variadic } = decl; FunctionSignature { inputs: inputs @@ -629,13 +637,13 @@ fn from_clean(decl: clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self { }) .collect(), output: if output.is_unit() { None } else { Some(output.into_json(renderer)) }, - is_c_variadic: c_variadic, + is_c_variadic: *c_variadic, } } } impl FromClean<clean::Trait> for Trait { - fn from_clean(trait_: clean::Trait, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(trait_: &clean::Trait, renderer: &JsonRenderer<'_>) -> Self { let tcx = renderer.tcx; let is_auto = trait_.is_auto(tcx); let is_unsafe = trait_.safety(tcx).is_unsafe(); @@ -645,7 +653,7 @@ fn from_clean(trait_: clean::Trait, renderer: &JsonRenderer<'_>) -> Self { is_auto, is_unsafe, is_dyn_compatible, - items: renderer.ids(items), + items: renderer.ids(&items), generics: generics.into_json(renderer), bounds: bounds.into_json(renderer), implementations: Vec::new(), // Added in JsonRenderer::item @@ -655,7 +663,7 @@ fn from_clean(trait_: clean::Trait, renderer: &JsonRenderer<'_>) -> Self { impl FromClean<clean::PolyTrait> for PolyTrait { fn from_clean( - clean::PolyTrait { trait_, generic_params }: clean::PolyTrait, + clean::PolyTrait { trait_, generic_params }: &clean::PolyTrait, renderer: &JsonRenderer<'_>, ) -> Self { PolyTrait { @@ -666,14 +674,14 @@ fn from_clean( } impl FromClean<clean::Impl> for Impl { - fn from_clean(impl_: clean::Impl, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(impl_: &clean::Impl, renderer: &JsonRenderer<'_>) -> Self { let provided_trait_methods = impl_.provided_trait_methods(renderer.tcx); let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_; // FIXME: use something like ImplKind in JSON? let (is_synthetic, blanket_impl) = match kind { clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None), clean::ImplKind::Auto => (true, None), - clean::ImplKind::Blanket(ty) => (false, Some(*ty)), + clean::ImplKind::Blanket(ty) => (false, Some(ty)), }; let is_negative = match polarity { ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false, @@ -686,18 +694,18 @@ fn from_clean(impl_: clean::Impl, renderer: &JsonRenderer<'_>) -> Self { .into_iter() .map(|x| x.to_string()) .collect(), - trait_: trait_.map(|path| path.into_json(renderer)), + trait_: trait_.as_ref().map(|path| path.into_json(renderer)), for_: for_.into_json(renderer), - items: renderer.ids(items), + items: renderer.ids(&items), is_negative, is_synthetic, - blanket_impl: blanket_impl.map(|x| x.into_json(renderer)), + blanket_impl: blanket_impl.map(|x| x.as_ref().into_json(renderer)), } } } pub(crate) fn from_function( - clean::Function { decl, generics }: clean::Function, + clean::Function { decl, generics }: &clean::Function, has_body: bool, header: rustc_hir::FnHeader, renderer: &JsonRenderer<'_>, @@ -711,30 +719,30 @@ pub(crate) fn from_function( } impl FromClean<clean::Enum> for Enum { - fn from_clean(enum_: clean::Enum, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(enum_: &clean::Enum, renderer: &JsonRenderer<'_>) -> Self { let has_stripped_variants = enum_.has_stripped_entries(); let clean::Enum { variants, generics } = enum_; Enum { generics: generics.into_json(renderer), has_stripped_variants, - variants: renderer.ids(variants), + variants: renderer.ids(&variants.as_slice().raw), impls: Vec::new(), // Added in JsonRenderer::item } } } impl FromClean<clean::Variant> for Variant { - fn from_clean(variant: clean::Variant, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(variant: &clean::Variant, renderer: &JsonRenderer<'_>) -> Self { use clean::VariantKind::*; - let discriminant = variant.discriminant.map(|d| d.into_json(renderer)); + let discriminant = variant.discriminant.as_ref().map(|d| d.into_json(renderer)); - let kind = match variant.kind { + let kind = match &variant.kind { CLike => VariantKind::Plain, - Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(fields)), + Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(&fields)), Struct(s) => VariantKind::Struct { has_stripped_fields: s.has_stripped_entries(), - fields: renderer.ids(s.fields), + fields: renderer.ids(&s.fields), }, }; @@ -743,7 +751,7 @@ fn from_clean(variant: clean::Variant, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<clean::Discriminant> for Discriminant { - fn from_clean(disr: clean::Discriminant, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(disr: &clean::Discriminant, renderer: &JsonRenderer<'_>) -> Self { let tcx = renderer.tcx; Discriminant { // expr is only none if going through the inlining path, which gets @@ -756,7 +764,7 @@ fn from_clean(disr: clean::Discriminant, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<clean::Import> for Use { - fn from_clean(import: clean::Import, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(import: &clean::Import, renderer: &JsonRenderer<'_>) -> Self { use clean::ImportKind::*; let (name, is_glob) = match import.kind { Simple(s) => (s.to_string(), false), @@ -775,7 +783,7 @@ fn from_clean(import: clean::Import, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<clean::ProcMacro> for ProcMacro { - fn from_clean(mac: clean::ProcMacro, _renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(mac: &clean::ProcMacro, _renderer: &JsonRenderer<'_>) -> Self { ProcMacro { kind: from_macro_kind(mac.kind), helpers: mac.helpers.iter().map(|x| x.to_string()).collect(), @@ -792,21 +800,21 @@ pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind } } -impl FromClean<Box<clean::TypeAlias>> for TypeAlias { - fn from_clean(type_alias: Box<clean::TypeAlias>, renderer: &JsonRenderer<'_>) -> Self { - let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = *type_alias; +impl FromClean<clean::TypeAlias> for TypeAlias { + fn from_clean(type_alias: &clean::TypeAlias, renderer: &JsonRenderer<'_>) -> Self { + let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = type_alias; TypeAlias { type_: type_.into_json(renderer), generics: generics.into_json(renderer) } } } fn convert_static( - stat: clean::Static, - safety: rustc_hir::Safety, + stat: &clean::Static, + safety: &rustc_hir::Safety, renderer: &JsonRenderer<'_>, ) -> Static { let tcx = renderer.tcx; Static { - type_: (*stat.type_).into_json(renderer), + type_: stat.type_.as_ref().into_json(renderer), is_mutable: stat.mutability == ast::Mutability::Mut, is_unsafe: safety.is_unsafe(), expr: stat @@ -817,7 +825,7 @@ fn convert_static( } impl FromClean<clean::TraitAlias> for TraitAlias { - fn from_clean(alias: clean::TraitAlias, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(alias: &clean::TraitAlias, renderer: &JsonRenderer<'_>) -> Self { TraitAlias { generics: alias.generics.into_json(renderer), params: alias.bounds.into_json(renderer), @@ -826,7 +834,7 @@ fn from_clean(alias: clean::TraitAlias, renderer: &JsonRenderer<'_>) -> Self { } impl FromClean<ItemType> for ItemKind { - fn from_clean(kind: ItemType, _renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(kind: &ItemType, _renderer: &JsonRenderer<'_>) -> Self { use ItemType::*; match kind { Module => ItemKind::Module,
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 131a12c..2feadce 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs
@@ -18,6 +18,7 @@ use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::features::StabilityExt; use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; // It's important to use the FxHashMap from rustdoc_json_types here, instead of @@ -36,19 +37,18 @@ use crate::json::conversions::IntoJson; use crate::{clean, try_err}; -#[derive(Clone)] pub(crate) struct JsonRenderer<'tcx> { tcx: TyCtxt<'tcx>, /// A mapping of IDs that contains all local items for this crate which gets output as a top /// level field of the JSON blob. - index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>, + index: FxHashMap<types::Id, types::Item>, /// The directory where the JSON blob should be written to. /// /// If this is `None`, the blob will be printed to `stdout` instead. out_dir: Option<PathBuf>, cache: Rc<Cache>, imported_items: DefIdSet, - id_interner: Rc<RefCell<ids::IdInterner>>, + id_interner: RefCell<ids::IdInterner>, } impl<'tcx> JsonRenderer<'tcx> { @@ -65,7 +65,7 @@ fn get_trait_implementors(&mut self, id: DefId) -> Vec<types::Id> { .iter() .map(|i| { let item = &i.impl_item; - self.item(item.clone()).unwrap(); + self.item(item).unwrap(); self.id_from_item(item) }) .collect() @@ -96,7 +96,7 @@ fn get_impls(&mut self, id: DefId) -> Vec<types::Id> { } if item.item_id.is_local() || is_primitive_impl { - self.item(item.clone()).unwrap(); + self.item(item).unwrap(); Some(self.id_from_item(item)) } else { None @@ -148,7 +148,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { .copied() .filter(|(_, stability, _)| { // Describe only target features which the user can toggle - stability.toggle_allowed().is_ok() + stability.is_toggle_permitted(sess).is_ok() }) .map(|(name, stability, implied_features)| { types::TargetFeature { @@ -164,7 +164,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { // Imply only target features which the user can toggle feature_stability .get(name) - .map(|stability| stability.toggle_allowed().is_ok()) + .map(|stability| stability.is_toggle_permitted(sess).is_ok()) .unwrap_or(false) }) .map(String::from) @@ -197,7 +197,7 @@ fn init( Ok(( JsonRenderer { tcx, - index: Rc::new(RefCell::new(FxHashMap::default())), + index: FxHashMap::default(), out_dir: if options.output_to_stdout { None } else { Some(options.output) }, cache: Rc::new(cache), imported_items, @@ -217,7 +217,9 @@ fn restore_module_data(&mut self, _info: Self::ModuleData) { /// Inserts an item into the index. This should be used rather than directly calling insert on /// the hashmap because certain items (traits and types) need to have their mappings for trait /// implementations filled out before they're inserted. - fn item(&mut self, item: clean::Item) -> Result<(), Error> { + fn item(&mut self, item: &clean::Item) -> Result<(), Error> { + use std::collections::hash_map::Entry; + let item_type = item.type_(); let item_name = item.name; trace!("rendering {item_type} {item_name:?}"); @@ -225,11 +227,11 @@ fn item(&mut self, item: clean::Item) -> Result<(), Error> { // Flatten items that recursively store other items. We include orphaned items from // stripped modules and etc that are otherwise reachable. if let ItemKind::StrippedItem(inner) = &item.kind { - inner.inner_items().for_each(|i| self.item(i.clone()).unwrap()); + inner.inner_items().for_each(|i| self.item(i).unwrap()); } // Flatten items that recursively store other items - item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap()); + item.kind.inner_items().for_each(|i| self.item(i).unwrap()); let item_id = item.item_id; if let Some(mut new_item) = self.convert_item(item) { @@ -272,18 +274,25 @@ fn item(&mut self, item: clean::Item) -> Result<(), Error> { | types::ItemEnum::Macro(_) | types::ItemEnum::ProcMacro(_) => false, }; - let removed = self.index.borrow_mut().insert(new_item.id, new_item.clone()); // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check // to make sure the items are unique. The main place this happens is when an item, is // reexported in more than one place. See `rustdoc-json/reexport/in_root_and_mod` - if let Some(old_item) = removed { - // In case of generic implementations (like `impl<T> Trait for T {}`), all the - // inner items will be duplicated so we can ignore if they are slightly different. - if !can_be_ignored { - assert_eq!(old_item, new_item); + match self.index.entry(new_item.id) { + Entry::Vacant(entry) => { + entry.insert(new_item); } - trace!("replaced {old_item:?}\nwith {new_item:?}"); + Entry::Occupied(mut entry) => { + // In case of generic implementations (like `impl<T> Trait for T {}`), all the + // inner items will be duplicated so we can ignore if they are slightly + // different. + let old_item = entry.get_mut(); + if !can_be_ignored { + assert_eq!(*old_item, new_item); + } + trace!("replaced {old_item:?}\nwith {new_item:?}"); + *old_item = new_item; + } } } @@ -295,11 +304,13 @@ fn mod_item_in(&mut self, _item: &clean::Item) -> Result<(), Error> { unreachable!("RUN_ON_MODULE = false, should never call mod_item_in") } - fn after_krate(&mut self) -> Result<(), Error> { + fn after_krate(mut self) -> Result<(), Error> { debug!("Done with crate"); let e = ExternalCrate { crate_num: LOCAL_CRATE }; - let index = (*self.index).clone().into_inner(); + + // We've finished using the index, and don't want to clone it, because it is big. + let index = std::mem::take(&mut self.index); // Note that tcx.rust_target_features is inappropriate here because rustdoc tries to run for // multiple targets: https://github.com/rust-lang/rust/pull/137632 @@ -324,7 +335,7 @@ fn after_krate(&mut self) -> Result<(), Error> { types::ItemSummary { crate_id: k.krate.as_u32(), path: path.iter().map(|s| s.to_string()).collect(), - kind: kind.into_json(self), + kind: kind.into_json(&self), }, ) })
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 3a98217..0cfe89a 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md
@@ -5685,6 +5685,7 @@ [`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned +[`coerce_container_to_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#coerce_container_to_any [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity [`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 @@ -5736,6 +5737,7 @@ [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs [`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items +[`doc_suspicious_footnotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_suspicious_footnotes [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons [`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use @@ -5862,6 +5864,7 @@ [`ineffective_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_open_options [`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match +[`infallible_try_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_try_from [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter [`infinite_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_loop [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string @@ -5888,6 +5891,7 @@ [`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`io_other_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error +[`ip_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#ip_constant [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module @@ -6163,6 +6167,7 @@ [`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false +[`pointer_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointer_format [`pointers_in_nomem_asm_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointers_in_nomem_asm_block [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 320462a..08592f2 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -73,8 +73,8 @@ pub fn generate_lint_files( ( "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`", + "// 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();
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 59a0c7c..b9ae9af 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -204,7 +204,7 @@ fn lint_impl_item<T: LintContext>(&self, cx: &T, item: &ImplItemRef, before_item self.assoc_types_order ), Some(before_item.span), - format!("should be placed before `{}`", before_item.ident.as_str(),), + format!("should be placed before `{}`", before_item.ident.name), ); } @@ -216,7 +216,7 @@ fn lint_member_name<T: LintContext>(cx: &T, ident: &rustc_span::Ident, before_id ident.span, "incorrect ordering of items (must be alphabetically ordered)", Some(before_ident.span), - format!("should be placed before `{}`", before_ident.as_str(),), + format!("should be placed before `{}`", before_ident.name), ); } @@ -228,7 +228,7 @@ fn lint_member_item<T: LintContext>(cx: &T, item: &Item<'_>, before_item: &Item< }; let (before_span, note) = if let Some(ident) = before_item.kind.ident() { - (ident.span, format!("should be placed before `{}`", ident.as_str(),)) + (ident.span, format!("should be placed before `{}`", ident.name)) } else { ( before_item.span, @@ -255,7 +255,7 @@ fn lint_trait_item<T: LintContext>(&self, cx: &T, item: &TraitItemRef, before_it self.assoc_types_order ), Some(before_item.span), - format!("should be placed before `{}`", before_item.ident.as_str(),), + format!("should be placed before `{}`", before_item.ident.name), ); } }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs index 0edb50b..d67a194 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
@@ -61,7 +61,7 @@ pub(super) fn check_clippy(cx: &EarlyContext<'_>, attr: &Attribute) { fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) { if let Some(ident) = attr.ident() { - if ["any", "all", "not"].contains(&ident.name.as_str()) { + if matches!(ident.name, sym::any | sym::all | sym::not) { let Some(list) = attr.meta_item_list() else { return }; for item in list.iter().filter_map(|item| item.meta_item()) { check_deprecated_cfg_recursively(cx, item);
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index a851daa..c2406bc 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -1,9 +1,10 @@ use super::DUPLICATED_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; +use itertools::Itertools; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_lint::EarlyContext; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use std::collections::hash_map::Entry; fn emit_if_duplicated( @@ -29,7 +30,7 @@ fn check_duplicated_attr( cx: &EarlyContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap<String, Span>, - parent: &mut Vec<String>, + parent: &mut Vec<Symbol>, ) { if attr.span.from_expansion() { return; @@ -43,7 +44,7 @@ fn check_duplicated_attr( return; } if let Some(direct_parent) = parent.last() - && direct_parent == sym::cfg_trace.as_str() + && *direct_parent == sym::cfg_trace && [sym::all, sym::not, sym::any].contains(&name) { // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one @@ -51,9 +52,14 @@ fn check_duplicated_attr( return; } if let Some(value) = attr.value_str() { - emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":"))); + emit_if_duplicated( + cx, + attr, + attr_paths, + format!("{}:{name}={value}", parent.iter().join(":")), + ); } else if let Some(sub_attrs) = attr.meta_item_list() { - parent.push(name.as_str().to_string()); + parent.push(name); for sub_attr in sub_attrs { if let Some(meta) = sub_attr.meta_item() { check_duplicated_attr(cx, meta, attr_paths, parent); @@ -61,7 +67,7 @@ fn check_duplicated_attr( } parent.pop(); } else { - emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.join(":"))); + emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.iter().join(":"))); } }
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 7c6fd91..bf43234 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -1,10 +1,10 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::eq_expr_value; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{eq_expr_value, sym}; use rustc_ast::ast::LitKind; use rustc_attr_data_structures::RustcVersion; use rustc_errors::Applicability; @@ -13,7 +13,7 @@ use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, SyntaxContext, sym}; +use rustc_span::{Span, Symbol, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -73,10 +73,10 @@ } // For each pairs, both orders are considered. -const METHODS_WITH_NEGATION: [(Option<RustcVersion>, &str, &str); 3] = [ - (None, "is_some", "is_none"), - (None, "is_err", "is_ok"), - (Some(msrvs::IS_NONE_OR), "is_some_and", "is_none_or"), +const METHODS_WITH_NEGATION: [(Option<RustcVersion>, Symbol, Symbol); 3] = [ + (None, sym::is_some, sym::is_none), + (None, sym::is_err, sym::is_ok), + (Some(msrvs::IS_NONE_OR), sym::is_some_and, sym::is_none_or), ]; pub struct NonminimalBool { @@ -440,9 +440,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio .iter() .copied() .flat_map(|(msrv, a, b)| vec![(msrv, a, b), (msrv, b, a)]) - .find(|&(msrv, a, _)| { - a == path.ident.name.as_str() && msrv.is_none_or(|msrv| curr_msrv.meets(cx, msrv)) - }) + .find(|&(msrv, a, _)| a == path.ident.name && msrv.is_none_or(|msrv| curr_msrv.meets(cx, msrv))) .and_then(|(_, _, neg_method)| { let negated_args = args .iter()
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index 0f066fa..c1d6cec 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -76,19 +76,20 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M return false; } - match (cast_from.is_integral(), cast_to.is_integral()) { - (true, true) => { + match ( + utils::int_ty_to_nbits(cx.tcx, cast_from), + utils::int_ty_to_nbits(cx.tcx, cast_to), + ) { + (Some(from_nbits), Some(to_nbits)) => { let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed(); - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned }, - (true, false) => { - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); + (Some(from_nbits), None) => { + // FIXME: handle `f16` and `f128` let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { 32 } else { @@ -96,9 +97,7 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M }; !is_isize_or_usize(cast_from) && from_nbits < to_nbits }, - (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(cx, msrvs::FROM_BOOL) => true, - (_, _) => { - matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) - }, + (None, Some(_)) if cast_from.is_bool() && msrv.meets(cx, msrvs::FROM_BOOL) => true, + _ => matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)), } }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 4120e5c..a2ecb5f 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -91,15 +91,14 @@ pub(super) fn check( cast_to: Ty<'_>, cast_to_span: Span, ) { - let msg = match (cast_from.kind(), cast_to.is_integral()) { - (ty::Int(_) | ty::Uint(_), true) => { + let msg = match (cast_from.kind(), utils::int_ty_to_nbits(cx.tcx, cast_to)) { + (ty::Int(_) | ty::Uint(_), Some(to_nbits)) => { let from_nbits = apply_reductions( cx, - utils::int_ty_to_nbits(cast_from, cx.tcx), + utils::int_ty_to_nbits(cx.tcx, cast_from).unwrap(), cast_expr, cast_from.is_signed(), ); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { (true, true) | (false, false) => (to_nbits < from_nbits, ""), @@ -121,7 +120,7 @@ pub(super) fn check( format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",) }, - (ty::Adt(def, _), true) if def.is_enum() => { + (ty::Adt(def, _), Some(to_nbits)) if def.is_enum() => { let (from_nbits, variant) = if let ExprKind::Path(p) = &cast_expr.kind && let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id) { @@ -132,7 +131,6 @@ pub(super) fn check( } else { (utils::enum_ty_to_nbits(*def, cx.tcx), None) }; - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); let cast_from_ptr_size = def.repr().int.is_none_or(|ty| matches!(ty, IntegerType::Pointer(_),)); let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) { @@ -157,11 +155,11 @@ pub(super) fn check( format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}") }, - (ty::Float(_), true) => { + (ty::Float(_), Some(_)) => { format!("casting `{cast_from}` to `{cast_to}` may truncate the value") }, - (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { + (ty::Float(FloatTy::F64), None) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { "casting `f64` to `f32` may truncate the value".to_string() },
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs index 504d0a2..e26c03c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -17,9 +17,12 @@ enum EmitState { } pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { - if !(cast_from.is_integral() && cast_to.is_integral()) { + let (Some(from_nbits), Some(to_nbits)) = ( + utils::int_ty_to_nbits(cx.tcx, cast_from), + utils::int_ty_to_nbits(cx.tcx, cast_to), + ) else { return; - } + }; // emit a lint if a cast is: // 1. unsigned to signed @@ -35,9 +38,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca return; } - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); - let should_lint = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) { (true, true) => { // casts between two ptr sized integers are trivially always the same size
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs index 1eb115c..712e38d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
@@ -7,15 +7,14 @@ use super::{CAST_PRECISION_LOSS, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { - if !cast_from.is_integral() || cast_to.is_integral() { + let Some(from_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_from) else { return; - } + }; - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) { - 32 - } else { - 64 + // FIXME: handle `f16` and `f128` + let to_nbits = match cast_to.kind() { + ty::Float(f @ (FloatTy::F32 | FloatTy::F64)) => f.bit_width(), + _ => return, }; if !(is_isize_or_usize(cast_from) || from_nbits >= to_nbits) { @@ -29,9 +28,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca let from_nbits_str = if arch_dependent { "64".to_owned() } else if is_isize_or_usize(cast_from) { + // FIXME: handle 16 bits `usize` type "32 or 64".to_owned() } else { - utils::int_ty_to_nbits(cast_from, cx.tcx).to_string() + from_nbits.to_string() }; span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index 01020f3..e4dafde 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -61,7 +61,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { }; match parent.kind { ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => { - if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned") + if matches!(name.ident.name, sym::read_unaligned | sym::write_unaligned) && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && let Some(def_id) = cx.tcx.impl_of_method(def_id) && cx.tcx.type_of(def_id).instantiate_identity().is_raw_ptr()
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs index ac1a355..1054770 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
@@ -3,24 +3,22 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, UintTy}; +use rustc_middle::ty::{self, Ty}; use super::{FN_TO_NUMERIC_CAST, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` - match cast_to.kind() { - ty::Uint(_) | ty::Int(..) => { /* continue on */ }, - _ => return, - } + let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else { + return; + }; match cast_from.kind() { ty::FnDef(..) | ty::FnPtr(..) => { let mut applicability = Applicability::MaybeIncorrect; - let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); - if (to_nbits >= cx.tcx.data_layout.pointer_size.bits()) && (*cast_to.kind() != ty::Uint(UintTy::Usize)) { + if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() { + let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); span_lint_and_sugg( cx, FN_TO_NUMERIC_CAST,
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 18e7798..700b7d0 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
@@ -9,16 +9,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` - match cast_to.kind() { - ty::Uint(_) | ty::Int(..) => { /* continue on */ }, - _ => return, - } + let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else { + return; + }; match cast_from.kind() { ty::FnDef(..) | ty::FnPtr(..) => { let mut applicability = Applicability::MaybeIncorrect; let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); if to_nbits < cx.tcx.data_layout.pointer_size.bits() { span_lint_and_sugg( cx,
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 8e8c55c..010f09d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -185,7 +185,7 @@ fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => { MaybeParenOrBlock::Block }, - Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren, + Node::Expr(parent) if cx.precedence(cast_expr) < cx.precedence(parent) => MaybeParenOrBlock::Paren, _ => MaybeParenOrBlock::Nothing, };
diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs index 5ccba92..318a164 100644 --- a/src/tools/clippy/clippy_lints/src/casts/utils.rs +++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs
@@ -1,27 +1,14 @@ use clippy_utils::ty::{EnumValue, read_explicit_enum_value}; use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; -/// Returns the size in bits of an integral type. -/// Will return 0 if the type is not an int or uint variant -pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { - match typ.kind() { - ty::Int(i) => match i { - IntTy::Isize => tcx.data_layout.pointer_size.bits(), - IntTy::I8 => 8, - IntTy::I16 => 16, - IntTy::I32 => 32, - IntTy::I64 => 64, - IntTy::I128 => 128, - }, - ty::Uint(i) => match i { - UintTy::Usize => tcx.data_layout.pointer_size.bits(), - UintTy::U8 => 8, - UintTy::U16 => 16, - UintTy::U32 => 32, - UintTy::U64 => 64, - UintTy::U128 => 128, - }, - _ => 0, +/// Returns the size in bits of an integral type, or `None` if `ty` is not an +/// integral type. +pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<u64> { + match ty.kind() { + ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()), + ty::Int(i) => i.bit_width(), + ty::Uint(i) => i.bit_width(), + _ => None, } }
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 8ada608..9b3822f 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -98,7 +99,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { struct Conversion<'a> { cvt: ConversionType, expr_to_cast: &'a Expr<'a>, - to_type: Option<&'a str>, + to_type: Option<Symbol>, } /// The kind of conversion that is checked @@ -150,7 +151,7 @@ fn has_compatible_to_type(&self, other: &Self) -> bool { } /// Try to construct a new conversion if the conversion type is valid - fn try_new(expr_to_cast: &'a Expr<'_>, from_type: &str, to_type: &'a str) -> Option<Conversion<'a>> { + fn try_new(expr_to_cast: &'a Expr<'_>, from_type: Symbol, to_type: Symbol) -> Option<Conversion<'a>> { ConversionType::try_new(from_type, to_type).map(|cvt| Conversion { cvt, expr_to_cast, @@ -171,7 +172,7 @@ fn new_any(expr_to_cast: &'a Expr<'_>) -> Conversion<'a> { impl ConversionType { /// Creates a conversion type if the type is allowed & conversion is valid #[must_use] - fn try_new(from: &str, to: &str) -> Option<Self> { + fn try_new(from: Symbol, to: Symbol) -> Option<Self> { if UINTS.contains(&from) { Some(Self::FromUnsigned) } else if SINTS.contains(&from) { @@ -190,7 +191,7 @@ fn try_new(from: &str, to: &str) -> Option<Self> { /// Check for `expr <= (to_type::MAX as from_type)` fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> { - if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") { + if let Some((from, to)) = get_types_from_cast(gt, INTS, sym::max_value, sym::MAX) { Conversion::try_new(lt, from, to) } else { None @@ -209,7 +210,7 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> O /// Check for `expr >= (to_type::MIN as from_type)` fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> { - if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") { + if let Some((from, to)) = get_types_from_cast(check, SINTS, sym::min_value, sym::MIN) { Conversion::try_new(candidate, from, to) } else { None @@ -217,15 +218,15 @@ fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Op } /// Tries to extract the from- and to-type from a cast expression -fn get_types_from_cast<'a>( - expr: &'a Expr<'_>, - types: &'a [&str], - func: &'a str, - assoc_const: &'a str, -) -> Option<(&'a str, &'a str)> { +fn get_types_from_cast( + expr: &Expr<'_>, + types: &[Symbol], + func: Symbol, + assoc_const: Symbol, +) -> Option<(Symbol, Symbol)> { // `to_type::max_value() as from_type` // or `to_type::MAX as from_type` - let call_from_cast: Option<(&Expr<'_>, &str)> = if let ExprKind::Cast(limit, from_type) = &expr.kind + let call_from_cast: Option<(&Expr<'_>, Symbol)> = if let ExprKind::Cast(limit, from_type) = &expr.kind // to_type::max_value(), from_type && let TyKind::Path(from_type_path) = &from_type.kind && let Some(from_sym) = int_ty_to_sym(from_type_path) @@ -236,12 +237,12 @@ fn get_types_from_cast<'a>( }; // `from_type::from(to_type::max_value())` - let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { + let limit_from: Option<(&Expr<'_>, Symbol)> = call_from_cast.or_else(|| { if let ExprKind::Call(from_func, [limit]) = &expr.kind // `from_type::from, to_type::max_value()` // `from_type::from` && let ExprKind::Path(path) = &from_func.kind - && let Some(from_sym) = get_implementing_type(path, INTS, "from") + && let Some(from_sym) = get_implementing_type(path, INTS, sym::from) { Some((limit, from_sym)) } else { @@ -273,32 +274,41 @@ fn get_types_from_cast<'a>( } /// Gets the type which implements the called function -fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> { +fn get_implementing_type(path: &QPath<'_>, candidates: &[Symbol], function: Symbol) -> Option<Symbol> { if let QPath::TypeRelative(ty, path) = &path - && path.ident.name.as_str() == function + && path.ident.name == function && let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind && let [int] = tp.segments { - let name = int.ident.name.as_str(); - candidates.iter().find(|c| &name == *c).copied() + candidates.iter().find(|c| int.ident.name == **c).copied() } else { None } } /// Gets the type as a string, if it is a supported integer -fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { +fn int_ty_to_sym(path: &QPath<'_>) -> Option<Symbol> { if let QPath::Resolved(_, path) = *path && let [ty] = path.segments { - let name = ty.ident.name.as_str(); - INTS.iter().find(|c| &name == *c).copied() + INTS.iter().find(|c| ty.ident.name == **c).copied() } else { None } } // Constants -const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"]; -const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"]; -const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"]; +const UINTS: &[Symbol] = &[sym::u8, sym::u16, sym::u32, sym::u64, sym::usize]; +const SINTS: &[Symbol] = &[sym::i8, sym::i16, sym::i32, sym::i64, sym::isize]; +const INTS: &[Symbol] = &[ + sym::u8, + sym::u16, + sym::u32, + sym::u64, + sym::usize, + sym::i8, + sym::i16, + sym::i32, + sym::i64, + sym::isize, +];
diff --git a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs index 6b239a1..e33a8e0 100644 --- a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs +++ b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
@@ -17,7 +17,7 @@ /// /// ### Why is this bad /// - /// A reference does not need to be owned in order to used as a slice. + /// A reference does not need to be owned in order to be used as a slice. /// /// ### Known problems ///
diff --git a/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs b/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs new file mode 100644 index 0000000..2b65925 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs
@@ -0,0 +1,108 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::sym; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, ExistentialPredicate, Ty, TyCtxt}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// Protects against unintended coercion of references to container types to `&dyn Any` when the + /// container type dereferences to a `dyn Any` which could be directly referenced instead. + /// + /// ### Why is this bad? + /// + /// The intention is usually to get a reference to the `dyn Any` the value dereferences to, + /// rather than coercing a reference to the container itself to `&dyn Any`. + /// + /// ### Example + /// + /// Because `Box<dyn Any>` itself implements `Any`, `&Box<dyn Any>` + /// can be coerced to an `&dyn Any` which refers to *the `Box` itself*, rather than the + /// inner `dyn Any`. + /// ```no_run + /// # use std::any::Any; + /// let x: Box<dyn Any> = Box::new(0u32); + /// let dyn_any_of_box: &dyn Any = &x; + /// + /// // Fails as we have a &dyn Any to the Box, not the u32 + /// assert_eq!(dyn_any_of_box.downcast_ref::<u32>(), None); + /// ``` + /// Use instead: + /// ```no_run + /// # use std::any::Any; + /// let x: Box<dyn Any> = Box::new(0u32); + /// let dyn_any_of_u32: &dyn Any = &*x; + /// + /// // Succeeds since we have a &dyn Any to the inner u32! + /// assert_eq!(dyn_any_of_u32.downcast_ref::<u32>(), Some(&0u32)); + /// ``` + #[clippy::version = "1.88.0"] + pub COERCE_CONTAINER_TO_ANY, + nursery, + "coercing to `&dyn Any` when dereferencing could produce a `dyn Any` without coercion is usually not intended" +} +declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]); + +impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + // If this expression has an effective type of `&dyn Any` ... + { + let coerced_ty = cx.typeck_results().expr_ty_adjusted(e); + + let ty::Ref(_, coerced_ref_ty, _) = *coerced_ty.kind() else { + return; + }; + if !is_dyn_any(cx.tcx, coerced_ref_ty) { + return; + } + } + + let expr_ty = cx.typeck_results().expr_ty(e); + let ty::Ref(_, expr_ref_ty, _) = *expr_ty.kind() else { + return; + }; + // ... but only due to coercion ... + if is_dyn_any(cx.tcx, expr_ref_ty) { + return; + } + // ... and it also *derefs* to `dyn Any` ... + let Some((depth, target)) = clippy_utils::ty::deref_chain(cx, expr_ref_ty).enumerate().last() else { + return; + }; + if !is_dyn_any(cx.tcx, target) { + return; + } + + // ... that's probably not intended. + let (span, deref_count) = match e.kind { + // If `e` was already an `&` expression, skip `*&` in the suggestion + ExprKind::AddrOf(_, _, referent) => (referent.span, depth), + _ => (e.span, depth + 1), + }; + span_lint_and_sugg( + cx, + COERCE_CONTAINER_TO_ANY, + e.span, + format!("coercing `{expr_ty}` to `&dyn Any`"), + "consider dereferencing", + format!("&{}{}", str::repeat("*", deref_count), snippet(cx, span, "x")), + Applicability::MaybeIncorrect, + ); + } +} + +fn is_dyn_any(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { + let ty::Dynamic(traits, ..) = ty.kind() else { + return false; + }; + traits.iter().any(|binder| { + let ExistentialPredicate::Trait(t) = binder.skip_binder() else { + return false; + }; + tcx.is_diagnostic_item(sym::Any, t.def_id) + }) +}
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 2467fc9..5ef7266 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -425,7 +425,9 @@ fn scan_block_for_eq<'tcx>( modifies_any_local(cx, stmt, &cond_locals) || !eq_stmts(stmt, blocks, |b| b.stmts.get(i), &mut eq, &mut moved_locals) }) - .map_or(block.stmts.len(), |(i, _)| i); + .map_or(block.stmts.len(), |(i, stmt)| { + adjust_by_closest_callsite(i, stmt, block.stmts[..i].iter().enumerate().rev()) + }); if local_needs_ordered_drop { return BlockEq { @@ -467,7 +469,9 @@ fn scan_block_for_eq<'tcx>( .is_none_or(|s| hash != hash_stmt(cx, s)) }) }) - .map_or(block.stmts.len() - start_end_eq, |(i, _)| i); + .map_or(block.stmts.len() - start_end_eq, |(i, stmt)| { + adjust_by_closest_callsite(i, stmt, (0..i).rev().zip(block.stmts[(block.stmts.len() - i)..].iter())) + }); let moved_locals_at_start = moved_locals.len(); let mut i = end_search_start; @@ -522,6 +526,49 @@ fn scan_block_for_eq<'tcx>( } } +/// Adjusts the index for which the statements begin to differ to the closest macro callsite. This +/// avoids giving suggestions that requires splitting a macro call in half, when only a part of the +/// macro expansion is equal. +/// +/// For example, for the following macro: +/// ```rust,ignore +/// macro_rules! foo { +/// ($x:expr) => { +/// let y = 42; +/// $x; +/// }; +/// } +/// ``` +/// If the macro is called like this: +/// ```rust,ignore +/// if false { +/// let z = 42; +/// foo!(println!("Hello")); +/// } else { +/// let z = 42; +/// foo!(println!("World")); +/// } +/// ``` +/// Although the expanded `let y = 42;` is equal, the macro call should not be included in the +/// suggestion. +fn adjust_by_closest_callsite<'tcx>( + i: usize, + stmt: &'tcx Stmt<'tcx>, + mut iter: impl Iterator<Item = (usize, &'tcx Stmt<'tcx>)>, +) -> usize { + let Some((_, first)) = iter.next() else { + return 0; + }; + + // If it is already at the boundary of a macro call, then just return. + if first.span.source_callsite() != stmt.span.source_callsite() { + return i; + } + + iter.find(|(_, stmt)| stmt.span.source_callsite() != first.span.source_callsite()) + .map_or(0, |(i, _)| i + 1) +} + fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbol)], if_expr: &Expr<'_>) -> bool { get_enclosing_block(cx, if_expr.hir_id).is_some_and(|block| { let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs index b439069..695b25a 100644 --- a/src/tools/clippy/clippy_lints/src/create_dir.rs +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -34,10 +33,12 @@ impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Call(func, [arg]) = expr.kind + if let ExprKind::Call(func, [_]) = expr.kind && let ExprKind::Path(ref path) = func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id) + && let QPath::Resolved(_, path) = path + && let Some(last) = path.segments.last() { span_lint_and_then( cx, @@ -45,15 +46,15 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "calling `std::fs::create_dir` where there may be a better way", |diag| { - let mut app = Applicability::MaybeIncorrect; - diag.span_suggestion_verbose( - expr.span, + let mut suggestions = vec![(last.ident.span.shrink_to_hi(), "_all".to_owned())]; + if path.segments.len() == 1 { + suggestions.push((path.span.shrink_to_lo(), "std::fs::".to_owned())); + } + + diag.multipart_suggestion_verbose( "consider calling `std::fs::create_dir_all` instead", - format!( - "create_dir_all({})", - snippet_with_applicability(cx, arg.span, "..", &mut app) - ), - app, + suggestions, + Applicability::MaybeIncorrect, ); }, );
diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs deleted file mode 100644 index 7bae04a..0000000 --- a/src/tools/clippy/clippy_lints/src/ctfe.rs +++ /dev/null
@@ -1,26 +0,0 @@ -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, FnDecl}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::Span; - -declare_lint_pass! { - /// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes). - /// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran. - ClippyCtfe => [] -} - -impl<'tcx> LateLintPass<'tcx> for ClippyCtfe { - fn check_fn( - &mut self, - cx: &LateContext<'_>, - _: FnKind<'tcx>, - _: &'tcx FnDecl<'tcx>, - _: &'tcx Body<'tcx>, - _: Span, - defid: LocalDefId, - ) { - cx.tcx.ensure_ok().mir_drops_elaborated_and_const_checked(defid); // Lint - } -}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 5fcb851..1e3907d 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -77,6 +77,7 @@ crate::cfg_not_test::CFG_NOT_TEST_INFO, crate::checked_conversions::CHECKED_CONVERSIONS_INFO, crate::cloned_ref_to_slice_refs::CLONED_REF_TO_SLICE_REFS_INFO, + crate::coerce_container_to_any::COERCE_CONTAINER_TO_ANY_INFO, crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO, crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO, crate::collapsible_if::COLLAPSIBLE_IF_INFO, @@ -119,6 +120,7 @@ crate::doc::DOC_MARKDOWN_INFO, crate::doc::DOC_NESTED_REFDEFS_INFO, crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO, + crate::doc::DOC_SUSPICIOUS_FOOTNOTES_INFO, crate::doc::EMPTY_DOCS_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, crate::doc::MISSING_PANICS_DOC_INFO, @@ -166,6 +168,7 @@ crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO, crate::format::USELESS_FORMAT_INFO, crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO, + crate::format_args::POINTER_FORMAT_INFO, crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO, crate::format_args::UNINLINED_FORMAT_ARGS_INFO, crate::format_args::UNNECESSARY_DEBUG_FORMATTING_INFO, @@ -211,6 +214,7 @@ crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO, + crate::infallible_try_from::INFALLIBLE_TRY_FROM_INFO, crate::infinite_iter::INFINITE_ITER_INFO, crate::infinite_iter::MAYBE_INFINITE_ITER_INFO, crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO, @@ -379,6 +383,7 @@ crate::methods::INSPECT_FOR_EACH_INFO, crate::methods::INTO_ITER_ON_REF_INFO, crate::methods::IO_OTHER_ERROR_INFO, + crate::methods::IP_CONSTANT_INFO, crate::methods::IS_DIGIT_ASCII_RADIX_INFO, crate::methods::ITERATOR_STEP_BY_ZERO_INFO, crate::methods::ITER_CLONED_COLLECT_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 886c325b..a48e4d2 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,10 +1,9 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro}; +use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_expr_default, is_from_proc_macro}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -129,7 +128,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { // only take bindings to identifiers && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind // only when assigning `... = Default::default()` - && is_expr_default(expr, cx) + && is_expr_default(cx, expr) && let binding_type = cx.typeck_results().node_type(binding_id) && let ty::Adt(adt, args) = *binding_type.kind() && adt.is_struct() @@ -251,19 +250,6 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { } } -/// Checks if the given expression is the `default` method belonging to the `Default` trait. -fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool { - if let ExprKind::Call(fn_expr, []) = &expr.kind - && let ExprKind::Path(qpath) = &fn_expr.kind - && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) - { - // right hand side of assignment is `Default::default` - cx.tcx.is_diagnostic_item(sym::default_fn, def_id) - } else { - false - } -} - /// Returns the reassigned field and the assigning expression (right-hand side of assign). fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> { if let StmtKind::Semi(later_expr) = this.kind
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index cde9528..7463d7b 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -972,7 +972,7 @@ fn report<'tcx>( "&" }; - let expr_str = if !expr_is_macro_call && is_ufcs && expr.precedence() < ExprPrecedence::Prefix { + let expr_str = if !expr_is_macro_call && is_ufcs && cx.precedence(expr) < ExprPrecedence::Prefix { Cow::Owned(format!("({expr_str})")) } else { expr_str @@ -1015,10 +1015,10 @@ fn report<'tcx>( Node::Expr(e) => match e.kind { ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => false, ExprKind::Call(..) => { - expr.precedence() < ExprPrecedence::Unambiguous + cx.precedence(expr) < ExprPrecedence::Unambiguous || matches!(expr.kind, ExprKind::Field(..)) }, - _ => expr.precedence() < e.precedence(), + _ => cx.precedence(expr) < cx.precedence(e), }, _ => false, }; @@ -1066,7 +1066,7 @@ fn report<'tcx>( Mutability::Not => "&", Mutability::Mut => "&mut ", }; - (prefix, expr.precedence() < ExprPrecedence::Prefix) + (prefix, cx.precedence(expr) < ExprPrecedence::Prefix) }, None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", false), _ => ("", false), @@ -1172,7 +1172,7 @@ fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: H }, Some(parent) if !parent.span.from_expansion() => { // Double reference might be needed at this point. - if parent.precedence() == ExprPrecedence::Unambiguous { + if cx.precedence(parent) == ExprPrecedence::Unambiguous { // Parentheses would be needed here, don't lint. *outer_pat = None; } else {
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index f55b0cf..566aa12 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test; +use clippy_utils::{is_from_proc_macro, is_in_test}; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -43,8 +43,10 @@ pub fn new(conf: &'static Conf) -> Self { impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if let PatKind::Binding(.., ident, _) = pat.kind + && !ident.span.from_expansion() && self.disallow.contains(&ident.name) && !is_in_test(cx.tcx, pat.hir_id) + && !is_from_proc_macro(cx, &ident) { span_lint( cx,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 821bb25..7875cdd 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -105,10 +105,10 @@ pub fn def_kind_predicate(def_kind: DefKind) -> bool { impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind { - if let Some(res) = path.res.type_ns { - self.check_res_emit(cx, &res, item.span); - } + if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind + && let Some(res) = path.res.type_ns + { + self.check_res_emit(cx, &res, item.span); } }
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 new file mode 100644 index 0000000..289b6b9 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
@@ -0,0 +1,113 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::token::CommentKind; +use rustc_errors::Applicability; +use rustc_hir::{AttrStyle, Attribute}; +use rustc_lint::{LateContext, LintContext}; +use rustc_resolve::rustdoc::DocFragmentKind; + +use std::ops::Range; + +use super::{DOC_SUSPICIOUS_FOOTNOTES, Fragments}; + +pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &Fragments<'_>, attrs: &[Attribute]) { + for i in doc[range.clone()] + .bytes() + .enumerate() + .filter_map(|(i, c)| if c == b'[' { Some(i) } else { None }) + { + let start = i + range.start; + if doc.as_bytes().get(start + 1) == Some(&b'^') + && let Some(end) = all_numbers_upto_brace(doc, start + 2) + && doc.as_bytes().get(end) != Some(&b':') + && doc.as_bytes().get(start - 1) != Some(&b'\\') + && let Some(this_fragment) = { + // the `doc` string contains all fragments concatenated together + // figure out which one this suspicious footnote comes from + let mut starting_position = 0; + let mut found_fragment = fragments.fragments.last(); + for fragment in fragments.fragments { + if start >= starting_position && start < starting_position + fragment.doc.as_str().len() { + found_fragment = Some(fragment); + break; + } + starting_position += fragment.doc.as_str().len(); + } + found_fragment + } + { + let span = fragments.span(cx, start..end).unwrap_or(this_fragment.span); + span_lint_and_then( + cx, + DOC_SUSPICIOUS_FOOTNOTES, + span, + "looks like a footnote ref, but has no matching footnote", + |diag| { + if this_fragment.kind == DocFragmentKind::SugaredDoc { + let (doc_attr, (_, doc_attr_comment_kind)) = attrs + .iter() + .filter(|attr| attr.span().overlaps(this_fragment.span)) + .rev() + .find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?))) + .unwrap(); + let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) { + (CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""), + (CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""), + (CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"), + (CommentKind::Block, AttrStyle::Inner) => ("\n/*! ", " */"), + }; + diag.span_suggestion_verbose( + doc_attr.span().shrink_to_hi(), + "add footnote definition", + format!( + "{to_add}{label}: <!-- description -->{terminator}", + label = &doc[start..end] + ), + Applicability::HasPlaceholders, + ); + } else { + let is_file_include = cx + .sess() + .source_map() + .span_to_snippet(this_fragment.span) + .as_ref() + .map(|vdoc| vdoc.trim()) + == Ok(doc); + if is_file_include { + // if this is a file include, then there's no quote marks + diag.span_suggestion_verbose( + this_fragment.span.shrink_to_hi(), + "add footnote definition", + format!("\n\n{label}: <!-- description -->", label = &doc[start..end],), + Applicability::HasPlaceholders, + ); + } else { + // otherwise, we wrap in a string + diag.span_suggestion_verbose( + this_fragment.span, + "add footnote definition", + format!( + "r#\"{doc}\n\n{label}: <!-- description -->\"#", + doc = this_fragment.doc, + label = &doc[start..end], + ), + Applicability::HasPlaceholders, + ); + } + } + }, + ); + } + } +} + +fn all_numbers_upto_brace(text: &str, i: usize) -> Option<usize> { + for (j, c) in text.as_bytes()[i..].iter().copied().enumerate().take(64) { + if c == b']' && j != 0 { + return Some(i + j + 1); + } + if !c.is_ascii_digit() || j >= 64 { + break; + } + } + None +}
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index c46dd09..e0fc2fd 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -25,6 +25,7 @@ use url::Url; mod doc_comment_double_space_linebreaks; +mod doc_suspicious_footnotes; mod include_in_doc_without_cfg; mod lazy_continuation; mod link_with_quotes; @@ -607,6 +608,37 @@ "double-space used for doc comment linebreak instead of `\\`" } +declare_clippy_lint! { + /// ### What it does + /// Detects syntax that looks like a footnote reference. + /// + /// Rustdoc footnotes are compatible with GitHub-Flavored Markdown (GFM). + /// GFM does not parse a footnote reference unless its definition also + /// exists. This lint checks for footnote references with missing + /// definitions, unless it thinks you're writing a regex. + /// + /// ### Why is this bad? + /// This probably means that a footnote was meant to exist, + /// but was not written. + /// + /// ### Example + /// ```no_run + /// /// This is not a footnote[^1], because no definition exists. + /// fn my_fn() {} + /// ``` + /// Use instead: + /// ```no_run + /// /// This is a footnote[^1]. + /// /// + /// /// [^1]: defined here + /// fn my_fn() {} + /// ``` + #[clippy::version = "1.88.0"] + pub DOC_SUSPICIOUS_FOOTNOTES, + suspicious, + "looks like a link or footnote ref, but with no definition" +} + pub struct Documentation { valid_idents: FxHashSet<String>, check_private_items: bool, @@ -638,7 +670,8 @@ pub fn new(conf: &'static Conf) -> Self { DOC_OVERINDENTED_LIST_ITEMS, TOO_LONG_FIRST_DOC_PARAGRAPH, DOC_INCLUDE_WITHOUT_CFG, - DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS + DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS, + DOC_SUSPICIOUS_FOOTNOTES, ]); impl EarlyLintPass for Documentation { @@ -825,6 +858,7 @@ fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowSt doc: &doc, fragments: &fragments, }, + attrs, )) } @@ -905,6 +939,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize events: Events, doc: &str, fragments: Fragments<'_>, + attrs: &[Attribute], ) -> DocHeaders { // true if a safety header was found let mut headers = DocHeaders::default(); @@ -1148,7 +1183,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize // Don't check the text associated with external URLs continue; } - text_to_check.push((text, range, code_level)); + text_to_check.push((text, range.clone(), code_level)); + doc_suspicious_footnotes::check(cx, doc, range, &fragments, attrs); } } FootnoteReference(_) => {}
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs index a7670ff..75db923 100644 --- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -1,6 +1,6 @@ use crate::Lint; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_lint_allowed; +use clippy_utils::{is_lint_allowed, sym}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Ty; @@ -65,9 +65,9 @@ declare_lint_pass!(EndianBytes => [HOST_ENDIAN_BYTES, LITTLE_ENDIAN_BYTES, BIG_ENDIAN_BYTES]); -const HOST_NAMES: [&str; 2] = ["from_ne_bytes", "to_ne_bytes"]; -const LITTLE_NAMES: [&str; 2] = ["from_le_bytes", "to_le_bytes"]; -const BIG_NAMES: [&str; 2] = ["from_be_bytes", "to_be_bytes"]; +const HOST_NAMES: [Symbol; 2] = [sym::from_ne_bytes, sym::to_ne_bytes]; +const LITTLE_NAMES: [Symbol; 2] = [sym::from_le_bytes, sym::to_le_bytes]; +const BIG_NAMES: [Symbol; 2] = [sym::from_be_bytes, sym::to_be_bytes]; #[derive(Clone, Debug)] enum LintKind { @@ -95,7 +95,7 @@ fn as_lint(&self) -> &'static Lint { } } - fn as_name(&self, prefix: Prefix) -> &str { + fn as_name(&self, prefix: Prefix) -> Symbol { let index = usize::from(prefix == Prefix::To); match self { @@ -133,7 +133,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix let le = LintKind::Little.as_name(prefix); let be = LintKind::Big.as_name(prefix); - let (lint, other_lints) = match name.as_str() { + let (lint, other_lints) = match name { name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]), name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]), name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]),
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index a26e736c..0c39aae 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -1,6 +1,8 @@ +use std::collections::hash_map::Entry; + use arrayvec::ArrayVec; use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{ FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, @@ -9,7 +11,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{implements_trait, is_type_lang_item}; -use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test}; +use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test, trait_ref_of_method}; use itertools::Itertools; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, @@ -22,10 +24,12 @@ use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; -use rustc_middle::ty::{List, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, List, TraitRef, Ty, TyCtxt, Upcast}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition::Edition2021; use rustc_span::{Span, Symbol, sym}; +use rustc_trait_selection::infer::TyCtxtInferExt; +use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext}; declare_clippy_lint! { /// ### What it does @@ -194,12 +198,41 @@ "use of a format specifier that has no effect" } +declare_clippy_lint! { + /// ### What it does + /// Detects [pointer format] as well as `Debug` formatting of raw pointers or function pointers + /// or any types that have a derived `Debug` impl that recursively contains them. + /// + /// ### Why restrict this? + /// The addresses are only useful in very specific contexts, and certain projects may want to keep addresses of + /// certain data structures or functions from prying hacker eyes as an additional line of security. + /// + /// ### Known problems + /// The lint currently only looks through derived `Debug` implementations. Checking whether a manual + /// implementation prints an address is left as an exercise to the next lint implementer. + /// + /// ### Example + /// ```no_run + /// let foo = &0_u32; + /// fn bar() {} + /// println!("{:p}", foo); + /// let _ = format!("{:?}", &(bar as fn())); + /// ``` + /// + /// [pointer format]: https://doc.rust-lang.org/std/fmt/index.html#formatting-traits + #[clippy::version = "1.88.0"] + pub POINTER_FORMAT, + restriction, + "formatting a pointer" +} + impl_lint_pass!(FormatArgs<'_> => [ FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS, UNINLINED_FORMAT_ARGS, UNNECESSARY_DEBUG_FORMATTING, UNUSED_FORMAT_SPECS, + POINTER_FORMAT, ]); #[allow(clippy::struct_field_names)] @@ -208,6 +241,8 @@ pub struct FormatArgs<'tcx> { msrv: Msrv, ignore_mixed: bool, ty_msrv_map: FxHashMap<Ty<'tcx>, Option<RustcVersion>>, + has_derived_debug: FxHashMap<Ty<'tcx>, bool>, + has_pointer_format: FxHashMap<Ty<'tcx>, bool>, } impl<'tcx> FormatArgs<'tcx> { @@ -218,6 +253,8 @@ pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf, format_args: FormatArgsStorag msrv: conf.msrv, ignore_mixed: conf.allow_mixed_uninlined_format_args, ty_msrv_map, + has_derived_debug: FxHashMap::default(), + has_pointer_format: FxHashMap::default(), } } } @@ -228,7 +265,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { && is_format_macro(cx, macro_call.def_id) && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { - let linter = FormatArgsExpr { + let mut linter = FormatArgsExpr { cx, expr, macro_call: ¯o_call, @@ -236,6 +273,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { ignore_mixed: self.ignore_mixed, msrv: &self.msrv, ty_msrv_map: &self.ty_msrv_map, + has_derived_debug: &mut self.has_derived_debug, + has_pointer_format: &mut self.has_pointer_format, }; linter.check_templates(); @@ -255,10 +294,12 @@ struct FormatArgsExpr<'a, 'tcx> { ignore_mixed: bool, msrv: &'a Msrv, ty_msrv_map: &'a FxHashMap<Ty<'tcx>, Option<RustcVersion>>, + has_derived_debug: &'a mut FxHashMap<Ty<'tcx>, bool>, + has_pointer_format: &'a mut FxHashMap<Ty<'tcx>, bool>, } impl<'tcx> FormatArgsExpr<'_, 'tcx> { - fn check_templates(&self) { + fn check_templates(&mut self) { for piece in &self.format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece && let Ok(index) = placeholder.argument.index @@ -279,6 +320,17 @@ fn check_templates(&self) { if placeholder.format_trait == FormatTrait::Debug { let name = self.cx.tcx.item_name(self.macro_call.def_id); self.check_unnecessary_debug_formatting(name, arg_expr); + if let Some(span) = placeholder.span + && self.has_pointer_debug(self.cx.typeck_results().expr_ty(arg_expr), 0) + { + span_lint(self.cx, POINTER_FORMAT, span, "pointer formatting detected"); + } + } + + if placeholder.format_trait == FormatTrait::Pointer + && let Some(span) = placeholder.span + { + span_lint(self.cx, POINTER_FORMAT, span, "pointer formatting detected"); } } } @@ -490,6 +542,16 @@ fn check_unnecessary_debug_formatting(&self, name: Symbol, value: &Expr<'tcx>) { && let ty = cx.typeck_results().expr_ty(value) && self.can_display_format(ty) { + // If the parent function is a method of `Debug`, we don't want to lint + // because it is likely that the user wants to use `Debug` formatting. + let parent_fn = cx.tcx.hir_get_parent_item(value.hir_id); + if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn) + && let Some(trait_def_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::Debug, trait_def_id) + { + return; + } + let snippet = snippet(cx.sess(), value.span, ".."); span_lint_and_then( cx, @@ -559,6 +621,58 @@ fn can_display_format(&self, ty: Ty<'tcx>) -> bool { false } + + fn has_pointer_debug(&mut self, ty: Ty<'tcx>, depth: usize) -> bool { + let cx = self.cx; + let tcx = cx.tcx; + if !tcx.recursion_limit().value_within_limit(depth) { + return false; + } + let depth = depth + 1; + let typing_env = cx.typing_env(); + let ty = tcx.normalize_erasing_regions(typing_env, ty); + match ty.kind() { + ty::RawPtr(..) | ty::FnPtr(..) | ty::FnDef(..) => true, + ty::Ref(_, t, _) | ty::Slice(t) | ty::Array(t, _) => self.has_pointer_debug(*t, depth), + ty::Tuple(ts) => ts.iter().any(|t| self.has_pointer_debug(t, depth)), + ty::Adt(adt, args) => { + match self.has_pointer_format.entry(ty) { + Entry::Occupied(o) => return *o.get(), + Entry::Vacant(v) => v.insert(false), + }; + let derived_debug = if let Some(&known) = self.has_derived_debug.get(&ty) { + known + } else { + let Some(trait_id) = tcx.get_diagnostic_item(sym::Debug) else { + return false; + }; + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let trait_ref = TraitRef::new(tcx, trait_id, [GenericArg::from(ty)]); + let obligation = Obligation { + cause: ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: trait_ref.upcast(tcx), + }; + let selection = SelectionContext::new(&infcx).select(&obligation); + let derived = if let Ok(Some(Selection::UserDefined(data))) = selection { + tcx.has_attr(data.impl_def_id, sym::automatically_derived) + } else { + false + }; + self.has_derived_debug.insert(ty, derived); + derived + }; + let pointer_debug = derived_debug + && adt.all_fields().any(|f| { + self.has_pointer_debug(tcx.normalize_erasing_regions(typing_env, f.ty(tcx, args)), depth) + }); + self.has_pointer_format.insert(ty, pointer_debug); + pointer_debug + }, + _ => false, + } + } } fn make_ty_msrv_map(tcx: TyCtxt<'_>) -> FxHashMap<Ty<'_>, Option<RustcVersion>> {
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index d0d02a3..6051dc9 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -303,7 +303,7 @@ /// to the name of the method, when there is a field's whose name matches that of the method. /// /// ### Why is this bad? - /// It is most likely that such a method is a bug caused by a typo or by copy-pasting. + /// It is most likely that such a method is a bug caused by a typo or by copy-pasting. /// /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index 6444e99..a99118f 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{eq_expr_value, higher}; +use clippy_utils::{eq_expr_value, higher, sym}; use core::ops::ControlFlow; use rustc_errors::Diag; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::edition::Edition::Edition2024; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -94,7 +93,7 @@ fn mutex_lock_call<'tcx>( op_mutex: Option<&'tcx Expr<'_>>, ) -> ControlFlow<&'tcx Expr<'tcx>> { if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind - && path.ident.as_str() == "lock" + && path.ident.name == sym::lock && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() && is_type_diagnostic_item(cx, ty, sym::Mutex) && op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op))
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index 0823ef5..c743501 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -3,7 +3,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::{ - SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, + SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, sym, }; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -11,7 +11,7 @@ use rustc_hir::{AssignOpKind, BinOp, BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -325,7 +325,7 @@ fn check_with_condition<'tcx>( } // Get the variable name - let var_name = ares_path.segments[0].ident.name.as_str(); + let var_name = ares_path.segments[0].ident.name; match cond_num_val.kind { ExprKind::Lit(cond_lit) => { // Check if the constant is zero @@ -337,7 +337,7 @@ fn check_with_condition<'tcx>( } }, ExprKind::Path(QPath::TypeRelative(_, name)) => { - if name.ident.as_str() == "MIN" + if name.ident.name == sym::MIN && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(const_id) && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl @@ -348,7 +348,7 @@ fn check_with_condition<'tcx>( }, ExprKind::Call(func, []) => { if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind - && name.ident.as_str() == "min_value" + && name.ident.name == sym::min_value && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(func_id) && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl @@ -383,7 +383,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp } } -fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) { +fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: Symbol, expr: &Expr<'_>) { span_lint_and_sugg( cx, IMPLICIT_SATURATING_SUB,
diff --git a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs new file mode 100644 index 0000000..b54c289 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
@@ -0,0 +1,76 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; +use rustc_errors::MultiSpan; +use rustc_hir::{AssocItemKind, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// Finds manual impls of `TryFrom` with infallible error types. + /// + /// ### Why is this bad? + /// + /// Infalliable conversions should be implemented via `From` with the blanket conversion. + /// + /// ### Example + /// ```no_run + /// use std::convert::Infallible; + /// struct MyStruct(i16); + /// impl TryFrom<i16> for MyStruct { + /// type Error = Infallible; + /// fn try_from(other: i16) -> Result<Self, Infallible> { + /// Ok(Self(other.into())) + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// struct MyStruct(i16); + /// impl From<i16> for MyStruct { + /// fn from(other: i16) -> Self { + /// Self(other) + /// } + /// } + /// ``` + #[clippy::version = "1.88.0"] + pub INFALLIBLE_TRY_FROM, + suspicious, + "TryFrom with infallible Error type" +} +declare_lint_pass!(InfallibleTryFrom => [INFALLIBLE_TRY_FROM]); + +impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + let ItemKind::Impl(imp) = item.kind else { return }; + let Some(r#trait) = imp.of_trait else { return }; + let Some(trait_def_id) = r#trait.trait_def_id() else { + return; + }; + if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) { + return; + } + for ii in imp.items { + if ii.kind == AssocItemKind::Type { + let ii = cx.tcx.hir_impl_item(ii.id); + if ii.ident.name != sym::Error { + continue; + } + let ii_ty = ii.expect_type(); + let ii_ty_span = ii_ty.span; + let ii_ty = clippy_utils::ty::ty_from_hir_ty(cx, ii_ty); + if !ii_ty.is_inhabited_from(cx.tcx, ii.owner_id.to_def_id(), cx.typing_env()) { + let mut span = MultiSpan::from_span(cx.tcx.def_span(item.owner_id.to_def_id())); + span.push_span_label(ii_ty_span, "infallible error type"); + span_lint( + cx, + INFALLIBLE_TRY_FROM, + span, + "infallible TryFrom impl; consider implementing From, instead", + ); + } + } + } + } +}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 92eb3d7..be9142b 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -55,6 +55,7 @@ extern crate rustc_span; extern crate rustc_target; extern crate rustc_trait_selection; +extern crate smallvec; extern crate thin_vec; #[macro_use] @@ -65,11 +66,10 @@ mod utils; -pub mod ctfe; // Very important lint, do not remove (rust#125116) pub mod declared_lints; pub mod deprecated_lints; -// begin lints modules, do not remove this comment, it’s used in `update_lints` +// begin lints modules, do not remove this comment, it's used in `update_lints` mod absolute_paths; mod almost_complete_range; mod approx_const; @@ -95,6 +95,7 @@ mod cfg_not_test; mod checked_conversions; mod cloned_ref_to_slice_refs; +mod coerce_container_to_any; mod cognitive_complexity; mod collapsible_if; mod collection_is_never_read; @@ -169,6 +170,7 @@ mod index_refutable_slice; mod indexing_slicing; mod ineffective_open_options; +mod infallible_try_from; mod infinite_iter; mod inherent_impl; mod inherent_to_string; @@ -404,7 +406,7 @@ mod zero_repeat_side_effects; mod zero_sized_map_values; mod zombie_processes; -// end lints modules, do not remove this comment, it’s used in `update_lints` +// end lints modules, do not remove this comment, it's used in `update_lints` use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; @@ -583,8 +585,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let attrs = attr_storage.clone(); store.register_early_pass(move || Box::new(AttrCollector::new(attrs.clone()))); - store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe)); - store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); @@ -946,5 +946,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap)); store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix)); store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf))); + store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom)); + store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny)); // add lints here, do not remove this comment, it's used in `new_lint` }
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index 81f14b7..ddb8bb5 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -2,8 +2,9 @@ use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::visitors::is_local_used; -use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt}; +use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, Pat, PatKind}; @@ -39,13 +40,20 @@ pub(super) fn check<'tcx>( && msrv.meets(cx, msrvs::ITER_FLATTEN) && !is_refutable(cx, inner_pat) { + if arg.span.from_expansion() || if_then.span.from_expansion() { + return; + } let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message - let mut applicability = Applicability::MaybeIncorrect; + let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability); let copied = match cx.typeck_results().expr_ty(let_expr).kind() { ty::Ref(_, inner, _) => match inner.kind() { @@ -55,20 +63,26 @@ pub(super) fn check<'tcx>( _ => "", }; - let sugg = format!("{arg_snippet}{copied}.flatten()"); + let help_msg = "try `.flatten()` and remove the `if let` statement in the for loop"; - // If suggestion is not a one-liner, it won't be shown inline within the error message. In that - // case, it will be shown in the extra `help` message at the end, which is why the first - // `help_msg` needs to refer to the correct relative position of the suggestion. - let help_msg = if sugg.contains('\n') { - "remove the `if let` statement in the for loop and then..." - } else { - "...and remove the `if let` statement in the for loop" - }; + let pat_snippet = + snippet_with_applicability(cx, inner_pat.span.source_callsite(), "_", &mut applicability).to_string(); + let body_snippet = + snippet_with_applicability(cx, if_then.span.source_callsite(), "[body]", &mut applicability).to_string(); + let suggestions = vec![ + // flatten the iterator + (arg.span, format!("{arg_snippet}{copied}.flatten()")), + (pat.span, pat_snippet), + // remove the `if let` statement + ( + body.span, + reindent_multiline(&body_snippet, true, indent_of(cx, body.span)), + ), + ]; span_lint_and_then(cx, MANUAL_FLATTEN, span, msg, |diag| { - diag.span_suggestion(arg.span, "try", sugg, applicability); diag.span_help(inner_expr.span, help_msg); + diag.multipart_suggestion("try", suggestions, applicability); }); } }
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index 12719c4..d66771a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>( if !prefix.is_empty() && ( // Precedence of internal expression is less than or equal to precedence of `&expr`. - arg_expression.precedence() <= ExprPrecedence::Prefix || is_range_literal(arg_expression) + cx.precedence(arg_expression) <= ExprPrecedence::Prefix || is_range_literal(arg_expression) ) { arg_snip = format!("({arg_snip})").into();
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 02afe9f..42fe386 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -8,7 +8,7 @@ use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::{ MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, - peel_blocks, peel_blocks_with_stmt, + peel_blocks, peel_blocks_with_stmt, sym, }; use itertools::Itertools; use rustc_errors::{Applicability, Diag}; @@ -18,7 +18,6 @@ use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; use rustc_span::Span; -use rustc_span::symbol::sym; use std::cmp::Ordering; use std::ops::Deref; @@ -299,9 +298,9 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord)) { let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); - let (min, max) = match (seg_first.ident.as_str(), seg_second.ident.as_str()) { - ("min", "max") => (arg_second, arg_first), - ("max", "min") => (arg_first, arg_second), + let (min, max) = match (seg_first.ident.name, seg_second.ident.name) { + (sym::min, sym::max) => (arg_second, arg_first), + (sym::max, sym::min) => (arg_first, arg_second), _ => return None, }; Some(ClampSuggestion {
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index 73ee1c3..9b590e0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sym; use rustc_ast::LitKind; use rustc_errors::Applicability::MachineApplicable; use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -89,9 +90,10 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) { /// Tries to parse an expression as a method call, emitting the warning if necessary. fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) { - let ident = path_segment.ident.as_str(); let method_arg_kind = &receiver.kind; - if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) { + if matches!(path_segment.ident.name, sym::to_string | sym::to_owned | sym::into) + && is_expr_kind_empty_str(method_arg_kind) + { warn_then_suggest(cx, span); } else if let ExprKind::Call(func, [arg]) = method_arg_kind { // If our first argument is a function call itself, it could be an `unwrap`-like function.
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs index 2a5fc8b..e0cb5d1 100644 --- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{higher, is_res_lang_ctor}; +use clippy_utils::{higher, is_res_lang_ctor, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -57,7 +56,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result<T,E>.ok(, _) && let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind //get operation - && ok_path.ident.as_str() == "ok" + && ok_path.ident.name == sym::ok && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome) && let ctxt = expr.span.ctxt()
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index d090573..dbae71b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -117,7 +117,7 @@ pub(super) fn check_with<'tcx, F>( // it's being passed by value. let scrutinee = peel_hir_expr_refs(scrutinee).0; let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); - let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence() < ExprPrecedence::Unambiguous { + let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && cx.precedence(scrutinee) < ExprPrecedence::Unambiguous { format!("({scrutinee_str})") } else { scrutinee_str.into()
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs index adda358..6a76c6c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::HirNode; use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_context}; -use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; +use clippy_utils::{is_refutable, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind}; use rustc_lint::LateContext; @@ -9,6 +9,7 @@ use super::MATCH_SINGLE_BINDING; +#[derive(Debug)] enum AssignmentExpr { Assign { span: Span, match_span: Span }, Local { span: Span, pat_span: Span }, @@ -160,6 +161,17 @@ fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<Ass None } +fn expr_parent_requires_curlies<'a>(cx: &LateContext<'a>, match_expr: &Expr<'a>) -> bool { + let parent = cx.tcx.parent_hir_node(match_expr.hir_id); + matches!( + parent, + Node::Expr(Expr { + kind: ExprKind::Closure { .. }, + .. + }) | Node::AnonConst(..) + ) +} + fn sugg_with_curlies<'a>( cx: &LateContext<'a>, (ex, match_expr): (&Expr<'a>, &Expr<'a>), @@ -172,9 +184,7 @@ fn sugg_with_curlies<'a>( let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0)); let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new()); - if let Some(parent_expr) = get_parent_expr(cx, match_expr) - && let ExprKind::Closure { .. } = parent_expr.kind - { + if expr_parent_requires_curlies(cx, match_expr) { cbrace_end = format!("\n{indent}}}"); // Fix body indent due to the closure indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 65b93a0..8b4c170 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -1,6 +1,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sym; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -42,7 +43,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> { type Result = ControlFlow<CaseMethod>; fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result { if let ExprKind::MethodCall(segment, receiver, [], _) = ex.kind { - let result = self.case_altered(segment.ident.as_str(), receiver); + let result = self.case_altered(segment.ident.name, receiver); if result.is_break() { return result; } @@ -53,7 +54,7 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result { } impl MatchExprVisitor<'_, '_> { - fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { + fn case_altered(&mut self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { if let Some(case_method) = get_case_method(segment_ident) { let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); @@ -66,12 +67,12 @@ fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> ControlF } } -fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> { - match segment_ident_str { - "to_lowercase" => Some(CaseMethod::LowerCase), - "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase), - "to_uppercase" => Some(CaseMethod::UpperCase), - "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase), +fn get_case_method(segment_ident: Symbol) -> Option<CaseMethod> { + match segment_ident { + sym::to_lowercase => Some(CaseMethod::LowerCase), + sym::to_ascii_lowercase => Some(CaseMethod::AsciiLowerCase), + sym::to_uppercase => Some(CaseMethod::UpperCase), + sym::to_ascii_uppercase => Some(CaseMethod::AsciiUppercase), _ => None, } }
diff --git a/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs b/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs new file mode 100644 index 0000000..83803fb --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs
@@ -0,0 +1,52 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, QPath, Ty, TyKind}; +use rustc_lint::LateContext; +use rustc_span::sym; +use smallvec::SmallVec; + +use super::IP_CONSTANT; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>]) { + if let ExprKind::Path(QPath::TypeRelative( + Ty { + kind: TyKind::Path(QPath::Resolved(_, func_path)), + .. + }, + p, + )) = func.kind + && p.ident.name == sym::new + && let Some(func_def_id) = func_path.res.opt_def_id() + && matches!( + cx.tcx.get_diagnostic_name(func_def_id), + Some(sym::Ipv4Addr | sym::Ipv6Addr) + ) + && let Some(args) = args + .iter() + .map(|arg| { + if let Some(Constant::Int(constant @ (0 | 1 | 127 | 255))) = ConstEvalCtxt::new(cx).eval(arg) { + u8::try_from(constant).ok() + } else { + None + } + }) + .collect::<Option<SmallVec<[u8; 8]>>>() + { + let constant_name = match args.as_slice() { + [0, 0, 0, 0] | [0, 0, 0, 0, 0, 0, 0, 0] => "UNSPECIFIED", + [127, 0, 0, 1] | [0, 0, 0, 0, 0, 0, 0, 1] => "LOCALHOST", + [255, 255, 255, 255] => "BROADCAST", + _ => return, + }; + + span_lint_and_then(cx, IP_CONSTANT, expr.span, "hand-coded well-known IP address", |diag| { + diag.span_suggestion_verbose( + expr.span.with_lo(p.ident.span.lo()), + "use", + constant_name, + Applicability::MachineApplicable, + ); + }); + } +}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index c884621..cbb1b45 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>( if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind && let [local_ident] = path.segments - && local_ident.ident.as_str() == bound_ident.as_str() + && local_ident.ident.name == bound_ident.name { span_lint_and_sugg( cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index e2df8ce..c785b23b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -72,9 +72,9 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> { if let hir::ExprKind::Call(func, []) = &expr.kind && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind { - match segment.ident.as_str() { - "max_value" => return Some(MinMax::Max), - "min_value" => return Some(MinMax::Min), + match segment.ident.name { + sym::max_value => return Some(MinMax::Max), + sym::min_value => return Some(MinMax::Min), _ => {}, } }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index bc15920..347960e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -37,6 +37,7 @@ mod inspect_for_each; mod into_iter_on_ref; mod io_other_error; +mod ip_constant; mod is_digit_ascii_radix; mod is_empty; mod iter_cloned_collect; @@ -4528,6 +4529,42 @@ "detect swap with a temporary value" } +declare_clippy_lint! { + /// ### What it does + /// Checks for IP addresses that could be replaced with predefined constants such as + /// `Ipv4Addr::new(127, 0, 0, 1)` instead of using the appropriate constants. + /// + /// ### Why is this bad? + /// Using specific IP addresses like `127.0.0.1` or `::1` is less clear and less maintainable than using the + /// predefined constants `Ipv4Addr::LOCALHOST` or `Ipv6Addr::LOCALHOST`. These constants improve code + /// readability, make the intent explicit, and are less error-prone. + /// + /// ### Example + /// ```no_run + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// // IPv4 loopback + /// let addr_v4 = Ipv4Addr::new(127, 0, 0, 1); + /// + /// // IPv6 loopback + /// let addr_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + /// ``` + /// Use instead: + /// ```no_run + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// // IPv4 loopback + /// let addr_v4 = Ipv4Addr::LOCALHOST; + /// + /// // IPv6 loopback + /// let addr_v6 = Ipv6Addr::LOCALHOST; + /// ``` + #[clippy::version = "1.89.0"] + pub IP_CONSTANT, + pedantic, + "hardcoded localhost IP address" +} + #[expect(clippy::struct_excessive_bools)] pub struct Methods { avoid_breaking_exported_api: bool, @@ -4706,6 +4743,7 @@ pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self { MANUAL_CONTAINS, IO_OTHER_ERROR, SWAP_WITH_TEMPORARY, + IP_CONSTANT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4738,6 +4776,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { useless_nonzero_new_unchecked::check(cx, expr, func, args, self.msrv); io_other_error::check(cx, expr, func, args, self.msrv); swap_with_temporary::check(cx, expr, func, args); + ip_constant::check(cx, expr, func, args); }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span;
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 2b75d6a..0075bf1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -44,11 +44,10 @@ pub(super) fn check<'tcx>( if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { let mut app = Applicability::MachineApplicable; - let name = name.ident.as_str(); let collect_ty = cx.typeck_results().expr_ty(collect_expr); - let sugg: String = match name { - "len" => { + let sugg: String = match name.ident.name { + sym::len => { if let Some(adt) = collect_ty.ty_adt_def() && matches!( cx.tcx.get_diagnostic_name(adt.did()), @@ -60,13 +59,13 @@ pub(super) fn check<'tcx>( return; } }, - "is_empty" + sym::is_empty if is_is_empty_sig(cx, parent.hir_id) && iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) => { "next().is_none()".into() }, - "contains" => { + sym::contains => { if is_contains_sig(cx, parent.hir_id, iter_expr) && let Some(arg) = args.first() {
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index bce314e..fd36802 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -1,14 +1,14 @@ use rustc_data_structures::fx::FxHashMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::paths; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{paths, sym}; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; +use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; @@ -87,23 +87,23 @@ fn get_open_options( _ => Argument::Unknown, }; - match path.ident.as_str() { - "create" => { + match path.ident.name { + sym::create => { options.push((OpenOption::Create, argument_option, span)); }, - "create_new" => { + sym::create_new => { options.push((OpenOption::CreateNew, argument_option, span)); }, - "append" => { + sym::append => { options.push((OpenOption::Append, argument_option, span)); }, - "truncate" => { + sym::truncate => { options.push((OpenOption::Truncate, argument_option, span)); }, - "read" => { + sym::read => { options.push((OpenOption::Read, argument_option, span)); }, - "write" => { + sym::write => { options.push((OpenOption::Write, argument_option, span)); }, _ => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 6935ae1..6f78d6c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -285,9 +285,9 @@ fn parse_iter_usage<'tcx>( let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; - match (name.ident.as_str(), args) { - ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), - ("next_tuple", []) => { + match (name.ident.name, args) { + (sym::next, []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), + (sym::next_tuple, []) => { return if paths::ITERTOOLS_NEXT_TUPLE.matches(cx, did) && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind() && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) @@ -303,7 +303,7 @@ fn parse_iter_usage<'tcx>( None }; }, - ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + (sym::nth | sym::skip, [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) { let span = if name.ident.as_str() == "nth" { e.span
diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs index 4b32ba8..741f38f 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
@@ -47,7 +47,7 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: Node for param in &generics.params { if !param.bounds.is_empty() { - generic_params_with_bounds.insert(param.ident.name.as_str(), param.ident.span); + generic_params_with_bounds.insert(param.ident.as_str(), param.ident.span); } } for clause in &generics.where_clause.predicates { @@ -64,7 +64,7 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: Node }, WherePredicateKind::RegionPredicate(pred) => { if !pred.bounds.is_empty() - && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.name.as_str()) + && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.as_str()) { emit_lint(cx, *bound_span, pred.lifetime.ident.span); }
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index 74c8142..442280f 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -64,7 +64,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { { let mut applicability = Applicability::MachineApplicable; let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); - let suggestion = if !from_macro && exp.precedence() < ExprPrecedence::Prefix && !has_enclosing_paren(&snip) { + let suggestion = if !from_macro && cx.precedence(exp) < ExprPrecedence::Prefix && !has_enclosing_paren(&snip) { format!("-({snip})") } else { format!("-{snip}")
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 9386519..04b0927 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -293,7 +293,14 @@ fn self_cmp_call<'tcx>( ExprKind::Call(path, [_, _]) => path_res(cx, path) .opt_def_id() .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)), - ExprKind::MethodCall(_, _, [_other], ..) => { + ExprKind::MethodCall(_, recv, [_], ..) => { + let ExprKind::Path(path) = recv.kind else { + return false; + }; + if last_path_segment(&path).ident.name != kw::SelfLower { + return false; + } + // We can set this to true here no matter what as if it's a `MethodCall` and goes to the // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp` *needs_fully_qualified = true;
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs index 35caac8..4ce6827 100644 --- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -1,14 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::path_to_local_id; use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{path_to_local_id, sym}; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -177,7 +177,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) - && name.ident.as_str() == "push" + && name.ident.name == sym::push { searcher.err_span = searcher.err_span.to(stmt.span); searcher.arg = Some(*arg_expr);
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 9149406..94cdcf0 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -2,7 +2,7 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::visitors::contains_unsafe_block; -use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core}; +use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core, sym}; use hir::LifetimeKind; use rustc_abi::ExternAbi; use rustc_errors::{Applicability, MultiSpan}; @@ -18,8 +18,8 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::{fmt, iter}; @@ -268,6 +268,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_paren(), _ => return check_ptr_eq(cx, expr, op.node, l, r), }; + let invert = if op.node == BinOpKind::Eq { "" } else { "!" }; span_lint_and_sugg( cx, @@ -275,7 +276,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { expr.span, "comparing with null is better expressed by the `.is_null()` method", "try", - format!("{non_null_path_snippet}.is_null()"), + format!("{invert}{non_null_path_snippet}.is_null()",), Applicability::MachineApplicable, ); } @@ -299,7 +300,7 @@ struct PtrArg<'tcx> { emission_id: HirId, span: Span, ty_name: Symbol, - method_renames: &'static [(&'static str, &'static str)], + method_renames: &'static [(Symbol, &'static str)], ref_prefix: RefPrefix, deref_ty: DerefTy<'tcx>, } @@ -385,6 +386,7 @@ fn display<'a>(&'a self, cx: &'a LateContext<'tcx>) -> DerefTyDisplay<'a, 'tcx> } } +#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -409,7 +411,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( - [("clone", ".to_owned()")].as_slice(), + [(sym::clone, ".to_owned()")].as_slice(), DerefTy::Slice( name.args.and_then(|args| args.args.first()).and_then(|arg| { if let GenericArg::Type(ty) = arg { @@ -421,10 +423,14 @@ fn check_fn_args<'cx, 'tcx: 'cx>( args.type_at(0), ), ), - _ if Some(adt.did()) == cx.tcx.lang_items().string() => { - ([("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str) - }, - Some(sym::PathBuf) => ([("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path), + _ if Some(adt.did()) == cx.tcx.lang_items().string() => ( + [(sym::clone, ".to_owned()"), (sym::as_str, "")].as_slice(), + DerefTy::Str, + ), + Some(sym::PathBuf) => ( + [(sym::clone, ".to_path_buf()"), (sym::as_path, "")].as_slice(), + DerefTy::Path, + ), Some(sym::Cow) if mutability == Mutability::Not => { if let Some((lifetime, ty)) = name.args.and_then(|args| { if let [GenericArg::Lifetime(lifetime), ty] = args.args { @@ -595,7 +601,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if let ExprKind::MethodCall(name, receiver, ..) = use_expr.kind && receiver.hir_id == child_id { - let name = name.ident.as_str(); + let name = name.ident.name; // Check if the method can be renamed. if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
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 49b5229..6b1dc86 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
@@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::get_enclosing_block; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; 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; @@ -87,7 +87,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &hir::Block<'tcx>) { diag.span_suggestion( expr.span, "try", - format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), + format!("{}.resize({len}, 0); {}", ident, snippet(cx, expr.span, "..")), applicability, ); }, @@ -106,7 +106,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &hir::Block<'tcx>) { "try", format!( "{}.resize({}, 0); {}", - ident.as_str(), + ident, snippet(cx, e.span, ".."), snippet(cx, expr.span, "..") ), @@ -142,8 +142,8 @@ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { if let ExprKind::MethodCall(path, receiver, args, _) = e.kind { let PathSegment { ident, .. } = *path; - match ident.as_str() { - "read" | "read_exact" => { + match ident.name { + sym::read | sym::read_exact => { let [arg] = args else { return }; if let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind @@ -155,7 +155,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { return; } }, - "resize" => { + sym::resize => { // If the Vec is resized, then it's a valid read if let ExprKind::Path(QPath::Resolved(_, inner_path)) = receiver.kind && let Res::Local(res_id) = inner_path.res
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index 1117dea..324a05c 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -86,7 +86,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); let needs_parens_for_prefix = - parent_expr.is_some_and(|parent| parent.precedence() > ExprPrecedence::Prefix); + parent_expr.is_some_and(|parent| cx.precedence(parent) > ExprPrecedence::Prefix); if expr_ty == indexed_ty { if expr_ref_count > indexed_ref_count {
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs index 152d745..51adbbc 100644 --- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; -use clippy_utils::{is_from_proc_macro, path_to_local_id}; +use clippy_utils::{is_from_proc_macro, path_to_local_id, sym}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind}; @@ -126,7 +126,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) - && name.ident.as_str() == "reserve" + && name.ident.name == sym::reserve && !is_from_proc_macro(cx, expr) { self.searcher = Some(VecReserveSearcher {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index d85f4a8..f6c128d 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -143,7 +143,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { StmtKind::Expr(Expr { kind: ExprKind::Block(block, _), .. - }) if !block.span.from_expansion() => { + }) if !block.span.from_expansion() && stmt.span.contains(block.span) => { let Block { expr: None, stmts: [.., stmt],
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs index a64b9b2..b36a5d6 100644 --- a/src/tools/clippy/clippy_lints/src/serde_api.rs +++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::paths; +use clippy_utils::{paths, sym}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -36,9 +36,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let mut seen_str = None; let mut seen_string = None; for item in *items { - match item.ident.as_str() { - "visit_str" => seen_str = Some(item.span), - "visit_string" => seen_string = Some(item.span), + match item.ident.name { + sym::visit_str => seen_str = Some(item.span), + sym::visit_string => seen_string = Some(item.span), _ => {}, } }
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 3d39386..442b325 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,13 +1,13 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::Msrv; use rustc_attr_data_structures::{StabilityLevel, StableSince}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; -use rustc_hir::{HirId, Path, PathSegment}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_hir::{Block, Body, HirId, Path, PathSegment}; +use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{Span, sym}; @@ -88,24 +88,35 @@ } pub struct StdReexports { - // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen - // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro - // when the path could be also be used to access the module. - prev_span: Span, + lint_point: (Span, Option<LintPoint>), msrv: Msrv, } impl StdReexports { pub fn new(conf: &'static Conf) -> Self { Self { - prev_span: Span::default(), + lint_point: Default::default(), msrv: conf.msrv, } } + + fn lint_if_finish(&mut self, cx: &LateContext<'_>, (span, item): (Span, Option<LintPoint>)) { + if span.source_equal(self.lint_point.0) { + return; + } + + if !self.lint_point.0.is_dummy() { + emit_lints(cx, &self.lint_point); + } + + self.lint_point = (span, item); + } } impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]); +type LintPoint = (&'static Lint, &'static str, &'static str); + impl<'tcx> LateLintPass<'tcx> for StdReexports { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { if let Res::Def(_, def_id) = path.res @@ -119,7 +130,7 @@ fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { - self.prev_span = first_segment.ident.span; + self.lint_if_finish(cx, (first_segment.ident.span, None)); return; }, }, @@ -127,32 +138,44 @@ fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { if cx.tcx.crate_name(def_id.krate) == sym::core { (ALLOC_INSTEAD_OF_CORE, "alloc", "core") } else { - self.prev_span = first_segment.ident.span; + self.lint_if_finish(cx, (first_segment.ident.span, None)); return; } }, _ => return, }; - if first_segment.ident.span != self.prev_span { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - lint, - first_segment.ident.span, - format!("used import from `{used_mod}` instead of `{replace_with}`"), - |diag| { - diag.span_suggestion( - first_segment.ident.span, - format!("consider importing the item from `{replace_with}`"), - replace_with.to_string(), - Applicability::MachineApplicable, - ); - }, - ); - self.prev_span = first_segment.ident.span; - } + + self.lint_if_finish(cx, (first_segment.ident.span, Some((lint, used_mod, replace_with)))); } } + + fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &Block<'tcx>) { + self.lint_if_finish(cx, Default::default()); + } + + fn check_body_post(&mut self, cx: &LateContext<'tcx>, _: &Body<'tcx>) { + self.lint_if_finish(cx, Default::default()); + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + self.lint_if_finish(cx, Default::default()); + } +} + +fn emit_lints(cx: &LateContext<'_>, (span, item): &(Span, Option<LintPoint>)) { + let Some((lint, used_mod, replace_with)) = item else { + return; + }; + + span_lint_and_sugg( + cx, + lint, + *span, + format!("used import from `{used_mod}` instead of `{replace_with}`"), + format!("consider importing the item from `{replace_with}`"), + (*replace_with).to_string(), + Applicability::MachineApplicable, + ); } /// Returns the first named segment of a [`Path`].
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 73a9fe7..1cda6f5 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -560,7 +560,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id) && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id) && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind - && let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str() + && let trim_fn_name @ (sym::trim | sym::trim_start | sym::trim_end) = path.ident.name && let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id) && is_one_of_trim_diagnostic_items(cx, trim_def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index e3ecd65..5ecbb56 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core}; +use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, path_to_local, std_or_core}; use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; @@ -350,12 +350,21 @@ fn snippet_index_binding(&mut self, expr: &'tcx Expr<'tcx>) -> String { format!("{lhs_snippet}{rhs_snippet}") }, ExprKind::Path(QPath::Resolved(_, path)) => { - let init = self.cx.expr_or_init(expr); - let Some(first_segment) = path.segments.first() else { return String::new(); }; - if !self.suggest_span.contains(init.span) || !self.is_used_other_than_swapping(first_segment.ident) { + + let init = self.cx.expr_or_init(expr); + + // We skip suggesting a variable binding in any of these cases: + // - Variable initialization is outside the suggestion span + // - Variable declaration is outside the suggestion span + // - Variable is not used as an index or elsewhere later + if !self.suggest_span.contains(init.span) + || path_to_local(expr) + .is_some_and(|hir_id| !self.suggest_span.contains(self.cx.tcx.hir_span(hir_id))) + || !self.is_used_other_than_swapping(first_segment.ident) + { return String::new(); }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs index 96286fcf7..08f36a2 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -74,7 +74,7 @@ pub(super) fn check<'tcx>( last.ident.span.with_hi(path.span.hi()), "transmute used without annotations", "consider adding missing annotations", - format!("{}::<{from_ty}, {to_ty}>", last.ident.as_str()), + format!("{}::<{from_ty}, {to_ty}>", last.ident), Applicability::MaybeIncorrect, ); true
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 0d5cf45..18897fb 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( }; if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id) - && parent.precedence() > ExprPrecedence::Cast + && cx.precedence(parent) > ExprPrecedence::Cast { sugg = format!("({sugg})"); }
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index 004ad03..4b23367 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m let ltopt = if lt.is_anonymous() { String::new() } else { - format!("{} ", lt.ident.as_str()) + format!("{} ", lt.ident) }; if mut_ty.mutbl == Mutability::Mut {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index 019ae16..ae6d8a1 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -1,9 +1,14 @@ +use std::iter; + use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::expr_type_is_certain; +use clippy_utils::{is_expr_default, is_from_proc_macro}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; +use rustc_span::SyntaxContext; use super::{UNIT_ARG, utils}; @@ -59,7 +64,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { } } -fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { +fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_recover: &[&'tcx Expr<'tcx>]) { let mut applicability = Applicability::MachineApplicable; let (singular, plural) = if args_to_recover.len() > 1 { ("", "s") @@ -100,34 +105,41 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp let arg_snippets: Vec<_> = args_to_recover .iter() - .filter_map(|arg| arg.span.get_source_text(cx)) + // If the argument is from an expansion and is a `Default::default()`, we skip it + .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg)) + .filter_map(|arg| get_expr_snippet(cx, arg)) .collect(); - let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover + + // If the argument is an empty block or `Default::default()`, we can replace it with `()`. + let arg_snippets_without_redundant_exprs: Vec<_> = args_to_recover .iter() - .filter(|arg| !is_empty_block(arg)) - .filter_map(|arg| arg.span.get_source_text(cx)) + .filter(|arg| !is_expr_default_nested(cx, arg) && (arg.span.from_expansion() || !is_empty_block(arg))) + .filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg)) .collect(); if let Some(call_snippet) = expr.span.get_source_text(cx) { - let sugg = fmt_stmts_and_call( - cx, - expr, - &call_snippet, - &arg_snippets, - &arg_snippets_without_empty_blocks, - ); - - if arg_snippets_without_empty_blocks.is_empty() { + if arg_snippets_without_redundant_exprs.is_empty() + && let suggestions = args_to_recover + .iter() + .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg)) + .map(|arg| (arg.span.parent_callsite().unwrap_or(arg.span), "()".to_string())) + .collect::<Vec<_>>() + && !suggestions.is_empty() + { db.multipart_suggestion( format!("use {singular}unit literal{plural} instead"), - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::<Vec<_>>(), + suggestions, applicability, ); } else { - let plural = arg_snippets_without_empty_blocks.len() > 1; + let plural = arg_snippets_without_redundant_exprs.len() > 1; + let sugg = fmt_stmts_and_call( + cx, + expr, + &call_snippet, + arg_snippets, + arg_snippets_without_redundant_exprs, + ); let empty_or_s = if plural { "s" } else { "" }; let it_or_them = if plural { "them" } else { "it" }; db.span_suggestion( @@ -144,6 +156,55 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp ); } +fn is_expr_default_nested<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + is_expr_default(cx, expr) + || matches!(expr.kind, ExprKind::Block(block, _) + if block.expr.is_some() && is_expr_default_nested(cx, block.expr.unwrap())) +} + +enum MaybeTypeUncertain<'tcx> { + Certain(Sugg<'tcx>), + Uncertain(Sugg<'tcx>), +} + +impl From<MaybeTypeUncertain<'_>> for String { + fn from(value: MaybeTypeUncertain<'_>) -> Self { + match value { + MaybeTypeUncertain::Certain(sugg) => sugg.to_string(), + MaybeTypeUncertain::Uncertain(sugg) => format!("let _: () = {sugg}"), + } + } +} + +fn get_expr_snippet<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<Sugg<'tcx>> { + let mut app = Applicability::MachineApplicable; + let snip = Sugg::hir_with_context(cx, expr, SyntaxContext::root(), "..", &mut app); + if app != Applicability::MachineApplicable { + return None; + } + + Some(snip) +} + +fn get_expr_snippet_with_type_certainty<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, +) -> Option<MaybeTypeUncertain<'tcx>> { + get_expr_snippet(cx, expr).map(|snip| { + // If the type of the expression is certain, we can use it directly. + // Otherwise, we wrap it in a `let _: () = ...` to ensure the type is correct. + if !expr_type_is_certain(cx, expr) && !is_block_with_no_expr(expr) { + MaybeTypeUncertain::Uncertain(snip) + } else { + MaybeTypeUncertain::Certain(snip) + } + }) +} + +fn is_block_with_no_expr(expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::Block(Block { expr: None, .. }, _)) +} + fn is_empty_block(expr: &Expr<'_>) -> bool { matches!( expr.kind, @@ -162,23 +223,20 @@ fn fmt_stmts_and_call( cx: &LateContext<'_>, call_expr: &Expr<'_>, call_snippet: &str, - args_snippets: &[SourceText], - non_empty_block_args_snippets: &[SourceText], + args_snippets: Vec<Sugg<'_>>, + non_empty_block_args_snippets: Vec<MaybeTypeUncertain<'_>>, ) -> String { let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); - let call_snippet_with_replacements = args_snippets - .iter() - .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); + let call_snippet_with_replacements = args_snippets.into_iter().fold(call_snippet.to_owned(), |acc, arg| { + acc.replacen(&arg.to_string(), "()", 1) + }); - let mut stmts_and_call = non_empty_block_args_snippets - .iter() - .map(|it| it.as_ref().to_owned()) - .collect::<Vec<_>>(); - stmts_and_call.push(call_snippet_with_replacements); - stmts_and_call = stmts_and_call + let stmts_and_call = non_empty_block_args_snippets .into_iter() + .map(Into::into) + .chain(iter::once(call_snippet_with_replacements)) .map(|v| reindent_multiline(&v, true, Some(call_expr_indent))) - .collect(); + .collect::<Vec<_>>(); let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); // expr is not in a block statement or result expression position, wrap in a block
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 5e1cb9e..12cc109 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use clippy_utils::{is_res_lang_ctor, paths, peel_blocks}; +use clippy_utils::{is_res_lang_ctor, paths, peel_blocks, sym}; use hir::{ExprKind, HirId, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -232,8 +232,16 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { while let ExprKind::MethodCall(path, receiver, ..) = expr.kind { if matches!( - path.ident.as_str(), - "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or" + path.ident.name, + sym::unwrap + | sym::expect + | sym::unwrap_or + | sym::unwrap_or_else + | sym::ok + | sym::is_ok + | sym::is_err + | sym::or_else + | sym::or ) { expr = receiver; } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs index 958f19d..f5ed10f 100644 --- a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
@@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -36,7 +36,7 @@ impl LateLintPass<'_> for UnusedResultOk { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _) - && ok_path.ident.as_str() == "ok" + && ok_path.ident.name == sym::ok && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) && !stmt.span.in_external_macro(cx.sess().source_map()) {
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 9859ddf..3811f0f 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -100,7 +100,7 @@ fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTrait let segments = &poly.trait_ref.path.segments; if segments.len() == 1 - && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) + && matches!(segments[0].ident.name, sym::Fn | sym::FnMut | sym::FnOnce) && let Some(args) = segments[0].args && args.parenthesized == GenericArgsParentheses::ParenSugar && let constraints = &args.constraints @@ -109,6 +109,7 @@ fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTrait && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind && args.span_ext.hi() != poly.span.hi() && !hir_ty.span.from_expansion() + && args.span_ext.hi() != hir_ty.span.hi() && is_unit_ty(hir_ty) { lint_unneeded_unit_return(cx, hir_ty.span, poly.span);
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 3c23662..8d87353 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -2,7 +2,7 @@ use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, path_to_local_id}; +use clippy_utils::{get_parent_expr, path_to_local_id, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -202,7 +202,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) - && name.ident.as_str() == "push" + && name.ident.name == sym::push { self.searcher = Some(VecPushSearcher { err_span: searcher.err_span.to(stmt.span),
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 467811c..d9dda6e 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -9,8 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::impl_lint_pass; +use rustc_span::BytePos; use rustc_span::symbol::kw; -use rustc_span::{BytePos, sym}; declare_clippy_lint! { /// ### What it does @@ -193,9 +193,7 @@ fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[Pa // Allow "...prelude::..::*" imports. // Many crates have a prelude, and it is imported as a glob by design. fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool { - segments - .iter() - .any(|ps| ps.ident.as_str().contains(sym::prelude.as_str())) + segments.iter().any(|ps| ps.ident.as_str().contains("prelude")) } // Allow "super::*" imports in tests.
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index a8758b6..d9a0076 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -5,8 +5,8 @@ use clippy_utils::{is_in_test, sym}; use rustc_ast::token::LitKind; use rustc_ast::{ - FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, - FormatTrait, + FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatCount, FormatOptions, + FormatPlaceholder, FormatTrait, }; use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; @@ -556,12 +556,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { // Decrement the index of the remaining by the number of replaced positional arguments if !suggestion.is_empty() { for piece in &format_args.template { - if let Some((span, index)) = positional_arg_piece_span(piece) - && suggestion.iter().all(|(s, _)| *s != span) - { - let decrement = replaced_position.iter().filter(|i| **i < index).count(); - suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement)))); - } + relocalize_format_args_indexes(piece, &mut suggestion, &replaced_position); } } @@ -574,7 +569,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { } } -/// Extract Span and its index from the given `piece`, iff it's positional argument. +/// Extract Span and its index from the given `piece`, if it's positional argument. fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { match piece { FormatArgsPiece::Placeholder(FormatPlaceholder { @@ -591,6 +586,57 @@ fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { } } +/// Relocalizes the indexes of positional arguments in the format string +fn relocalize_format_args_indexes( + piece: &FormatArgsPiece, + suggestion: &mut Vec<(Span, String)>, + replaced_position: &[usize], +) { + if let FormatArgsPiece::Placeholder(FormatPlaceholder { + argument: + FormatArgPosition { + index: Ok(index), + // Only consider positional arguments + kind: FormatArgPositionKind::Number, + span: Some(span), + }, + format_options, + .. + }) = piece + { + if suggestion.iter().any(|(s, _)| s.overlaps(*span)) { + // If the span is already in the suggestion, we don't need to process it again + return; + } + + // lambda to get the decremented index based on the replaced positions + let decremented_index = |index: usize| -> usize { + let decrement = replaced_position.iter().filter(|&&i| i < index).count(); + index - decrement + }; + + suggestion.push((*span, decremented_index(*index).to_string())); + + // If there are format options, we need to handle them as well + if *format_options != FormatOptions::default() { + // lambda to process width and precision format counts and add them to the suggestion + let mut process_format_count = |count: &Option<FormatCount>, formatter: &dyn Fn(usize) -> String| { + if let Some(FormatCount::Argument(FormatArgPosition { + index: Ok(format_arg_index), + kind: FormatArgPositionKind::Number, + span: Some(format_arg_span), + })) = count + { + suggestion.push((*format_arg_span, formatter(decremented_index(*format_arg_index)))); + } + }; + + process_format_count(&format_options.width, &|index: usize| format!("{index}$")); + process_format_count(&format_options.precision, &|index: usize| format!(".{index}$")); + } + } +} + /// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw /// /// `r#"a"#` -> (`a`, true)
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs index 09f1084..6ab94a5 100644 --- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs +++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -5,7 +5,7 @@ use rustc_ast::visit::visit_opt; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; @@ -69,8 +69,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { let mut vis = WaitFinder { cx, local_id, + create_id: expr.hir_id, body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id), - state: VisitorState::WalkUpToLocal, + state: VisitorState::WalkUpToCreate, early_return: None, missing_wait_branch: None, }; @@ -131,6 +132,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { struct WaitFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, local_id: HirId, + create_id: HirId, body_id: LocalDefId, state: VisitorState, early_return: Option<Span>, @@ -141,8 +143,8 @@ struct WaitFinder<'a, 'tcx> { #[derive(PartialEq)] enum VisitorState { - WalkUpToLocal, - LocalFound, + WalkUpToCreate, + CreateFound, } #[derive(Copy, Clone)] @@ -155,19 +157,13 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; type Result = ControlFlow<MaybeWait>; - fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { - if self.state == VisitorState::WalkUpToLocal - && let PatKind::Binding(_, pat_id, ..) = l.pat.kind - && self.local_id == pat_id - { - self.state = VisitorState::LocalFound; + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + if ex.hir_id == self.create_id { + self.state = VisitorState::CreateFound; + return Continue(()); } - walk_local(self, l) - } - - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { - if self.state != VisitorState::LocalFound { + if self.state != VisitorState::CreateFound { return walk_expr(self, ex); }
diff --git a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs index 311f76f..7eeec84 100644 --- a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
@@ -45,7 +45,7 @@ pub fn new() -> Self { impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let mut check_next = false; - if let ItemKind::Static(_, ty, Mutability::Not, _) = item.kind { + if let ItemKind::Static(Mutability::Not, _, ty, _) = item.kind { let lines = cx .tcx .hir_attrs(item.hir_id())
diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs index 0edeef3..45a8660 100644 --- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
@@ -105,7 +105,7 @@ pub struct LintWithoutLintPass { impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let hir::ItemKind::Static(ident, ty, Mutability::Not, body_id) = item.kind { + if let hir::ItemKind::Static(Mutability::Not, ident, ty, body_id) = item.kind { if is_lint_ref_type(cx, ty) { check_invalid_clippy_version_attribute(cx, item);
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index efbacbd..1aa16e3 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-05-31 +nightly-2025-06-12 ``` <!-- end autogenerated nightly -->
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index f6ef638..c7a2375 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1793,10 +1793,9 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { /// Checks if the given `DefId` matches the `libc` item. pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool { - let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().is_some_and(|s| *s == sym::libc) && path.last().copied() == Some(name) + cx.tcx.crate_name(did.krate) == sym::libc && cx.tcx.def_path_str(did).ends_with(name.as_str()) } /// Returns the list of condition expressions and the list of blocks in a @@ -3473,3 +3472,15 @@ pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { None } } + +/// Checks if the given expression is a call to `Default::default()`. +pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + if let ExprKind::Call(fn_expr, []) = &expr.kind + && let ExprKind::Path(qpath) = &fn_expr.kind + && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) + { + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) + } else { + false + } +}
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 8e16f94..e629012 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
@@ -18,7 +18,7 @@ }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgKind, Instance, TraitRef, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; @@ -349,7 +349,15 @@ fn check_terminator<'tcx>( } | TerminatorKind::TailCall { func, args, fn_span: _ } => { let fn_ty = func.ty(body, cx.tcx); - if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { + if let ty::FnDef(fn_def_id, fn_substs) = fn_ty.kind() { + // FIXME: when analyzing a function with generic parameters, we may not have enough information to + // resolve to an instance. However, we could check if a host effect predicate can guarantee that + // this can be made a `const` call. + let fn_def_id = match Instance::try_resolve(cx.tcx, cx.typing_env(), *fn_def_id, fn_substs) { + Ok(Some(fn_inst)) => fn_inst.def_id(), + Ok(None) => return Err((span, format!("cannot resolve instance for {func:?}").into())), + Err(_) => return Err((span, format!("error during instance resolution of {func:?}").into())), + }; if !is_stable_const_fn(cx, fn_def_id, msrv) { return Err(( span,
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index f417530..3b58dba 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -76,7 +76,6 @@ macro_rules! generate { Visitor, Weak, abs, - align_of, ambiguous_glob_reexports, append, arg, @@ -84,6 +83,7 @@ macro_rules! generate { as_deref, as_deref_mut, as_mut, + as_path, assert_failed, author, borrow, @@ -121,6 +121,8 @@ macro_rules! generate { copy_to, copy_to_nonoverlapping, count_ones, + create, + create_new, cycle, cyclomatic_complexity, de, @@ -132,7 +134,6 @@ macro_rules! generate { enum_glob_use, enumerate, err, - error, exp, expect_err, expn_data, @@ -150,8 +151,11 @@ macro_rules! generate { floor_char_boundary, fold, for_each, + from_be_bytes, from_bytes_with_nul, from_bytes_with_nul_unchecked, + from_le_bytes, + from_ne_bytes, from_ptr, from_raw, from_ref, @@ -184,8 +188,10 @@ macro_rules! generate { is_err, is_file, is_none, + is_none_or, is_ok, is_some, + is_some_and, isqrt, itertools, join, @@ -252,9 +258,12 @@ macro_rules! generate { powi, product, push, + read, + read_exact, read_line, read_to_end, read_to_string, + read_unaligned, redundant_pub_crate, regex, rem_euclid, @@ -323,16 +332,22 @@ macro_rules! generate { then_some, to_ascii_lowercase, to_ascii_uppercase, + to_be_bytes, to_digit, + to_le_bytes, to_lowercase, + to_ne_bytes, to_os_string, to_owned, to_path_buf, to_uppercase, tokio, trim, + trim_end, trim_end_matches, + trim_start, trim_start_matches, + truncate, unreachable_pub, unsafe_removed_from_name, unused, @@ -347,12 +362,15 @@ macro_rules! generate { unwrap_unchecked, unzip, utils, + visit_str, + visit_string, wake, warnings, wildcard_imports, with_capacity, wrapping_offset, write, + write_unaligned, writeln, zip, }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 61e70b3..32a992c 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -20,7 +20,7 @@ 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, TypeFoldable, TypeSuperVisitable, + GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; @@ -853,7 +853,7 @@ fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result { ControlFlow::Continue(()) } } - fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result { + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; @@ -1137,21 +1137,38 @@ pub fn without_pointers(tcx: TyCtxt<'tcx>, ignore_interior_mutability: &[String] /// Check if given type has interior mutability such as [`std::cell::Cell`] or /// [`std::cell::RefCell`] etc. and if it does, returns a chain of types that causes - /// this type to be interior mutable + /// this type to be interior mutable. False negatives may be expected for infinitely recursive + /// types, and `None` will be returned there. pub fn interior_mut_ty_chain(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx ty::List<Ty<'tcx>>> { + self.interior_mut_ty_chain_inner(cx, ty, 0) + } + + fn interior_mut_ty_chain_inner( + &mut self, + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + depth: usize, + ) -> Option<&'tcx ty::List<Ty<'tcx>>> { + if !cx.tcx.recursion_limit().value_within_limit(depth) { + return None; + } + match self.tys.entry(ty) { Entry::Occupied(o) => return *o.get(), // Temporarily insert a `None` to break cycles Entry::Vacant(v) => v.insert(None), }; + let depth = depth + 1; let chain = match *ty.kind() { - ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain(cx, inner_ty), - ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain(cx, inner_ty), + ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain_inner(cx, inner_ty, depth), + ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain_inner(cx, inner_ty, depth), ty::Array(inner_ty, size) if size.try_to_target_usize(cx.tcx) != Some(0) => { - self.interior_mut_ty_chain(cx, inner_ty) + self.interior_mut_ty_chain_inner(cx, inner_ty, depth) }, - ty::Tuple(fields) => fields.iter().find_map(|ty| self.interior_mut_ty_chain(cx, ty)), + ty::Tuple(fields) => fields + .iter() + .find_map(|ty| self.interior_mut_ty_chain_inner(cx, ty, depth)), ty::Adt(def, _) if def.is_unsafe_cell() => Some(ty::List::empty()), ty::Adt(def, args) => { let is_std_collection = matches!( @@ -1171,16 +1188,17 @@ pub fn interior_mut_ty_chain(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> if is_std_collection || def.is_box() { // Include the types from std collections that are behind pointers internally - args.types().find_map(|ty| self.interior_mut_ty_chain(cx, ty)) + args.types() + .find_map(|ty| self.interior_mut_ty_chain_inner(cx, ty, depth)) } else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() { None } else { def.all_fields() - .find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args))) + .find_map(|f| self.interior_mut_ty_chain_inner(cx, f.ty(cx.tcx, args), depth)) } }, ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { - Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain(cx, normalized_ty), + Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain_inner(cx, normalized_ty, depth), _ => None, }, _ => None, @@ -1342,7 +1360,8 @@ fn has_non_owning_mutable_access_inner<'tcx>( mutability.is_mut() || !pointee_ty.is_freeze(cx.tcx, cx.typing_env()) }, ty::Closure(_, closure_args) => { - matches!(closure_args.types().next_back(), Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures)) + matches!(closure_args.types().next_back(), + Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures)) }, ty::Tuple(tuple_args) => tuple_args .iter()
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index b6817d9..3fc5a12 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-05-31" +channel = "nightly-2025-06-12" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal"
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 78b27e2..99a0125 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs
@@ -273,10 +273,10 @@ fn run_ui_cargo(cx: &TestContext) { config.program.input_file_flag = CommandBuilder::cargo().input_file_flag; config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag; config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()]; - config - .program - .envs - .push(("RUSTFLAGS".into(), Some("-Dwarnings".into()))); + config.program.envs.extend([ + ("RUSTFLAGS".into(), Some("-Dwarnings".into())), + ("CARGO_INCREMENTAL".into(), Some("0".into())), + ]); // We need to do this while we still have a rustc in the `program` field. config.fill_host_and_target().unwrap(); config.program.program.set_file_name(if cfg!(windows) {
diff --git a/src/tools/clippy/tests/symbols-used.rs b/src/tools/clippy/tests/symbols-used.rs new file mode 100644 index 0000000..bc04567 --- /dev/null +++ b/src/tools/clippy/tests/symbols-used.rs
@@ -0,0 +1,81 @@ +// This test checks that all symbols defined in Clippy's `sym.rs` file +// are used in Clippy. Otherwise, it will fail with a list of symbols +// which are unused. +// +// This test is a no-op if run as part of the compiler test suite +// and will always succeed. + +use std::collections::HashSet; +use std::ffi::OsStr; +use std::fs; + +use regex::Regex; +use walkdir::{DirEntry, WalkDir}; + +const SYM_FILE: &str = "clippy_utils/src/sym.rs"; + +type Result<T, E = AnyError> = std::result::Result<T, E>; +type AnyError = Box<dyn std::error::Error>; + +#[test] +#[allow(clippy::case_sensitive_file_extension_comparisons)] +fn all_symbols_are_used() -> Result<()> { + if option_env!("RUSTC_TEST_SUITE").is_some() { + return Ok(()); + } + + // Load all symbols defined in `SYM_FILE`. + let content = fs::read_to_string(SYM_FILE)?; + let content = content + .split_once("generate! {") + .ok_or("cannot find symbols start")? + .1 + .split_once("\n}\n") + .ok_or("cannot find symbols end")? + .0; + let mut interned: HashSet<String> = Regex::new(r"(?m)^ (\w+)") + .unwrap() + .captures_iter(content) + .map(|m| m[1].to_owned()) + .collect(); + + // Remove symbols used as `sym::*`. + let used_re = Regex::new(r"\bsym::(\w+)\b").unwrap(); + let rs_ext = OsStr::new("rs"); + for dir in ["clippy_lints", "clippy_lints_internal", "clippy_utils", "src"] { + for file in WalkDir::new(dir) + .into_iter() + .flatten() + .map(DirEntry::into_path) + .filter(|p| p.extension() == Some(rs_ext)) + { + for cap in used_re.captures_iter(&fs::read_to_string(file)?) { + interned.remove(&cap[1]); + } + } + } + + // Remove symbols used as part of paths. + let paths_re = Regex::new(r"path!\(([\w:]+)\)").unwrap(); + for path in [ + "clippy_utils/src/paths.rs", + "clippy_lints_internal/src/internal_paths.rs", + ] { + for cap in paths_re.captures_iter(&fs::read_to_string(path)?) { + for sym in cap[1].split("::") { + interned.remove(sym); + } + } + } + + let mut extra = interned.iter().collect::<Vec<_>>(); + if !extra.is_empty() { + extra.sort_unstable(); + eprintln!("Unused symbols defined in {SYM_FILE}:"); + for sym in extra { + eprintln!(" - {sym}"); + } + Err(format!("extra symbols found — remove them {SYM_FILE}"))?; + } + Ok(()) +}
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs index 6a9a493..4a179cd 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs
@@ -1,4 +1,5 @@ #![warn(clippy::await_holding_invalid_type)] +#![allow(clippy::ip_constant)] use std::net::Ipv4Addr; async fn bad() -> u32 {
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index deb7f49..c3c8869 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
@@ -1,5 +1,5 @@ error: holding a disallowed type across an await point `std::string::String` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:6:9 | LL | let _x = String::from("hello"); | ^^ @@ -9,13 +9,13 @@ = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` error: holding a disallowed type across an await point `std::net::Ipv4Addr` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:11:9 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:12:9 | LL | let x = Ipv4Addr::new(127, 0, 0, 1); | ^ error: holding a disallowed type across an await point `std::string::String` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:35:13 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:36:13 | LL | let _x = String::from("hi!"); | ^^
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 06472a4..922d304 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
@@ -239,3 +239,40 @@ fn fp_if_let_issue7054() { } fn main() {} + +mod issue14873 { + fn foo() -> i32 { + todo!() + } + + macro_rules! qux { + ($a:ident, $b:ident, $condition:expr) => { + if $condition { + "." + } else { + "" + }; + $a = foo(); + $b = foo(); + }; + } + + fn share_on_bottom() { + let mut a = 0; + let mut b = 0; + if false { + qux!(a, b, a == b); + } else { + qux!(a, b, a != b); + }; + + if false { + qux!(a, b, a == b); + let y = 1; + } else { + qux!(a, b, a != b); + let y = 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 648a99c..f437db8 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
@@ -157,5 +157,20 @@ LL + a = 0x99; | -error: aborting due to 9 previous errors +error: all if blocks contain the same code at the end + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:274:9 + | +LL | / let y = 1; +LL | | +LL | | } + | |_________^ + | + = warning: some moved values might need to be renamed to avoid wrong references +help: consider moving these statements after the if + | +LL ~ } +LL + let y = 1; + | + +error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs index 694c67d..dcd7767 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
@@ -124,3 +124,34 @@ fn pf_local_with_inferred_type_issue7053() { } fn main() {} + +mod issue14873 { + fn foo() -> i32 { + todo!() + } + + macro_rules! qux { + ($a:ident, $b:ident, $condition:expr) => { + let $a: i32 = foo(); + let $b: i32 = foo(); + if $condition { "." } else { "" } + }; + } + + fn share_on_top() { + if false { + qux!(a, b, a == b); + } else { + qux!(a, b, a != b); + }; + + if false { + //~^ branches_sharing_code + let x = 1; + qux!(a, b, a == b); + } else { + let x = 1; + qux!(a, b, a != b); + } + } +}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr index d28e9c7..30efb98 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
@@ -125,5 +125,20 @@ LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_top.rs:148:9 + | +LL | / if false { +LL | | +LL | | let x = 1; + | |______________________^ + | + = warning: some moved values might need to be renamed to avoid wrong references +help: consider moving these statements before the if + | +LL ~ let x = 1; +LL + if false { + | + +error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs index 75334f7..e848f06 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
@@ -128,3 +128,42 @@ fn added_note_for_expression_use() -> u32 { } fn main() {} + +mod issue14873 { + fn foo() -> i32 { + todo!() + } + + macro_rules! qux { + ($a:ident, $b:ident, $condition:expr) => { + let mut $a: i32 = foo(); + let mut $b: i32 = foo(); + if $condition { + "." + } else { + "" + }; + $a = foo(); + $b = foo(); + }; + } + + fn share_on_top_and_bottom() { + if false { + qux!(a, b, a == b); + } else { + qux!(a, b, a != b); + }; + + if false { + //~^ branches_sharing_code + let x = 1; + qux!(a, b, a == b); + let y = 1; + } else { + let x = 1; + qux!(a, b, a != b); + let y = 1; + } + } +}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr index 2200ab4..40f3453 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
@@ -159,5 +159,31 @@ LL + x * 4 | -error: aborting due to 5 previous errors +error: all if blocks contain the same code at both the start and the end + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:158:9 + | +LL | / if false { +LL | | +LL | | let x = 1; + | |______________________^ + | +note: this code is shared at the end + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:166:9 + | +LL | / let y = 1; +LL | | } + | |_________^ + = warning: some moved values might need to be renamed to avoid wrong references +help: consider moving these statements before the if + | +LL ~ let x = 1; +LL + if false { + | +help: consider moving these statements after the if + | +LL ~ } +LL + let y = 1; + | + +error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/cmp_null.fixed b/src/tools/clippy/tests/ui/cmp_null.fixed index 140ddb1..04b8ec5 100644 --- a/src/tools/clippy/tests/ui/cmp_null.fixed +++ b/src/tools/clippy/tests/ui/cmp_null.fixed
@@ -33,3 +33,9 @@ let _ = (x as *const ()).is_null(); //~^ cmp_null } + +fn issue15010() { + let f: *mut i32 = std::ptr::null_mut(); + debug_assert!(!f.is_null()); + //~^ cmp_null +}
diff --git a/src/tools/clippy/tests/ui/cmp_null.rs b/src/tools/clippy/tests/ui/cmp_null.rs index 16ed177..6f7762e 100644 --- a/src/tools/clippy/tests/ui/cmp_null.rs +++ b/src/tools/clippy/tests/ui/cmp_null.rs
@@ -33,3 +33,9 @@ fn main() { let _ = x as *const () == ptr::null(); //~^ cmp_null } + +fn issue15010() { + let f: *mut i32 = std::ptr::null_mut(); + debug_assert!(f != std::ptr::null_mut()); + //~^ cmp_null +}
diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr index 6821846..8a75b05 100644 --- a/src/tools/clippy/tests/ui/cmp_null.stderr +++ b/src/tools/clippy/tests/ui/cmp_null.stderr
@@ -31,5 +31,11 @@ LL | let _ = x as *const () == ptr::null(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(x as *const ()).is_null()` -error: aborting due to 5 previous errors +error: comparing with null is better expressed by the `.is_null()` method + --> tests/ui/cmp_null.rs:39:19 + | +LL | debug_assert!(f != std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!f.is_null()` + +error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.fixed b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed new file mode 100644 index 0000000..ae9d3ef --- /dev/null +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed
@@ -0,0 +1,26 @@ +#![warn(clippy::coerce_container_to_any)] + +use std::any::Any; + +fn main() { + let x: Box<dyn Any> = Box::new(()); + let ref_x = &x; + + f(&*x); + //~^ coerce_container_to_any + + f(&**ref_x); + //~^ coerce_container_to_any + + let _: &dyn Any = &*x; + //~^ coerce_container_to_any + + f(&42); + f(&Box::new(())); + f(&Box::new(Box::new(()))); + f(&**ref_x); + f(&*x); + let _: &dyn Any = &*x; +} + +fn f(_: &dyn Any) {}
diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.rs b/src/tools/clippy/tests/ui/coerce_container_to_any.rs new file mode 100644 index 0000000..9948bd4 --- /dev/null +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.rs
@@ -0,0 +1,26 @@ +#![warn(clippy::coerce_container_to_any)] + +use std::any::Any; + +fn main() { + let x: Box<dyn Any> = Box::new(()); + let ref_x = &x; + + f(&x); + //~^ coerce_container_to_any + + f(ref_x); + //~^ coerce_container_to_any + + let _: &dyn Any = &x; + //~^ coerce_container_to_any + + f(&42); + f(&Box::new(())); + f(&Box::new(Box::new(()))); + f(&**ref_x); + f(&*x); + let _: &dyn Any = &*x; +} + +fn f(_: &dyn Any) {}
diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.stderr b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr new file mode 100644 index 0000000..00ab77e --- /dev/null +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr
@@ -0,0 +1,23 @@ +error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any` + --> tests/ui/coerce_container_to_any.rs:9:7 + | +LL | f(&x); + | ^^ help: consider dereferencing: `&*x` + | + = note: `-D clippy::coerce-container-to-any` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::coerce_container_to_any)]` + +error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any` + --> tests/ui/coerce_container_to_any.rs:12:7 + | +LL | f(ref_x); + | ^^^^^ help: consider dereferencing: `&**ref_x` + +error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any` + --> tests/ui/coerce_container_to_any.rs:15:23 + | +LL | let _: &dyn Any = &x; + | ^^ help: consider dereferencing: `&*x` + +error: aborting due to 3 previous errors +
diff --git a/src/tools/clippy/tests/ui/crashes/ice-14935.rs b/src/tools/clippy/tests/ui/crashes/ice-14935.rs new file mode 100644 index 0000000..74cda9a --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-14935.rs
@@ -0,0 +1,27 @@ +//@check-pass +#![warn(clippy::mutable_key_type)] + +use std::marker::PhantomData; + +trait Group { + type ExposantSet: Group; +} + +struct Pow<T: Group> { + exposant: Box<Pow<T::ExposantSet>>, + _p: PhantomData<T>, +} + +impl<T: Group> Pow<T> { + fn is_zero(&self) -> bool { + false + } + fn normalize(&self) { + #[expect(clippy::if_same_then_else)] + if self.is_zero() { + } else if false { + } + } +} + +fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.rs b/src/tools/clippy/tests/ui/crashes/ice-9463.rs index 93808e0..cfa6cda 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9463.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9463.rs
@@ -1,8 +1,7 @@ -#![deny(arithmetic_overflow)] +//@check-pass + fn main() { let _x = -1_i32 >> -1; - //~^ ERROR: this arithmetic operation will overflow + #[expect(overflowing_literals)] let _y = 1u32 >> 10000000000000u32; - //~^ ERROR: this arithmetic operation will overflow - //~| ERROR: literal out of range }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.stderr b/src/tools/clippy/tests/ui/crashes/ice-9463.stderr deleted file mode 100644 index 9a3a5e4..0000000 --- a/src/tools/clippy/tests/ui/crashes/ice-9463.stderr +++ /dev/null
@@ -1,29 +0,0 @@ -error: this arithmetic operation will overflow - --> tests/ui/crashes/ice-9463.rs:3:14 - | -LL | let _x = -1_i32 >> -1; - | ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow - | -note: the lint level is defined here - --> tests/ui/crashes/ice-9463.rs:1:9 - | -LL | #![deny(arithmetic_overflow)] - | ^^^^^^^^^^^^^^^^^^^ - -error: this arithmetic operation will overflow - --> tests/ui/crashes/ice-9463.rs:5:14 - | -LL | let _y = 1u32 >> 10000000000000u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift right by `1316134912_u32`, which would overflow - -error: literal out of range for `u32` - --> tests/ui/crashes/ice-9463.rs:5:22 - | -LL | let _y = 1u32 >> 10000000000000u32; - | ^^^^^^^^^^^^^^^^^ - | - = note: the literal `10000000000000u32` does not fit into the type `u32` whose range is `0..=4294967295` - = note: `#[deny(overflowing_literals)]` on by default - -error: aborting due to 3 previous errors -
diff --git a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs index 55fe418..dccb0cf 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs
@@ -4,6 +4,7 @@ struct Foo; +#[allow(clippy::infallible_try_from)] impl<'a> std::convert::TryFrom<&'a String> for Foo { type Error = std::convert::Infallible;
diff --git a/src/tools/clippy/tests/ui/create_dir.fixed b/src/tools/clippy/tests/ui/create_dir.fixed index 4a5b1b7..d4b8f8b 100644 --- a/src/tools/clippy/tests/ui/create_dir.fixed +++ b/src/tools/clippy/tests/ui/create_dir.fixed
@@ -7,12 +7,31 @@ fn main() { // Should be warned - create_dir_all("foo"); + std::fs::create_dir_all("foo"); //~^ create_dir - create_dir_all("bar").unwrap(); + std::fs::create_dir_all("bar").unwrap(); //~^ create_dir // Shouldn't be warned create_dir(); std::fs::create_dir_all("foobar"); } + +mod issue14994 { + fn with_no_prefix() { + use std::fs::create_dir; + std::fs::create_dir_all("some/dir").unwrap(); + //~^ create_dir + } + + fn with_fs_prefix() { + use std::fs; + fs::create_dir_all("/some/dir").unwrap(); + //~^ create_dir + } + + fn with_full_prefix() { + std::fs::create_dir_all("/some/dir").unwrap(); + //~^ create_dir + } +}
diff --git a/src/tools/clippy/tests/ui/create_dir.rs b/src/tools/clippy/tests/ui/create_dir.rs index bf185ba..21e0bdb 100644 --- a/src/tools/clippy/tests/ui/create_dir.rs +++ b/src/tools/clippy/tests/ui/create_dir.rs
@@ -16,3 +16,22 @@ fn main() { create_dir(); std::fs::create_dir_all("foobar"); } + +mod issue14994 { + fn with_no_prefix() { + use std::fs::create_dir; + create_dir("some/dir").unwrap(); + //~^ create_dir + } + + fn with_fs_prefix() { + use std::fs; + fs::create_dir("/some/dir").unwrap(); + //~^ create_dir + } + + fn with_full_prefix() { + std::fs::create_dir("/some/dir").unwrap(); + //~^ create_dir + } +}
diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr index 51d6ac6..e3ca0e7 100644 --- a/src/tools/clippy/tests/ui/create_dir.stderr +++ b/src/tools/clippy/tests/ui/create_dir.stderr
@@ -8,9 +8,8 @@ = help: to override `-D warnings` add `#[allow(clippy::create_dir)]` help: consider calling `std::fs::create_dir_all` instead | -LL - std::fs::create_dir("foo"); -LL + create_dir_all("foo"); - | +LL | std::fs::create_dir_all("foo"); + | ++++ error: calling `std::fs::create_dir` where there may be a better way --> tests/ui/create_dir.rs:12:5 @@ -20,9 +19,41 @@ | help: consider calling `std::fs::create_dir_all` instead | -LL - std::fs::create_dir("bar").unwrap(); -LL + create_dir_all("bar").unwrap(); - | +LL | std::fs::create_dir_all("bar").unwrap(); + | ++++ -error: aborting due to 2 previous errors +error: calling `std::fs::create_dir` where there may be a better way + --> tests/ui/create_dir.rs:23:9 + | +LL | create_dir("some/dir").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider calling `std::fs::create_dir_all` instead + | +LL | std::fs::create_dir_all("some/dir").unwrap(); + | +++++++++ ++++ + +error: calling `std::fs::create_dir` where there may be a better way + --> tests/ui/create_dir.rs:29:9 + | +LL | fs::create_dir("/some/dir").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider calling `std::fs::create_dir_all` instead + | +LL | fs::create_dir_all("/some/dir").unwrap(); + | ++++ + +error: calling `std::fs::create_dir` where there may be a better way + --> tests/ui/create_dir.rs:34:9 + | +LL | std::fs::create_dir("/some/dir").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider calling `std::fs::create_dir_all` instead + | +LL | std::fs::create_dir_all("/some/dir").unwrap(); + | ++++ + +error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs index 30fbdbc..15bb673 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.rs +++ b/src/tools/clippy/tests/ui/disallowed_names.rs
@@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![allow( dead_code, clippy::needless_if, @@ -9,6 +10,9 @@ )] #![warn(clippy::disallowed_names)] +extern crate proc_macros; +use proc_macros::{external, with_span}; + fn test(foo: ()) {} //~^ disallowed_names @@ -66,6 +70,17 @@ fn issue_1647_ref_mut() { //~^ disallowed_names } +pub fn issue_14958_proc_macro() { + // does not lint macro-generated code + external! { + let foo = 0; + } + with_span! { + span + let foo = 0; + } +} + #[cfg(test)] mod tests { fn issue_7305() {
diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr index 09398eb..b43d1b3 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.stderr +++ b/src/tools/clippy/tests/ui/disallowed_names.stderr
@@ -1,5 +1,5 @@ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:12:9 + --> tests/ui/disallowed_names.rs:16:9 | LL | fn test(foo: ()) {} | ^^^ @@ -8,79 +8,79 @@ = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:16:9 + --> tests/ui/disallowed_names.rs:20:9 | LL | let foo = 42; | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:19:9 + --> tests/ui/disallowed_names.rs:23:9 | LL | let baz = 42; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:22:9 + --> tests/ui/disallowed_names.rs:26:9 | LL | let quux = 42; | ^^^^ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:35:10 + --> tests/ui/disallowed_names.rs:39:10 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:35:20 + --> tests/ui/disallowed_names.rs:39:20 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:35:26 + --> tests/ui/disallowed_names.rs:39:26 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^^ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:43:19 + --> tests/ui/disallowed_names.rs:47:19 | LL | fn issue_1647(mut foo: u8) { | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:46:13 + --> tests/ui/disallowed_names.rs:50:13 | LL | let mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:49:21 + --> tests/ui/disallowed_names.rs:53:21 | LL | if let Some(mut quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:54:13 + --> tests/ui/disallowed_names.rs:58:13 | LL | let ref baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:57:21 + --> tests/ui/disallowed_names.rs:61:21 | LL | if let Some(ref quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:62:17 + --> tests/ui/disallowed_names.rs:66:17 | LL | let ref mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:65:25 + --> tests/ui/disallowed_names.rs:69:25 | LL | if let Some(ref mut quux) = Some(42) {} | ^^^^
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed new file mode 100644 index 0000000..9ed3fd4 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed
@@ -0,0 +1,186 @@ +#![warn(clippy::doc_suspicious_footnotes)] +#![allow(clippy::needless_raw_string_hashes)] +//! This is not a footnote[^1]. +//! +//! [^1]: <!-- description --> +//~^ doc_suspicious_footnotes +//! +//! This is not a footnote[^either], but it doesn't warn. +//! +//! This is not a footnote\[^1], but it also doesn't warn. +//! +//! This is not a footnote[^1\], but it also doesn't warn. +//! +//! This is not a `footnote[^1]`, but it also doesn't warn. +//! +//! This is a footnote[^2]. +//! +//! [^2]: hello world + +/// This is not a footnote[^1]. +/// +/// [^1]: <!-- description --> +//~^ doc_suspicious_footnotes +/// +/// This is not a footnote[^either], but it doesn't warn. +/// +/// This is not a footnote\[^1], but it also doesn't warn. +/// +/// This is not a footnote[^1\], but it also doesn't warn. +/// +/// This is not a `footnote[^1]`, but it also doesn't warn. +/// +/// This is a footnote[^2]. +/// +/// [^2]: hello world +pub fn footnotes() { + // test code goes here +} + +pub struct Foo; +#[rustfmt::skip] +impl Foo { + #[doc = r#"This is not a footnote[^1]. + +[^1]: <!-- description -->"#] + //~^ doc_suspicious_footnotes + #[doc = r#""#] + #[doc = r#"This is not a footnote[^either], but it doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote\[^1], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote[^1\], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a `footnote[^1]`, but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is a footnote[^2]."#] + #[doc = r#""#] + #[doc = r#"[^2]: hello world"#] + pub fn footnotes() { + // test code goes here + } + #[doc = r#"This is not a footnote[^1]. + + This is not a footnote[^either], but it doesn't warn. + + This is not a footnote\[^1], but it also doesn't warn. + + This is not a footnote[^1\], but it also doesn't warn. + + This is not a `footnote[^1]`, but it also doesn't warn. + + This is a footnote[^2]. + + [^2]: hello world + + +[^1]: <!-- description -->"#] + //~^^^^^^^^^^^^^^ doc_suspicious_footnotes + pub fn footnotes2() { + // test code goes here + } + #[cfg_attr( + not(FALSE), + doc = r#"This is not a footnote[^1]. + +This is not a footnote[^either], but it doesn't warn. + +[^1]: <!-- description -->"# + //~^ doc_suspicious_footnotes + )] + pub fn footnotes3() { + // test code goes here + } + #[doc = "My footnote [^foot\note]"] + pub fn footnote4() { + // test code goes here + } + #[doc = "Hihi"]pub fn footnote5() { + // test code goes here + } +} + +#[doc = r#"This is not a footnote[^1]. + +[^1]: <!-- description -->"#] +//~^ doc_suspicious_footnotes +#[doc = r""] +#[doc = r"This is not a footnote[^either], but it doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote\[^1], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote[^1\], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a `footnote[^1]`, but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is a footnote[^2]."] +#[doc = r""] +#[doc = r"[^2]: hello world"] +pub fn footnotes_attrs() { + // test code goes here +} + +pub mod multiline { + /*! + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ +/*! [^1]: <!-- description --> */ + /** + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ +/** [^1]: <!-- description --> */ + pub fn foo() {} +} + +/// This is not a footnote [^1] +/// +/// [^1]: <!-- description --> +//~^ doc_suspicious_footnotes +/// +/// This one is [^2] +/// +/// [^2]: contents +#[doc = r#"This is not a footnote [^3] + +[^3]: <!-- description -->"#] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^4]"] +#[doc = ""] +#[doc = "[^4]: contents"] +pub struct MultiFragmentFootnote; + +#[doc(inline)] +/// This is not a footnote [^5] +/// +/// [^5]: <!-- description --> +//~^ doc_suspicious_footnotes +/// +/// This one is [^6] +/// +/// [^6]: contents +#[doc = r#"This is not a footnote [^7] + +[^7]: <!-- description -->"#] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^8]"] +#[doc = ""] +#[doc = "[^8]: contents"] +pub use MultiFragmentFootnote as OtherInlinedFootnote;
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs new file mode 100644 index 0000000..9a8d0dc --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs
@@ -0,0 +1,162 @@ +#![warn(clippy::doc_suspicious_footnotes)] +#![allow(clippy::needless_raw_string_hashes)] +//! This is not a footnote[^1]. +//~^ doc_suspicious_footnotes +//! +//! This is not a footnote[^either], but it doesn't warn. +//! +//! This is not a footnote\[^1], but it also doesn't warn. +//! +//! This is not a footnote[^1\], but it also doesn't warn. +//! +//! This is not a `footnote[^1]`, but it also doesn't warn. +//! +//! This is a footnote[^2]. +//! +//! [^2]: hello world + +/// This is not a footnote[^1]. +//~^ doc_suspicious_footnotes +/// +/// This is not a footnote[^either], but it doesn't warn. +/// +/// This is not a footnote\[^1], but it also doesn't warn. +/// +/// This is not a footnote[^1\], but it also doesn't warn. +/// +/// This is not a `footnote[^1]`, but it also doesn't warn. +/// +/// This is a footnote[^2]. +/// +/// [^2]: hello world +pub fn footnotes() { + // test code goes here +} + +pub struct Foo; +#[rustfmt::skip] +impl Foo { + #[doc = r#"This is not a footnote[^1]."#] + //~^ doc_suspicious_footnotes + #[doc = r#""#] + #[doc = r#"This is not a footnote[^either], but it doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote\[^1], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote[^1\], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a `footnote[^1]`, but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is a footnote[^2]."#] + #[doc = r#""#] + #[doc = r#"[^2]: hello world"#] + pub fn footnotes() { + // test code goes here + } + #[doc = "This is not a footnote[^1]. + + This is not a footnote[^either], but it doesn't warn. + + This is not a footnote\\[^1], but it also doesn't warn. + + This is not a footnote[^1\\], but it also doesn't warn. + + This is not a `footnote[^1]`, but it also doesn't warn. + + This is a footnote[^2]. + + [^2]: hello world + "] + //~^^^^^^^^^^^^^^ doc_suspicious_footnotes + pub fn footnotes2() { + // test code goes here + } + #[cfg_attr( + not(FALSE), + doc = "This is not a footnote[^1].\n\nThis is not a footnote[^either], but it doesn't warn." + //~^ doc_suspicious_footnotes + )] + pub fn footnotes3() { + // test code goes here + } + #[doc = "My footnote [^foot\note]"] + pub fn footnote4() { + // test code goes here + } + #[doc = "Hihi"]pub fn footnote5() { + // test code goes here + } +} + +#[doc = r"This is not a footnote[^1]."] +//~^ doc_suspicious_footnotes +#[doc = r""] +#[doc = r"This is not a footnote[^either], but it doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote\[^1], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote[^1\], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a `footnote[^1]`, but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is a footnote[^2]."] +#[doc = r""] +#[doc = r"[^2]: hello world"] +pub fn footnotes_attrs() { + // test code goes here +} + +pub mod multiline { + /*! + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ + /** + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ + pub fn foo() {} +} + +/// This is not a footnote [^1] +//~^ doc_suspicious_footnotes +/// +/// This one is [^2] +/// +/// [^2]: contents +#[doc = "This is not a footnote [^3]"] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^4]"] +#[doc = ""] +#[doc = "[^4]: contents"] +pub struct MultiFragmentFootnote; + +#[doc(inline)] +/// This is not a footnote [^5] +//~^ doc_suspicious_footnotes +/// +/// This one is [^6] +/// +/// [^6]: contents +#[doc = "This is not a footnote [^7]"] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^8]"] +#[doc = ""] +#[doc = "[^8]: contents"] +pub use MultiFragmentFootnote as OtherInlinedFootnote;
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr new file mode 100644 index 0000000..4f920f3 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr
@@ -0,0 +1,179 @@ +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:3:27 + | +LL | //! This is not a footnote[^1]. + | ^^^^ + | + = note: `-D clippy::doc-suspicious-footnotes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_suspicious_footnotes)]` +help: add footnote definition + | +LL ~ //! This is not a footnote[^1]. +LL + //! +LL + //! [^1]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:18:27 + | +LL | /// This is not a footnote[^1]. + | ^^^^ + | +help: add footnote definition + | +LL ~ /// This is not a footnote[^1]. +LL + /// +LL + /// [^1]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:39:13 + | +LL | #[doc = r#"This is not a footnote[^1]."#] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote[^1]. +LL + +LL ~ [^1]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:56:13 + | +LL | #[doc = "This is not a footnote[^1]. + | _____________^ +LL | | +LL | | This is not a footnote[^either], but it doesn't warn. +... | +LL | | [^2]: hello world +LL | | "] + | |_____^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote[^1]. +LL + +LL + This is not a footnote[^either], but it doesn't warn. +LL + +LL + This is not a footnote\[^1], but it also doesn't warn. +LL + +LL + This is not a footnote[^1\], but it also doesn't warn. +LL + +LL + This is not a `footnote[^1]`, but it also doesn't warn. +LL + +LL + This is a footnote[^2]. +LL + +LL + [^2]: hello world +LL + +LL + +LL ~ [^1]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:76:38 + | +LL | doc = "This is not a footnote[^1].\n\nThis is not a footnote[^either], but it doesn't warn." + | ^^^^ + | +help: add footnote definition + | +LL ~ doc = r#"This is not a footnote[^1]. +LL + +LL + This is not a footnote[^either], but it doesn't warn. +LL + +LL + [^1]: <!-- description -->"# + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:91:9 + | +LL | #[doc = r"This is not a footnote[^1]."] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote[^1]. +LL + +LL ~ [^1]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:111:30 + | +LL | * This is not a footnote[^1]. + | ^^^^ + | +help: add footnote definition + | +LL ~ */ +LL + /*! [^1]: <!-- description --> */ + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:122:30 + | +LL | * This is not a footnote[^1]. + | ^^^^ + | +help: add footnote definition + | +LL ~ */ +LL + /** [^1]: <!-- description --> */ + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:135:28 + | +LL | /// This is not a footnote [^1] + | ^^^^ + | +help: add footnote definition + | +LL ~ /// This is not a footnote [^1] +LL + /// +LL + /// [^1]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:141:33 + | +LL | #[doc = "This is not a footnote [^3]"] + | ^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote [^3] +LL + +LL ~ [^3]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:150:28 + | +LL | /// This is not a footnote [^5] + | ^^^^ + | +help: add footnote definition + | +LL ~ /// This is not a footnote [^5] +LL + /// +LL + /// [^5]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:156:33 + | +LL | #[doc = "This is not a footnote [^7]"] + | ^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote [^7] +LL + +LL ~ [^7]: <!-- description -->"#] + | + +error: aborting due to 12 previous errors +
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs new file mode 100644 index 0000000..4f75ad9 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs
@@ -0,0 +1,4 @@ +//@ error-in-other-file: footnote +//@ no-rustfix +#![warn(clippy::doc_suspicious_footnotes)] +#![doc=include_str!("doc_suspicious_footnotes_include.txt")]
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr new file mode 100644 index 0000000..74154e3 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr
@@ -0,0 +1,17 @@ +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes_include.txt:1:23 + | +LL | This is not a footnote[^1]. + | ^^^^ + | + = note: `-D clippy::doc-suspicious-footnotes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_suspicious_footnotes)]` +help: add footnote definition + | +LL ~ [^2]: hello world +LL + +LL + [^1]: <!-- description --> + | + +error: aborting due to 1 previous error +
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt new file mode 100644 index 0000000..2a533e3 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt
@@ -0,0 +1,13 @@ +This is not a footnote[^1]. //~ doc_suspicious_footnotes + +This is not a footnote[^either], but it doesn't warn. + +This is not a footnote\[^1], but it also doesn't warn. + +This is not a footnote[^1\], but it also doesn't warn. + +This is not a `footnote[^1]`, but it also doesn't warn. + +This is a footnote[^2]. + +[^2]: hello world
diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed index edfdaa2..3cb6c0b 100644 --- a/src/tools/clippy/tests/ui/format_args.fixed +++ b/src/tools/clippy/tests/ui/format_args.fixed
@@ -192,3 +192,13 @@ print_substring("Hello, world!"); } } + +mod issue14952 { + use std::path::Path; + struct Foo(Path); + impl std::fmt::Debug for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", &self.0) + } + } +}
diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs index 367560d..8a9c369 100644 --- a/src/tools/clippy/tests/ui/format_args.rs +++ b/src/tools/clippy/tests/ui/format_args.rs
@@ -192,3 +192,13 @@ fn main() { print_substring("Hello, world!"); } } + +mod issue14952 { + use std::path::Path; + struct Foo(Path); + impl std::fmt::Debug for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", &self.0) + } + } +}
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index ab6a823..2510a02 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
@@ -68,7 +68,6 @@ fn main() { // This should be linted, since `suppress-restriction-lint-in-const` default is false. const { &ARR[idx4()] }; //~^ ERROR: indexing may panic - //~| ERROR: index out of bounds let y = &x; // Ok, referencing shouldn't affect this lint. See the issue 6021
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 8e24b89..c68e1d5 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -9,18 +9,6 @@ = note: `-D clippy::indexing-slicing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` -error[E0080]: index out of bounds: the length is 2 but the index is 4 - --> tests/ui/indexing_slicing_index.rs:69:14 - | -LL | const { &ARR[idx4()] }; - | ^^^^^^^^^^^ evaluation of `main::{constant#3}` failed here - -note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:69:5 - | -LL | const { &ARR[idx4()] }; - | ^^^^^^^^^^^^^^^^^^^^^^ - error: indexing may panic --> tests/ui/indexing_slicing_index.rs:48:5 | @@ -63,13 +51,13 @@ = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:77:5 + --> tests/ui/indexing_slicing_index.rs:76:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:81:5 + --> tests/ui/indexing_slicing_index.rs:80:5 | LL | v[0]; | ^^^^ @@ -77,7 +65,7 @@ = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:83:5 + --> tests/ui/indexing_slicing_index.rs:82:5 | LL | v[10]; | ^^^^^ @@ -85,7 +73,7 @@ = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:85:5 + --> tests/ui/indexing_slicing_index.rs:84:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +81,13 @@ = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:93:5 + --> tests/ui/indexing_slicing_index.rs:92:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:97:5 + --> tests/ui/indexing_slicing_index.rs:96:5 | LL | v[N]; | ^^^^ @@ -107,7 +95,7 @@ = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:99:5 + --> tests/ui/indexing_slicing_index.rs:98:5 | LL | v[M]; | ^^^^ @@ -115,11 +103,10 @@ = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:103:13 + --> tests/ui/indexing_slicing_index.rs:102:13 | LL | let _ = x[4]; | ^^^^ -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/clippy/tests/ui/infallible_try_from.rs b/src/tools/clippy/tests/ui/infallible_try_from.rs new file mode 100644 index 0000000..6a1f12f --- /dev/null +++ b/src/tools/clippy/tests/ui/infallible_try_from.rs
@@ -0,0 +1,33 @@ +#![feature(never_type)] +#![warn(clippy::infallible_try_from)] + +use std::convert::Infallible; + +struct MyStruct(i32); + +impl TryFrom<i8> for MyStruct { + //~^ infallible_try_from + type Error = !; + fn try_from(other: i8) -> Result<Self, !> { + Ok(Self(other.into())) + } +} + +impl TryFrom<i16> for MyStruct { + //~^ infallible_try_from + type Error = Infallible; + fn try_from(other: i16) -> Result<Self, Infallible> { + Ok(Self(other.into())) + } +} + +impl TryFrom<i64> for MyStruct { + type Error = i64; + fn try_from(other: i64) -> Result<Self, i64> { + Ok(Self(i32::try_from(other).map_err(|_| other)?)) + } +} + +fn main() { + // test code goes here +}
diff --git a/src/tools/clippy/tests/ui/infallible_try_from.stderr b/src/tools/clippy/tests/ui/infallible_try_from.stderr new file mode 100644 index 0000000..705b118 --- /dev/null +++ b/src/tools/clippy/tests/ui/infallible_try_from.stderr
@@ -0,0 +1,23 @@ +error: infallible TryFrom impl; consider implementing From, instead + --> tests/ui/infallible_try_from.rs:8:1 + | +LL | impl TryFrom<i8> for MyStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Error = !; + | - infallible error type + | + = note: `-D clippy::infallible-try-from` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::infallible_try_from)]` + +error: infallible TryFrom impl; consider implementing From, instead + --> tests/ui/infallible_try_from.rs:16:1 + | +LL | impl TryFrom<i16> for MyStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Error = Infallible; + | ---------- infallible error type + +error: aborting due to 2 previous errors +
diff --git a/src/tools/clippy/tests/ui/ip_constant.fixed b/src/tools/clippy/tests/ui/ip_constant.fixed new file mode 100644 index 0000000..2e3389c --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant.fixed
@@ -0,0 +1,107 @@ +#![warn(clippy::ip_constant)] +#![allow(dead_code)] +#![allow(clippy::identity_op)] +#![allow(clippy::eq_op)] + +fn literal_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv6Addr::UNSPECIFIED; + //~^ ip_constant +} + +fn literal_test2() { + use std::net; + let _ = net::Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = net::Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = net::Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + let _ = net::Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = net::Ipv6Addr::UNSPECIFIED; + //~^ ip_constant +} + +fn literal_test3() { + let _ = std::net::Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = std::net::Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = std::net::Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + let _ = std::net::Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = std::net::Ipv6Addr::UNSPECIFIED; + //~^ ip_constant +} + +const CONST_U8_0: u8 = 0; +const CONST_U8_1: u8 = 1; +const CONST_U8_127: u8 = 127; +const CONST_U8_255: u8 = 255; + +const CONST_U16_0: u16 = 0; +const CONST_U16_1: u16 = 1; + +fn const_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::LOCALHOST; + + let _ = Ipv6Addr::UNSPECIFIED; +} + +fn const_test2() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv6Addr::LOCALHOST; + //~^ ip_constant +} + +macro_rules! ipv4_new { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + std::net::Ipv4Addr::new($a, $b, $c, $d) + }; +} + +fn macro_test() { + let _ = ipv4_new!(127, 0, 0, 1); + // no lint + let _ = ipv4_new!(255, 255, 255, 255); + // no lint + let _ = ipv4_new!(0, 0, 0, 0); + // no lint +} + +fn main() { + // UI Test +}
diff --git a/src/tools/clippy/tests/ui/ip_constant.rs b/src/tools/clippy/tests/ui/ip_constant.rs new file mode 100644 index 0000000..15e0b05 --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant.rs
@@ -0,0 +1,127 @@ +#![warn(clippy::ip_constant)] +#![allow(dead_code)] +#![allow(clippy::identity_op)] +#![allow(clippy::eq_op)] + +fn literal_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::new(127, 0, 0, 1); + //~^ ip_constant + let _ = Ipv4Addr::new(255, 255, 255, 255); + //~^ ip_constant + let _ = Ipv4Addr::new(0, 0, 0, 0); + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + //~^ ip_constant +} + +fn literal_test2() { + use std::net; + let _ = net::Ipv4Addr::new(127, 0, 0, 1); + //~^ ip_constant + let _ = net::Ipv4Addr::new(255, 255, 255, 255); + //~^ ip_constant + let _ = net::Ipv4Addr::new(0, 0, 0, 0); + //~^ ip_constant + + let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + //~^ ip_constant +} + +fn literal_test3() { + let _ = std::net::Ipv4Addr::new(127, 0, 0, 1); + //~^ ip_constant + let _ = std::net::Ipv4Addr::new(255, 255, 255, 255); + //~^ ip_constant + let _ = std::net::Ipv4Addr::new(0, 0, 0, 0); + //~^ ip_constant + + let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + //~^ ip_constant +} + +const CONST_U8_0: u8 = 0; +const CONST_U8_1: u8 = 1; +const CONST_U8_127: u8 = 127; +const CONST_U8_255: u8 = 255; + +const CONST_U16_0: u16 = 0; +const CONST_U16_1: u16 = 1; + +fn const_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1); + //~^ ip_constant + let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255); + //~^ ip_constant + let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0); + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::new( + //~^ ip_constant + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_1, + ); + + let _ = Ipv6Addr::new( + //~^ ip_constant + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + ); +} + +fn const_test2() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::new(126 + 1, 0, 0, 1); + //~^ ip_constant + let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255); + //~^ ip_constant + let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 }); + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1); + //~^ ip_constant +} + +macro_rules! ipv4_new { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + std::net::Ipv4Addr::new($a, $b, $c, $d) + }; +} + +fn macro_test() { + let _ = ipv4_new!(127, 0, 0, 1); + // no lint + let _ = ipv4_new!(255, 255, 255, 255); + // no lint + let _ = ipv4_new!(0, 0, 0, 0); + // no lint +} + +fn main() { + // UI Test +}
diff --git a/src/tools/clippy/tests/ui/ip_constant.stderr b/src/tools/clippy/tests/ui/ip_constant.stderr new file mode 100644 index 0000000..3e984c6 --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant.stderr
@@ -0,0 +1,338 @@ +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:8:13 + | +LL | let _ = Ipv4Addr::new(127, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::ip-constant` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ip_constant)]` +help: use + | +LL - let _ = Ipv4Addr::new(127, 0, 0, 1); +LL + let _ = Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:10:13 + | +LL | let _ = Ipv4Addr::new(255, 255, 255, 255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(255, 255, 255, 255); +LL + let _ = Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:12:13 + | +LL | let _ = Ipv4Addr::new(0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(0, 0, 0, 0); +LL + let _ = Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:16:13 + | +LL | let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:18:13 + | +LL | let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); +LL + let _ = Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:24:13 + | +LL | let _ = net::Ipv4Addr::new(127, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv4Addr::new(127, 0, 0, 1); +LL + let _ = net::Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:26:13 + | +LL | let _ = net::Ipv4Addr::new(255, 255, 255, 255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv4Addr::new(255, 255, 255, 255); +LL + let _ = net::Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:28:13 + | +LL | let _ = net::Ipv4Addr::new(0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv4Addr::new(0, 0, 0, 0); +LL + let _ = net::Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:31:13 + | +LL | let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = net::Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:33:13 + | +LL | let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); +LL + let _ = net::Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:38:13 + | +LL | let _ = std::net::Ipv4Addr::new(127, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv4Addr::new(127, 0, 0, 1); +LL + let _ = std::net::Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:40:13 + | +LL | let _ = std::net::Ipv4Addr::new(255, 255, 255, 255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv4Addr::new(255, 255, 255, 255); +LL + let _ = std::net::Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:42:13 + | +LL | let _ = std::net::Ipv4Addr::new(0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv4Addr::new(0, 0, 0, 0); +LL + let _ = std::net::Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:45:13 + | +LL | let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = std::net::Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:47:13 + | +LL | let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); +LL + let _ = std::net::Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:61:13 + | +LL | let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1); +LL + let _ = Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:63:13 + | +LL | let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255); +LL + let _ = Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:65:13 + | +LL | let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0); +LL + let _ = Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:69:13 + | +LL | let _ = Ipv6Addr::new( + | _____________^ +LL | | +LL | | CONST_U16_0, +LL | | CONST_U16_0, +... | +LL | | CONST_U16_1, +LL | | ); + | |_____^ + | +help: use + | +LL - let _ = Ipv6Addr::new( +LL - +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_1, +LL - ); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:81:13 + | +LL | let _ = Ipv6Addr::new( + | _____________^ +LL | | +LL | | CONST_U16_0, +LL | | CONST_U16_0, +... | +LL | | CONST_U16_0, +LL | | ); + | |_____^ + | +help: use + | +LL - let _ = Ipv6Addr::new( +LL - +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - ); +LL + let _ = Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:96:13 + | +LL | let _ = Ipv4Addr::new(126 + 1, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(126 + 1, 0, 0, 1); +LL + let _ = Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:98:13 + | +LL | let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255); +LL + let _ = Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:100:13 + | +LL | let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 }); +LL + let _ = Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:104:13 + | +LL | let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:106:13 + | +LL | let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: aborting due to 25 previous errors +
diff --git a/src/tools/clippy/tests/ui/ip_constant_from_external.rs b/src/tools/clippy/tests/ui/ip_constant_from_external.rs new file mode 100644 index 0000000..7fd2702 --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant_from_external.rs
@@ -0,0 +1,12 @@ +//@error-in-other-file: hand-coded well-known IP address +//@no-rustfix +#![warn(clippy::ip_constant)] + +fn external_constant_test() { + let _ = include!("localhost.txt"); + // lint in external file `localhost.txt` +} + +fn main() { + external_constant_test(); +}
diff --git a/src/tools/clippy/tests/ui/ip_constant_from_external.stderr b/src/tools/clippy/tests/ui/ip_constant_from_external.stderr new file mode 100644 index 0000000..99dd827 --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant_from_external.stderr
@@ -0,0 +1,16 @@ +error: hand-coded well-known IP address + --> tests/ui/localhost.txt:1:1 + | +LL | std::net::Ipv4Addr::new(127, 0, 0, 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::ip-constant` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ip_constant)]` +help: use + | +LL - std::net::Ipv4Addr::new(127, 0, 0, 1) +LL + std::net::Ipv4Addr::LOCALHOST + | + +error: aborting due to 1 previous error +
diff --git a/src/tools/clippy/tests/ui/large_stack_frames.rs b/src/tools/clippy/tests/ui/large_stack_frames.rs index 3ed124f..132f145 100644 --- a/src/tools/clippy/tests/ui/large_stack_frames.rs +++ b/src/tools/clippy/tests/ui/large_stack_frames.rs
@@ -1,8 +1,7 @@ //@ normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR" //@ normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR" -#![allow(unused, incomplete_features)] +#![allow(unused)] #![warn(clippy::large_stack_frames)] -#![feature(unsized_locals)] use std::hint::black_box; @@ -11,11 +10,6 @@ fn generic<T: Default>() { black_box(&x); } -fn unsized_local() { - let x: dyn std::fmt::Display = *(Box::new(1) as Box<dyn std::fmt::Display>); - black_box(&x); -} - struct ArrayDefault<const N: usize>([u8; N]); impl<const N: usize> Default for ArrayDefault<N> {
diff --git a/src/tools/clippy/tests/ui/large_stack_frames.stderr b/src/tools/clippy/tests/ui/large_stack_frames.stderr index 0ff49e9..79482e6 100644 --- a/src/tools/clippy/tests/ui/large_stack_frames.stderr +++ b/src/tools/clippy/tests/ui/large_stack_frames.stderr
@@ -1,5 +1,5 @@ error: this function may allocate 250$PTR bytes on the stack - --> tests/ui/large_stack_frames.rs:27:4 + --> tests/ui/large_stack_frames.rs:21:4 | LL | fn many_small_arrays() { | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]` error: this function may allocate 1000000 bytes on the stack - --> tests/ui/large_stack_frames.rs:38:4 + --> tests/ui/large_stack_frames.rs:32:4 | LL | fn large_return_value() -> ArrayDefault<1_000_000> { | ^^^^^^^^^^^^^^^^^^ ----------------------- this is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>` @@ -21,7 +21,7 @@ = note: 1000000 bytes is larger than Clippy's configured `stack-size-threshold` of 512000 error: this function may allocate 100$PTR bytes on the stack - --> tests/ui/large_stack_frames.rs:44:4 + --> tests/ui/large_stack_frames.rs:38:4 | LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) { | ^^^^^^^^^^^^ - `x` is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>` @@ -29,7 +29,7 @@ = note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000 error: this function may allocate 100$PTR bytes on the stack - --> tests/ui/large_stack_frames.rs:51:13 + --> tests/ui/large_stack_frames.rs:45:13 | LL | let f = || black_box(&[0u8; 1_000_000]); | ^^^^^^^^^^^^^^----------------^
diff --git a/src/tools/clippy/tests/ui/localhost.txt b/src/tools/clippy/tests/ui/localhost.txt new file mode 100644 index 0000000..4502ec2 --- /dev/null +++ b/src/tools/clippy/tests/ui/localhost.txt
@@ -0,0 +1 @@ +std::net::Ipv4Addr::new(127, 0, 0, 1) \ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/manual_flatten.fixed b/src/tools/clippy/tests/ui/manual_flatten.fixed new file mode 100644 index 0000000..cc1fbd2 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_flatten.fixed
@@ -0,0 +1,148 @@ +#![warn(clippy::manual_flatten)] +#![allow(clippy::useless_vec, clippy::uninlined_format_args)] + +fn main() { + // Test for loop over implicitly adjusted `Iterator` with `if let` expression + let x = vec![Some(1), Some(2), Some(3)]; + for y in x.into_iter().flatten() { + println!("{}", y); + } + + // Test for loop over implicitly adjusted `Iterator` with `if let` statement + let y: Vec<Result<i32, i32>> = vec![]; + for n in y.clone().into_iter().flatten() { + println!("{}", n); + } + + // Test for loop over by reference + for n in y.iter().flatten() { + println!("{}", n); + } + + // Test for loop over an implicit reference + let z = &y; + for n in z.iter().flatten() { + println!("{}", n); + } + + // Test for loop over `Iterator` with `if let` expression + let z = vec![Some(1), Some(2), Some(3)]; + let z = z.iter(); + for m in z.flatten() { + println!("{}", m); + } + + // Using the `None` variant should not trigger the lint + // Note: for an autofixable suggestion, the binding in the for loop has to take the + // name of the binding in the `if let` + let z = vec![Some(1), Some(2), Some(3)]; + for n in z { + if n.is_none() { + println!("Nada."); + } + } + + // Using the `Err` variant should not trigger the lint + for n in y.clone() { + if let Err(e) = n { + println!("Oops: {}!", e); + } + } + + // Having an else clause should not trigger the lint + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + } else { + println!("Oops!"); + } + } + + let vec_of_ref = vec![&Some(1)]; + for n in vec_of_ref.iter().copied().flatten() { + println!("{:?}", n); + } + + let vec_of_ref = &vec_of_ref; + for n in vec_of_ref.iter().copied().flatten() { + println!("{:?}", n); + } + + let slice_of_ref = &[&Some(1)]; + for n in slice_of_ref.iter().copied().flatten() { + println!("{:?}", n); + } + + struct Test { + a: usize, + } + + let mut vec_of_struct = [Some(Test { a: 1 }), None]; + + // Usage of `if let` expression should not trigger lint + for n in vec_of_struct.iter_mut() { + if let Some(z) = n { + *n = None; + } + } + + // Using manual flatten should not trigger the lint + for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { + println!("{}", n); + } + + // Using nested `Some` pattern should not trigger the lint + for n in vec![Some((1, Some(2)))] { + if let Some((_, Some(n))) = n { + println!("{}", n); + } + } + + macro_rules! inner { + ($id:ident / $new:pat => $action:expr) => { + if let Some($new) = $id { + $action; + } + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for ab in [Some((1, 2)), Some((3, 4))] { + inner!(ab / (c, d) => println!("{c}-{d}")); + } + + macro_rules! args { + ($($arg:expr),*) => { + vec![$(Some($arg)),*] + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for n in args!(1, 2, 3) { + if let Some(n) = n { + println!("{:?}", n); + } + } + + // This should trigger the lint, but the applicability is `MaybeIncorrect` + let z = vec![Some(1), Some(2), Some(3)]; + for n in z.into_iter().flatten() { + println!("{:?}", n); + } + + run_unformatted_tests(); +} + +#[rustfmt::skip] +fn run_unformatted_tests() { + // Skip rustfmt here on purpose so the suggestion does not fit in one line + for n in vec![ + //~^ manual_flatten + + Some(1), + Some(2), + Some(3) + ].iter().flatten() { + println!("{:?}", n); + } +}
diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs index f1a0053..53b4ac7 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.rs +++ b/src/tools/clippy/tests/ui/manual_flatten.rs
@@ -1,6 +1,6 @@ #![warn(clippy::manual_flatten)] #![allow(clippy::useless_vec, clippy::uninlined_format_args)] -//@no-rustfix + fn main() { // Test for loop over implicitly adjusted `Iterator` with `if let` expression let x = vec![Some(1), Some(2), Some(3)]; @@ -130,6 +130,43 @@ struct Test { } } + macro_rules! inner { + ($id:ident / $new:pat => $action:expr) => { + if let Some($new) = $id { + $action; + } + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for ab in [Some((1, 2)), Some((3, 4))] { + inner!(ab / (c, d) => println!("{c}-{d}")); + } + + macro_rules! args { + ($($arg:expr),*) => { + vec![$(Some($arg)),*] + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for n in args!(1, 2, 3) { + if let Some(n) = n { + println!("{:?}", n); + } + } + + // This should trigger the lint, but the applicability is `MaybeIncorrect` + let z = vec![Some(1), Some(2), Some(3)]; + for n in z { + //~^ manual_flatten + + if let Some(n) = n { + println!("{:?}", n); + } + // foo + } + run_unformatted_tests(); }
diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr index 9a846fe..eb39ee4 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.stderr +++ b/src/tools/clippy/tests/ui/manual_flatten.stderr
@@ -1,10 +1,7 @@ error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:7:5 | -LL | for n in x { - | ^ - help: try: `x.into_iter().flatten()` - | _____| - | | +LL | / for n in x { LL | | LL | | LL | | if let Some(y) = n { @@ -12,7 +9,7 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:10:9 | LL | / if let Some(y) = n { @@ -21,14 +18,17 @@ | |_________^ = note: `-D clippy::manual-flatten` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_flatten)]` +help: try + | +LL ~ for y in x.into_iter().flatten() { +LL + println!("{}", y); +LL + } + | error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> tests/ui/manual_flatten.rs:17:5 | -LL | for n in y.clone() { - | ^ --------- help: try: `y.clone().into_iter().flatten()` - | _____| - | | +LL | / for n in y.clone() { LL | | LL | | LL | | if let Ok(n) = n { @@ -37,21 +37,24 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:20:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); LL | | }; | |_________^ +help: try + | +LL ~ for n in y.clone().into_iter().flatten() { +LL + println!("{}", n); +LL + } + | error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> tests/ui/manual_flatten.rs:26:5 | -LL | for n in &y { - | ^ -- help: try: `y.iter().flatten()` - | _____| - | | +LL | / for n in &y { LL | | LL | | LL | | if let Ok(n) = n { @@ -59,21 +62,24 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:29:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in y.iter().flatten() { +LL + println!("{}", n); +LL + } + | error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> tests/ui/manual_flatten.rs:36:5 | -LL | for n in z { - | ^ - help: try: `z.iter().flatten()` - | _____| - | | +LL | / for n in z { LL | | LL | | LL | | if let Ok(n) = n { @@ -81,21 +87,24 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:39:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in z.iter().flatten() { +LL + println!("{}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:47:5 | -LL | for n in z { - | ^ - help: try: `z.flatten()` - | _____| - | | +LL | / for n in z { LL | | LL | | LL | | if let Some(m) = n { @@ -103,21 +112,24 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:50:9 | LL | / if let Some(m) = n { LL | | println!("{}", m); LL | | } | |_________^ +help: try + | +LL ~ for m in z.flatten() { +LL + println!("{}", m); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:82:5 | -LL | for n in &vec_of_ref { - | ^ ----------- help: try: `vec_of_ref.iter().copied().flatten()` - | _____| - | | +LL | / for n in &vec_of_ref { LL | | LL | | LL | | if let Some(n) = n { @@ -125,21 +137,24 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:85:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in vec_of_ref.iter().copied().flatten() { +LL + println!("{:?}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:91:5 | -LL | for n in vec_of_ref { - | ^ ---------- help: try: `vec_of_ref.iter().copied().flatten()` - | _____| - | | +LL | / for n in vec_of_ref { LL | | LL | | LL | | if let Some(n) = n { @@ -147,21 +162,24 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:94:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in vec_of_ref.iter().copied().flatten() { +LL + println!("{:?}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:100:5 | -LL | for n in slice_of_ref { - | ^ ------------ help: try: `slice_of_ref.iter().copied().flatten()` - | _____| - | | +LL | / for n in slice_of_ref { LL | | LL | | LL | | if let Some(n) = n { @@ -169,16 +187,47 @@ LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:103:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in slice_of_ref.iter().copied().flatten() { +LL + println!("{:?}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:139:5 + --> tests/ui/manual_flatten.rs:161:5 + | +LL | / for n in z { +LL | | +LL | | +LL | | if let Some(n) = n { +... | +LL | | } + | |_____^ + | +help: try `.flatten()` and remove the `if let` statement in the for loop + --> tests/ui/manual_flatten.rs:164:9 + | +LL | / if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } + | |_________^ +help: try + | +LL ~ for n in z.into_iter().flatten() { +LL + println!("{:?}", n); +LL + } + | + +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> tests/ui/manual_flatten.rs:176:5 | LL | / for n in vec![ LL | | @@ -188,8 +237,8 @@ LL | | } | |_____^ | -help: remove the `if let` statement in the for loop and then... - --> tests/ui/manual_flatten.rs:146:9 +help: try `.flatten()` and remove the `if let` statement in the for loop + --> tests/ui/manual_flatten.rs:183:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); @@ -201,7 +250,9 @@ ... LL | Some(3) LL ~ ].iter().flatten() { +LL + println!("{:?}", n); +LL + } | -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed index 28466ff..6cd81ba 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed
@@ -55,3 +55,14 @@ let i2 = 1; v.swap(i1 + i2, i2); } + +fn issue_14931() { + let mut v = [1, 2, 3, 4]; + + let mut i1 = 0; + for i2 in 0..4 { + v.swap(i1, i2); + + i1 += 2; + } +}
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs index c9880e6..19dabfd 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs
@@ -78,3 +78,17 @@ fn swap8() { v[i1 + i2] = v[i2]; v[i2] = tmp; } + +fn issue_14931() { + let mut v = [1, 2, 3, 4]; + + let mut i1 = 0; + for i2 in 0..4 { + let tmp = v[i1]; + //~^ manual_swap + v[i1] = v[i2]; + v[i2] = tmp; + + i1 += 2; + } +}
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr index 7ab898f..a0bb322 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr
@@ -92,5 +92,14 @@ LL | | v[i2] = tmp; | |________________^ help: try: `v.swap(i1 + i2, i2);` -error: aborting due to 8 previous errors +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:87:9 + | +LL | / let tmp = v[i1]; +LL | | +LL | | v[i1] = v[i2]; +LL | | v[i2] = tmp; + | |____________________^ help: try: `v.swap(i1, i2);` + +error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed index bdf3979..e11dea3 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -188,3 +188,19 @@ let id!(_a) = dbg!(b + 1); //~^^^ match_single_binding } + +mod issue14991 { + struct AnnoConstWOBlock { + inner: [(); { + let _n = 1; + 42 + }], + } + + struct AnnoConstWBlock { + inner: [(); { + let _n = 1; + 42 + }], + } +}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs index 419ff95..d498da3 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.rs +++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -249,3 +249,21 @@ macro_rules! id { }; //~^^^ match_single_binding } + +mod issue14991 { + struct AnnoConstWOBlock { + inner: [(); match 1 { + //~^ match_single_binding + _n => 42, + }], + } + + struct AnnoConstWBlock { + inner: [(); { + match 1 { + //~^ match_single_binding + _n => 42, + } + }], + } +}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr index bdd0134..f274f80 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -378,5 +378,38 @@ LL + let id!(_a) = dbg!(b + 1); | -error: aborting due to 27 previous errors +error: this match could be written as a `let` statement + --> tests/ui/match_single_binding.rs:255:21 + | +LL | inner: [(); match 1 { + | _____________________^ +LL | | +LL | | _n => 42, +LL | | }], + | |_________^ + | +help: consider using a `let` statement + | +LL ~ inner: [(); { +LL + let _n = 1; +LL + 42 +LL ~ }], + | + +error: this match could be written as a `let` statement + --> tests/ui/match_single_binding.rs:263:13 + | +LL | / match 1 { +LL | | +LL | | _n => 42, +LL | | } + | |_____________^ + | +help: consider using a `let` statement + | +LL ~ let _n = 1; +LL + 42 + | + +error: aborting due to 29 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 new file mode 100644 index 0000000..7e0d4fc --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
@@ -0,0 +1,36 @@ +#![feature(const_trait_impl)] +#![warn(clippy::missing_const_for_fn)] + +// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 + +#[const_trait] +trait ConstTrait { + fn method(self); +} + +impl ConstTrait for u32 { + fn method(self) {} +} + +impl const ConstTrait for u64 { + fn method(self) {} +} + +fn cannot_be_const() { + 0u32.method(); +} + +//~v missing_const_for_fn +const fn can_be_const() { + 0u64.method(); +} + +// False negative, see FIXME comment in `clipy_utils::qualify_min_const` +fn could_be_const_but_does_not_trigger<T>(t: T) +where + T: const ConstTrait, +{ + t.method(); +} + +fn main() {}
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 new file mode 100644 index 0000000..439da46 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
@@ -0,0 +1,36 @@ +#![feature(const_trait_impl)] +#![warn(clippy::missing_const_for_fn)] + +// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 + +#[const_trait] +trait ConstTrait { + fn method(self); +} + +impl ConstTrait for u32 { + fn method(self) {} +} + +impl const ConstTrait for u64 { + fn method(self) {} +} + +fn cannot_be_const() { + 0u32.method(); +} + +//~v missing_const_for_fn +fn can_be_const() { + 0u64.method(); +} + +// False negative, see FIXME comment in `clipy_utils::qualify_min_const` +fn could_be_const_but_does_not_trigger<T>(t: T) +where + T: const ConstTrait, +{ + t.method(); +} + +fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr new file mode 100644 index 0000000..b994b88 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr
@@ -0,0 +1,17 @@ +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/const_trait.rs:24:1 + | +LL | / fn can_be_const() { +LL | | 0u64.method(); +LL | | } + | |_^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const fn can_be_const() { + | +++++ + +error: aborting due to 1 previous error +
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index ceea448..15ca409 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - mismatched_lifetime_syntaxes, + mismatched_lifetime_syntaxes )] extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index 8432f9e..af9649d 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - mismatched_lifetime_syntaxes, + mismatched_lifetime_syntaxes )] extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed index 23dbee5..6915e19 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
@@ -195,3 +195,19 @@ //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } + +// #14574, check that partial_cmp invokes other.cmp + +#[derive(Eq, PartialEq)] +struct L(u32); + +impl Ord for L { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for L { + //~^ non_canonical_partial_ord_impl + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } +}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs index 12f055a..7ce4cdc 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
@@ -201,3 +201,21 @@ fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Ordering::Greater.into() } } + +// #14574, check that partial_cmp invokes other.cmp + +#[derive(Eq, PartialEq)] +struct L(u32); + +impl Ord for L { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for L { + //~^ non_canonical_partial_ord_impl + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(other.cmp(self)) + } +}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr index c7de968..9bd6b1f 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
@@ -44,5 +44,18 @@ LL | | } | |__^ -error: aborting due to 3 previous errors +error: non-canonical implementation of `partial_cmp` on an `Ord` type + --> tests/ui/non_canonical_partial_ord_impl.rs:216:1 + | +LL | / impl PartialOrd for L { +LL | | +LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + | | _____________________________________________________________- +LL | || Some(other.cmp(self)) +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(other)) }` +LL | | } + | |__^ + +error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/pointer_format.rs b/src/tools/clippy/tests/ui/pointer_format.rs new file mode 100644 index 0000000..0621f96 --- /dev/null +++ b/src/tools/clippy/tests/ui/pointer_format.rs
@@ -0,0 +1,66 @@ +#![warn(clippy::pointer_format)] + +use core::fmt::Debug; +use core::marker::PhantomData; + +#[derive(Debug)] +struct ContainsPointerDeep { + w: WithPointer, +} + +struct ManualDebug { + ptr: *const u8, +} + +#[derive(Debug)] +struct WithPointer { + len: usize, + ptr: *const u8, +} + +impl std::fmt::Debug for ManualDebug { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("ManualDebug") + } +} + +trait Foo { + type Assoc: Foo + Debug; +} + +#[derive(Debug)] +struct S<T: Foo + 'static>(&'static S<T::Assoc>, PhantomData<T>); + +#[allow(unused)] +fn unbounded<T: Foo + Debug + 'static>(s: &S<T>) { + format!("{s:?}"); +} + +fn main() { + let m = &(main as fn()); + let g = &0; + let o = &format!("{m:p}"); + //~^ pointer_format + let _ = format!("{m:?}"); + //~^ pointer_format + println!("{g:p}"); + //~^ pointer_format + panic!("{o:p}"); + //~^ pointer_format + let answer = 42; + let x = &raw const answer; + let arr = [0u8; 8]; + let with_ptr = WithPointer { len: 8, ptr: &arr as _ }; + let _ = format!("{x:?}"); + //~^ pointer_format + print!("{with_ptr:?}"); + //~^ pointer_format + let container = ContainsPointerDeep { w: with_ptr }; + print!("{container:?}"); + //~^ pointer_format + + let no_pointer = "foo"; + println!("{no_pointer:?}"); + let manual_debug = ManualDebug { ptr: &arr as _ }; + println!("{manual_debug:?}"); +}
diff --git a/src/tools/clippy/tests/ui/pointer_format.stderr b/src/tools/clippy/tests/ui/pointer_format.stderr new file mode 100644 index 0000000..21ba39b --- /dev/null +++ b/src/tools/clippy/tests/ui/pointer_format.stderr
@@ -0,0 +1,47 @@ +error: pointer formatting detected + --> tests/ui/pointer_format.rs:42:23 + | +LL | let o = &format!("{m:p}"); + | ^^^^^ + | + = note: `-D clippy::pointer-format` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pointer_format)]` + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:44:22 + | +LL | let _ = format!("{m:?}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:46:15 + | +LL | println!("{g:p}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:48:13 + | +LL | panic!("{o:p}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:54:22 + | +LL | let _ = format!("{x:?}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:56:13 + | +LL | print!("{with_ptr:?}"); + | ^^^^^^^^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:59:13 + | +LL | print!("{container:?}"); + | ^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors +
diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed index 24c45a4..ebfe19c 100644 --- a/src/tools/clippy/tests/ui/print_literal.fixed +++ b/src/tools/clippy/tests/ui/print_literal.fixed
@@ -94,3 +94,14 @@ " ); } + +fn issue_14930() { + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal +}
diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs index 42ae589..8f3d9be 100644 --- a/src/tools/clippy/tests/ui/print_literal.rs +++ b/src/tools/clippy/tests/ui/print_literal.rs
@@ -95,3 +95,14 @@ fn issue_13959() { "# ); } + +fn issue_14930() { + println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + //~^ print_literal + println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + //~^ print_literal + println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + //~^ print_literal + println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + //~^ print_literal +}
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr index da66300..1c37801 100644 --- a/src/tools/clippy/tests/ui/print_literal.stderr +++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -229,5 +229,53 @@ LL ~ " | -error: aborting due to 18 previous errors +error: literal with an empty format string + --> tests/ui/print_literal.rs:100:52 + | +LL | println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + | ^^^ + | +help: try + | +LL - println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:102:49 + | +LL | println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + | ^^^ + | +help: try + | +LL - println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:104:46 + | +LL | println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + | ^^^ + | +help: try + | +LL - println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:106:40 + | +LL | println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + | ^^^ + | +help: try + | +LL - println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed index 52fae9a..a3be80b 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed
@@ -96,3 +96,28 @@ unit_fn_block() } + +fn issue14926() { + macro_rules! gen_code { + [$l:lifetime: $b:block, $b2: block $(,)?] => { + $l: loop { + $b + break $l; + } + $l: loop { + $b2 + break $l; + } + }; + } + + gen_code! { + 'root: + { + println!("Block1"); + }, + { + println!("Block2"); + }, + } +}
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.rs b/src/tools/clippy/tests/ui/semicolon_outside_block.rs index 5975e66..3b7bf68 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.rs
@@ -96,3 +96,28 @@ fn main() { unit_fn_block() } + +fn issue14926() { + macro_rules! gen_code { + [$l:lifetime: $b:block, $b2: block $(,)?] => { + $l: loop { + $b + break $l; + } + $l: loop { + $b2 + break $l; + } + }; + } + + gen_code! { + 'root: + { + println!("Block1"); + }, + { + println!("Block2"); + }, + } +}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed index ab2e801..1820ade 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed +++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -90,3 +90,9 @@ #[clippy::msrv = "1.77"] fn msrv_1_77(_: core::net::IpAddr) {} //~^ std_instead_of_core + +#[warn(clippy::std_instead_of_core)] +#[rustfmt::skip] +fn issue14982() { + use std::{collections::HashMap, hash::Hash}; +}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs index f760b35..32c4933 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -90,3 +90,9 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: std::net::IpAddr) {} //~^ std_instead_of_core + +#[warn(clippy::std_instead_of_core)] +#[rustfmt::skip] +fn issue14982() { + use std::{collections::HashMap, hash::Hash}; +}
diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 22a6a26..4208efa 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs
@@ -151,3 +151,27 @@ fn main() { bad(); ok(); } + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn some_other_fn(_: &i32) {} + + macro_rules! mac { + (def) => { + Default::default() + }; + (func $f:expr) => { + $f() + }; + (nonempty_block $e:expr) => {{ + some_other_fn(&$e); + $e + }}; + } + fn_take_unit(mac!(def)); + //~^ unit_arg + fn_take_unit(mac!(func Default::default)); + //~^ unit_arg + fn_take_unit(mac!(nonempty_block Default::default())); + //~^ unit_arg +}
diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 6c333d9..0dcfb02 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -199,5 +199,26 @@ LL + Some(()) | -error: aborting due to 10 previous errors +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:171:5 + | +LL | fn_take_unit(mac!(def)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:173:5 + | +LL | fn_take_unit(mac!(func Default::default)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:175:5 + | +LL | fn_take_unit(mac!(nonempty_block Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed deleted file mode 100644 index b045a33..0000000 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed +++ /dev/null
@@ -1,34 +0,0 @@ -#![warn(clippy::unit_arg)] -#![allow(unused_must_use, unused_variables)] -#![allow(clippy::no_effect, clippy::uninlined_format_args)] - -use std::fmt::Debug; - -fn foo<T: Debug>(t: T) { - println!("{:?}", t); -} - -fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { - println!("{:?}, {:?}, {:?}", t1, t2, t3); -} - -fn bad() { - foo(()); - //~^ unit_arg - foo3((), 2, 2); - //~^ unit_arg - foo(0); - taking_two_units((), ()); - //~^ unit_arg - foo(0); - foo(1); - taking_three_units((), (), ()); - //~^ unit_arg -} - -fn taking_two_units(a: (), b: ()) {} -fn taking_three_units(a: (), b: (), c: ()) {} - -fn main() { - bad(); -}
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs deleted file mode 100644 index ab30591..0000000 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs +++ /dev/null
@@ -1,31 +0,0 @@ -#![warn(clippy::unit_arg)] -#![allow(unused_must_use, unused_variables)] -#![allow(clippy::no_effect, clippy::uninlined_format_args)] - -use std::fmt::Debug; - -fn foo<T: Debug>(t: T) { - println!("{:?}", t); -} - -fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { - println!("{:?}, {:?}, {:?}", t1, t2, t3); -} - -fn bad() { - foo({}); - //~^ unit_arg - foo3({}, 2, 2); - //~^ unit_arg - taking_two_units({}, foo(0)); - //~^ unit_arg - taking_three_units({}, foo(0), foo(1)); - //~^ unit_arg -} - -fn taking_two_units(a: (), b: ()) {} -fn taking_three_units(a: (), b: (), c: ()) {} - -fn main() { - bad(); -}
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr deleted file mode 100644 index 2c686d5..0000000 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr +++ /dev/null
@@ -1,46 +0,0 @@ -error: passing a unit value to a function - --> tests/ui/unit_arg_empty_blocks.rs:16:5 - | -LL | foo({}); - | ^^^^--^ - | | - | help: use a unit literal instead: `()` - | - = note: `-D clippy::unit-arg` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` - -error: passing a unit value to a function - --> tests/ui/unit_arg_empty_blocks.rs:18:5 - | -LL | foo3({}, 2, 2); - | ^^^^^--^^^^^^^ - | | - | help: use a unit literal instead: `()` - -error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:20:5 - | -LL | taking_two_units({}, foo(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: move the expression in front of the call and replace it with the unit literal `()` - | -LL ~ foo(0); -LL ~ taking_two_units((), ()); - | - -error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:22:5 - | -LL | taking_three_units({}, foo(0), foo(1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: move the expressions in front of the call and replace them with the unit literal `()` - | -LL ~ foo(0); -LL + foo(1); -LL ~ taking_three_units((), (), ()); - | - -error: aborting due to 4 previous errors -
diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.fixed b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed new file mode 100644 index 0000000..03353a1 --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed
@@ -0,0 +1,78 @@ +#![warn(clippy::unit_arg)] +#![allow(unused_must_use, unused_variables)] +#![allow(clippy::no_effect, clippy::uninlined_format_args)] + +use std::fmt::Debug; + +fn foo<T: Debug>(t: T) { + println!("{:?}", t); +} + +fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo(()); + //~^ unit_arg + foo3((), 2, 2); + //~^ unit_arg + foo(0); + taking_two_units((), ()); + //~^ unit_arg + foo(0); + foo(1); + taking_three_units((), (), ()); + //~^ unit_arg +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn_take_unit(()); + //~^ unit_arg + + fn some_other_fn(_: &i32) {} + + macro_rules! another_mac { + () => { + some_other_fn(&Default::default()) + }; + ($e:expr) => { + some_other_fn(&$e) + }; + } + + another_mac!(); + fn_take_unit(()); + //~^ unit_arg + another_mac!(1); + fn_take_unit(()); + //~^ unit_arg + + macro_rules! mac { + (nondef $e:expr) => { + $e + }; + (empty_block) => {{}}; + } + fn_take_unit(mac!(nondef ())); + //~^ unit_arg + mac!(empty_block); + fn_take_unit(()); + //~^ unit_arg + + fn def<T: Default>() -> T { + Default::default() + } + + let _: () = def(); + fn_take_unit(()); + //~^ unit_arg +}
diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.rs b/src/tools/clippy/tests/ui/unit_arg_fixable.rs new file mode 100644 index 0000000..03fd96e --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.rs
@@ -0,0 +1,71 @@ +#![warn(clippy::unit_arg)] +#![allow(unused_must_use, unused_variables)] +#![allow(clippy::no_effect, clippy::uninlined_format_args)] + +use std::fmt::Debug; + +fn foo<T: Debug>(t: T) { + println!("{:?}", t); +} + +fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo({}); + //~^ unit_arg + foo3({}, 2, 2); + //~^ unit_arg + taking_two_units({}, foo(0)); + //~^ unit_arg + taking_three_units({}, foo(0), foo(1)); + //~^ unit_arg +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn_take_unit(Default::default()); + //~^ unit_arg + + fn some_other_fn(_: &i32) {} + + macro_rules! another_mac { + () => { + some_other_fn(&Default::default()) + }; + ($e:expr) => { + some_other_fn(&$e) + }; + } + + fn_take_unit(another_mac!()); + //~^ unit_arg + fn_take_unit(another_mac!(1)); + //~^ unit_arg + + macro_rules! mac { + (nondef $e:expr) => { + $e + }; + (empty_block) => {{}}; + } + fn_take_unit(mac!(nondef Default::default())); + //~^ unit_arg + fn_take_unit(mac!(empty_block)); + //~^ unit_arg + + fn def<T: Default>() -> T { + Default::default() + } + + fn_take_unit(def()); + //~^ unit_arg +}
diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.stderr b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr new file mode 100644 index 0000000..ccd5aa8 --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr
@@ -0,0 +1,110 @@ +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:16:5 + | +LL | foo({}); + | ^^^^--^ + | | + | help: use a unit literal instead: `()` + | + = note: `-D clippy::unit-arg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:18:5 + | +LL | foo3({}, 2, 2); + | ^^^^^--^^^^^^^ + | | + | help: use a unit literal instead: `()` + +error: passing unit values to a function + --> tests/ui/unit_arg_fixable.rs:20:5 + | +LL | taking_two_units({}, foo(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ foo(0); +LL ~ taking_two_units((), ()); + | + +error: passing unit values to a function + --> tests/ui/unit_arg_fixable.rs:22:5 + | +LL | taking_three_units({}, foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call and replace them with the unit literal `()` + | +LL ~ foo(0); +LL + foo(1); +LL ~ taking_three_units((), (), ()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:35:5 + | +LL | fn_take_unit(Default::default()); + | ^^^^^^^^^^^^^------------------^ + | | + | help: use a unit literal instead: `()` + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:49:5 + | +LL | fn_take_unit(another_mac!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ another_mac!(); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:51:5 + | +LL | fn_take_unit(another_mac!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ another_mac!(1); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:60:5 + | +LL | fn_take_unit(mac!(nondef Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^------------------^^ + | | + | help: use a unit literal instead: `()` + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:62:5 + | +LL | fn_take_unit(mac!(empty_block)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ mac!(empty_block); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:69:5 + | +LL | fn_take_unit(def()); + | ^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ let _: () = def(); +LL ~ fn_take_unit(()); + | + +error: aborting due to 10 previous errors +
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed index 93dd58b..def8ef8 100644 --- a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
@@ -143,4 +143,10 @@ todo!() } } -} \ No newline at end of file +} + +mod pr14962 { + #[allow(unused_parens)] + type UnusedParensButNoUnit = Box<dyn (Fn())>; +} +
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed index 987d901..f908b95 100644 --- a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
@@ -143,4 +143,10 @@ todo!() } } -} \ No newline at end of file +} + +mod pr14962 { + #[allow(unused_parens)] + type UnusedParensButNoUnit = Box<dyn (Fn())>; +} +
diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs index b7645f7..7298ec4 100644 --- a/src/tools/clippy/tests/ui/unused_unit.rs +++ b/src/tools/clippy/tests/ui/unused_unit.rs
@@ -143,4 +143,10 @@ fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) { todo!() } } -} \ No newline at end of file +} + +mod pr14962 { + #[allow(unused_parens)] + type UnusedParensButNoUnit = Box<dyn (Fn())>; +} +
diff --git a/src/tools/clippy/tests/ui/write_literal.fixed b/src/tools/clippy/tests/ui/write_literal.fixed index e84f768..29352fd 100644 --- a/src/tools/clippy/tests/ui/write_literal.fixed +++ b/src/tools/clippy/tests/ui/write_literal.fixed
@@ -87,3 +87,15 @@ " ); } + +fn issue_14930() { + let mut v = Vec::new(); + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal +}
diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs index fc29fcb..9287275 100644 --- a/src/tools/clippy/tests/ui/write_literal.rs +++ b/src/tools/clippy/tests/ui/write_literal.rs
@@ -88,3 +88,15 @@ fn issue_13959() { "# ); } + +fn issue_14930() { + let mut v = Vec::new(); + writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + //~^ write_literal + writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + //~^ write_literal + writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + //~^ write_literal + writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + //~^ write_literal +}
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr index d53c2a7..ca37406 100644 --- a/src/tools/clippy/tests/ui/write_literal.stderr +++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -181,5 +181,53 @@ LL ~ " | -error: aborting due to 14 previous errors +error: literal with an empty format string + --> tests/ui/write_literal.rs:94:55 + | +LL | writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/write_literal.rs:96:52 + | +LL | writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/write_literal.rs:98:49 + | +LL | writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/write_literal.rs:100:43 + | +LL | writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs index 395f9dd..e81b5fd 100644 --- a/src/tools/clippy/tests/ui/zombie_processes.rs +++ b/src/tools/clippy/tests/ui/zombie_processes.rs
@@ -198,3 +198,13 @@ fn foo() { child.wait().unwrap(); } } + +fn issue14911() -> std::io::Result<String> { + let (mut recv, send) = std::io::pipe()?; + let mut command = Command::new("ls") + .stdout(send.try_clone()?) + .spawn() + .expect("Could not spawn new process..."); + command.wait()?; + Ok("".into()) +}
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index fec8839..285aa34 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js
@@ -602,7 +602,7 @@ updateLintCount(); function updateLintCount() { - const allLints = filters.getAllLints(); + const allLints = filters.getAllLints().filter(lint => lint.group != "deprecated"); const totalLints = allLints.length; const countElement = document.getElementById("lint-count");
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 81f5679..202582b 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs
@@ -29,6 +29,7 @@ fn path_div() -> &'static str { pub fn logv(config: &Config, s: String) { debug!("{}", s); if config.verbose { + // Note: `./x test ... --verbose --no-capture` is needed to see this print. println!("{}", s); } }
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index fc7942a..5554c79 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md
@@ -286,6 +286,11 @@ specific circumstances, but Miri's behavior will also be more stable across versions and targets. This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0 -Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`. +* `-Zmiri-deterministic-floats` makes Miri's floating-point behavior fully deterministic. This means + that operations will always return the preferred NaN, imprecise operations will not have any + random error applied to them, and `min`/`max` as "maybe fused" multiply-add all behave + deterministically. Note that Miri still uses host floats for some operations, so behavior can + still differ depending on the host target and setup. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness.
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 2faaec5..d4ba7fb 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs
@@ -601,6 +601,8 @@ fn main() { miri_config.collect_leak_backtraces = false; } else if arg == "-Zmiri-force-intrinsic-fallback" { miri_config.force_intrinsic_fallback = true; + } else if arg == "-Zmiri-deterministic-floats" { + miri_config.float_nondet = false; } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; } else if arg == "-Zmiri-permissive-provenance" {
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 6f5f756..7a5f96e 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs
@@ -166,6 +166,8 @@ pub struct MiriConfig { pub fixed_scheduling: bool, /// Always prefer the intrinsic fallback body over the native Miri implementation. pub force_intrinsic_fallback: bool, + /// Whether floating-point operations can behave non-deterministically. + pub float_nondet: bool, } impl Default for MiriConfig { @@ -205,6 +207,7 @@ fn default() -> MiriConfig { address_reuse_cross_thread_rate: 0.1, fixed_scheduling: false, force_intrinsic_fallback: false, + float_nondet: true, } } }
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9957e35..458b772 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -272,8 +272,7 @@ fn emulate_intrinsic_by_name( let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft(); + let res = a.mul_add(b, c).value; let res = this.adjust_nan(res, &[a, b, c]); this.write_scalar(res, dest)?; } @@ -282,8 +281,7 @@ fn emulate_intrinsic_by_name( let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft(); + let res = a.mul_add(b, c).value; let res = this.adjust_nan(res, &[a, b, c]); this.write_scalar(res, dest)?; } @@ -293,10 +291,9 @@ fn emulate_intrinsic_by_name( let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; - let fuse: bool = this.machine.rng.get_mut().random(); + let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); let res = if fuse { - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value }; @@ -308,10 +305,9 @@ fn emulate_intrinsic_by_name( let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; - let fuse: bool = this.machine.rng.get_mut().random(); + let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); let res = if fuse { - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value };
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index b17fd4f..dbe193b 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -306,7 +306,8 @@ enum Op { let c = this.read_scalar(&this.project_index(&c, i)?)?; let dest = this.project_index(&dest, i)?; - let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().random(); + let fuse: bool = intrinsic_name == "fma" + || (this.machine.float_nondet && this.machine.rng.get_mut().random()); // Works for f32 and f64. // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468. @@ -320,7 +321,7 @@ enum Op { let b = b.to_f32()?; let c = c.to_f32()?; let res = if fuse { - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value }; @@ -332,7 +333,7 @@ enum Op { let b = b.to_f64()?; let c = c.to_f64()?; let res = if fuse { - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value };
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 344e12e..048ed81 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs
@@ -16,7 +16,7 @@ #![feature(unqualified_local_imports)] #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] -#![feature(file_lock)] +#![cfg_attr(bootstrap, feature(file_lock))] // Configure clippy and other lints #![allow( clippy::collapsible_else_if,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index b221dd8..b4d7db3 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs
@@ -618,6 +618,9 @@ pub struct MiriMachine<'tcx> { /// Always prefer the intrinsic fallback body over the native Miri implementation. pub force_intrinsic_fallback: bool, + + /// Whether floating-point operations can behave non-deterministically. + pub float_nondet: bool, } impl<'tcx> MiriMachine<'tcx> { @@ -778,6 +781,7 @@ pub(crate) fn new( int2ptr_warned: Default::default(), mangle_internal_symbol_cache: Default::default(), force_intrinsic_fallback: config.force_intrinsic_fallback, + float_nondet: config.float_nondet, } } @@ -956,6 +960,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) { int2ptr_warned: _, mangle_internal_symbol_cache: _, force_intrinsic_fallback: _, + float_nondet: _, } = self; threads.visit_provenance(visit);
diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index d1355a2..cf16a56 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs
@@ -15,6 +15,10 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>( val: F, err_scale: i32, ) -> F { + if !ecx.machine.float_nondet { + return val; + } + let rng = ecx.machine.rng.get_mut(); // Generate a random integer in the range [0, 2^PREC). // (When read as binary, the position of the first `1` determines the exponent,
diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 81f22b2..73d6711 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs
@@ -76,6 +76,11 @@ fn binary_ptr_op( } fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 { + let this = self.eval_context_ref(); + if !this.machine.float_nondet { + return F2::NAN; + } + /// Make the given NaN a signaling NaN. /// Returns `None` if this would not result in a NaN. fn make_signaling<F: Float>(f: F) -> Option<F> { @@ -89,7 +94,6 @@ fn make_signaling<F: Float>(f: F) -> Option<F> { if f.is_nan() { Some(f) } else { None } } - let this = self.eval_context_ref(); let mut rand = this.machine.rng.borrow_mut(); // Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation. // On some targets there are more possibilities; for now we just generate those options that @@ -118,6 +122,9 @@ fn make_signaling<F: Float>(f: F) -> Option<F> { fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F { let this = self.eval_context_ref(); + if !this.machine.float_nondet { + return a; + } // Return one side non-deterministically. let mut rand = this.machine.rng.borrow_mut(); if rand.random() { a } else { b }
diff --git a/src/tools/miri/tests/fail/unsized-local.rs b/src/tools/miri/tests/fail/unsized-local.rs deleted file mode 100644 index ceccae4..0000000 --- a/src/tools/miri/tests/fail/unsized-local.rs +++ /dev/null
@@ -1,23 +0,0 @@ -#![feature(unsized_locals)] -#![allow(incomplete_features)] - -fn main() { - pub trait Foo { - fn foo(self) -> String; - } - - struct A; - - impl Foo for A { - fn foo(self) -> String { - format!("hello") - } - } - - let x = *(Box::new(A) as Box<dyn Foo>); //~ERROR: unsized locals are not supported - assert_eq!(x.foo(), format!("hello")); - - // I'm not sure whether we want this to work - let x = Box::new(A) as Box<dyn Foo>; - assert_eq!(x.foo(), format!("hello")); -}
diff --git a/src/tools/miri/tests/fail/unsized-local.stderr b/src/tools/miri/tests/fail/unsized-local.stderr deleted file mode 100644 index 548f3d6..0000000 --- a/src/tools/miri/tests/fail/unsized-local.stderr +++ /dev/null
@@ -1,14 +0,0 @@ -error: unsupported operation: unsized locals are not supported - --> tests/fail/unsized-local.rs:LL:CC - | -LL | let x = *(Box::new(A) as Box<dyn Foo>); - | ^ unsized locals are not supported - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support - = note: BACKTRACE: - = note: inside `main` at tests/fail/unsized-local.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error -
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 2f30827..9d57257 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -2,7 +2,6 @@ #![feature(io_error_more)] #![feature(io_error_uncategorized)] -#![feature(file_lock)] use std::collections::BTreeMap; use std::ffi::OsString;
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 3e9d792..045f2f06 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt
@@ -754,7 +754,6 @@ ui/consts/issue-47789.rs ui/consts/issue-50439.rs ui/consts/issue-52023-array-size-pointer-cast.rs -ui/consts/issue-54224.rs ui/consts/issue-54348.rs ui/consts/issue-54387.rs ui/consts/issue-54582.rs
diff --git a/tests/assembly/asm/loongarch-type.rs b/tests/assembly/asm/loongarch-type.rs index 86d9e03..c782be1 100644 --- a/tests/assembly/asm/loongarch-type.rs +++ b/tests/assembly/asm/loongarch-type.rs
@@ -4,7 +4,7 @@ //@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: loongarch -#![feature(no_core)] +#![feature(no_core, f16)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -69,6 +69,12 @@ pub unsafe fn $func(x: $ty) -> $ty { // CHECK: #NO_APP check!(reg_i16, i16, reg, "move"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16, f16, reg, "move"); + // CHECK-LABEL: reg_i32: // CHECK: #APP // CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} @@ -99,6 +105,12 @@ pub unsafe fn $func(x: $ty) -> $ty { // CHECK: #NO_APP check!(reg_ptr, ptr, reg, "move"); +// CHECK-LABEL: freg_f16: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f16, f16, freg, "fmov.s"); + // CHECK-LABEL: freg_f32: // CHECK: #APP // CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} @@ -123,6 +135,12 @@ pub unsafe fn $func(x: $ty) -> $ty { // CHECK: #NO_APP check_reg!(r4_i16, i16, "$r4", "move"); +// CHECK-LABEL: r4_f16: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_f16, f16, "$r4", "move"); + // CHECK-LABEL: r4_i32: // CHECK: #APP // CHECK: move $a0, $a0 @@ -153,6 +171,12 @@ pub unsafe fn $func(x: $ty) -> $ty { // CHECK: #NO_APP check_reg!(r4_ptr, ptr, "$r4", "move"); +// CHECK-LABEL: f0_f16: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check_reg!(f0_f16, f16, "$f0", "fmov.s"); + // CHECK-LABEL: f0_f32: // CHECK: #APP // CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
diff --git a/tests/assembly/pic-relocation-model.rs b/tests/assembly/pic-relocation-model.rs index d35cd96..15a8723 100644 --- a/tests/assembly/pic-relocation-model.rs +++ b/tests/assembly/pic-relocation-model.rs
@@ -19,7 +19,7 @@ pub fn call_other_fn() -> u8 { } // CHECK-LABEL: other_fn: -// CHECK: callq *foreign_fn@GOTPCREL(%rip) +// CHECK: {{(jmpq|callq)}} *foreign_fn@GOTPCREL(%rip) #[no_mangle] #[inline(never)] pub fn other_fn() -> u8 {
diff --git a/tests/assembly/pie-relocation-model.rs b/tests/assembly/pie-relocation-model.rs index 5c74b34..cbe0001 100644 --- a/tests/assembly/pie-relocation-model.rs +++ b/tests/assembly/pie-relocation-model.rs
@@ -22,7 +22,7 @@ pub fn call_other_fn() -> u8 { // CHECK-LABEL: other_fn: // External functions are still called through GOT, since we don't know if the symbol // is defined in the binary or in the shared library. -// CHECK: callq *foreign_fn@GOTPCREL(%rip) +// CHECK: {{(jmpq|callq)}} *foreign_fn@GOTPCREL(%rip) #[no_mangle] #[inline(never)] pub fn other_fn() -> u8 {
diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs index 2a82517..3287e01 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs
@@ -10,8 +10,8 @@ //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled #![crate_type = "lib"] -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![allow(internal_features)] +#![feature(unsized_fn_params)] // CHECK-LABEL: emptyfn: #[no_mangle] @@ -357,27 +357,3 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } - -// CHECK-LABEL: unsized_local -#[no_mangle] -pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) { - let n = if l { 1 } else { 2 }; - let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from - f(&mut a); - - // This function allocates a slice as a local variable in its stack - // frame. Since the size is not a compile-time constant, an array - // alloca is required, and the function is protected by both the - // `strong` and `basic` heuristic. - - // We should have a __security_check_cookie call in `all`, `strong` and `basic` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -}
diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs index 9729da4..9a3dabc 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs
@@ -10,8 +10,7 @@ //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled #![crate_type = "lib"] -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![feature(unsized_fn_params)] // CHECK-LABEL: emptyfn: #[no_mangle] @@ -365,27 +364,3 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } - -// CHECK-LABEL: unsized_local -#[no_mangle] -pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) { - let n = if l { 1 } else { 2 }; - let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from - f(&mut a); - - // This function allocates a slice as a local variable in its stack - // frame. Since the size is not a compile-time constant, an array - // alloca is required, and the function is protected by both the - // `strong` and `basic` heuristic. - - // We should have a __security_check_cookie call in `all`, `strong` and `basic` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -}
diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs index 91c83fa..ae281cb 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs
@@ -16,8 +16,8 @@ // See comments on https://github.com/rust-lang/rust/issues/114903. #![crate_type = "lib"] -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![allow(internal_features)] +#![feature(unsized_fn_params)] // CHECK-LABEL: emptyfn{{:|\[}} #[no_mangle] @@ -343,22 +343,3 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } - -// CHECK-LABEL: unsized_local{{:|\[}} -#[no_mangle] -pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) { - let n = if l { 1 } else { 2 }; - let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from - f(&mut a); - - // This function allocates a slice as a local variable in its stack - // frame. Since the size is not a compile-time constant, an array - // alloca is required, and the function is protected by both the - // `strong` and `basic` heuristic. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -}
diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs new file mode 100644 index 0000000..c354228 --- /dev/null +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs
@@ -0,0 +1,31 @@ +//@ compile-flags: -Copt-level=2 + +#![crate_type = "lib"] +#![no_std] + +// This test is paired with the arch-specific -opt3.rs test. + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +}
diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs new file mode 100644 index 0000000..203d120 --- /dev/null +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs
@@ -0,0 +1,42 @@ +//@ revisions: AARCH64 X86_64 Z13 +//@ compile-flags: -Copt-level=3 +//@[AARCH64] only-aarch64 +//@[X86_64] only-x86_64 +//@[Z13] only-s390x +//@[Z13] compile-flags: -Ctarget-cpu=z13 + +#![crate_type = "lib"] +#![no_std] + +// This test is paired with the arch-neutral -opt2.rs test + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector + +// On higher opt levels, this should just be a bswap: +// CHECK: load <8 x i16> +// CHECK-NEXT: call <8 x i16> @llvm.bswap +// CHECK-NEXT: store <8 x i16> +// CHECK-NEXT: ret void +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +}
diff --git a/tests/codegen/deduced-param-attrs.rs b/tests/codegen/deduced-param-attrs.rs index 22db090..34504c8 100644 --- a/tests/codegen/deduced-param-attrs.rs +++ b/tests/codegen/deduced-param-attrs.rs
@@ -1,8 +1,8 @@ //@ compile-flags: -Copt-level=3 #![crate_type = "lib"] -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![allow(internal_features)] +#![feature(unsized_fn_params)] use std::cell::Cell; use std::hint;
diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/dont-shuffle-bswaps.rs deleted file mode 100644 index c1dab2b..0000000 --- a/tests/codegen/dont-shuffle-bswaps.rs +++ /dev/null
@@ -1,44 +0,0 @@ -//@ revisions: OPT2 OPT3 OPT3_S390X -//@[OPT2] compile-flags: -Copt-level=2 -//@[OPT3] compile-flags: -C opt-level=3 -// some targets don't do the opt we are looking for -//@[OPT3] only-64bit -//@[OPT3] ignore-s390x -//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13 -//@[OPT3_S390X] only-s390x - -#![crate_type = "lib"] -#![no_std] - -// The code is from https://github.com/rust-lang/rust/issues/122805. -// Ensure we do not generate the shufflevector instruction -// to avoid complicating the code. -// CHECK-LABEL: define{{.*}}void @convert( -// CHECK-NOT: shufflevector -// On higher opt levels, this should just be a bswap: -// OPT3: load <8 x i16> -// OPT3-NEXT: call <8 x i16> @llvm.bswap -// OPT3-NEXT: store <8 x i16> -// OPT3-NEXT: ret void -// OPT3_S390X: load <8 x i16> -// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap -// OPT3_S390X-NEXT: store <8 x i16> -// OPT3_S390X-NEXT: ret void -#[no_mangle] -pub fn convert(value: [u16; 8]) -> [u8; 16] { - #[cfg(target_endian = "little")] - let bswap = u16::to_be; - #[cfg(target_endian = "big")] - let bswap = u16::to_le; - let addr16 = [ - bswap(value[0]), - bswap(value[1]), - bswap(value[2]), - bswap(value[3]), - bswap(value[4]), - bswap(value[5]), - bswap(value[6]), - bswap(value[7]), - ]; - unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } -}
diff --git a/tests/codegen/pie-relocation-model.rs b/tests/codegen/pie-relocation-model.rs index b10af69..cb8de91 100644 --- a/tests/codegen/pie-relocation-model.rs +++ b/tests/codegen/pie-relocation-model.rs
@@ -13,7 +13,7 @@ pub fn call_foreign_fn() -> u8 { // External functions are still marked as non-dso_local, since we don't know if the symbol // is defined in the binary or in the shared library. -// CHECK: declare zeroext i8 @foreign_fn() +// CHECK: declare i8 @foreign_fn() extern "C" { fn foreign_fn() -> u8; }
diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs new file mode 100644 index 0000000..915c2c3 --- /dev/null +++ b/tests/codegen/retpoline.rs
@@ -0,0 +1,27 @@ +// ignore-tidy-linelength +// Test that the +// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls` +// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set. + +//@ add-core-stubs +//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [enabled_retpoline] compile-flags: -Zretpoline +//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] +extern crate minicore; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} } + + // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } + // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } +}
diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs index d2d0c4b..2660447 100644 --- a/tests/codegen/virtual-function-elimination.rs +++ b/tests/codegen/virtual-function-elimination.rs
@@ -6,8 +6,6 @@ // CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]] #![crate_type = "lib"] -#![allow(incomplete_features)] -#![feature(unsized_locals)] use std::rc::Rc;
diff --git a/tests/crashes/137188.rs b/tests/crashes/137188.rs deleted file mode 100644 index fdd098d..0000000 --- a/tests/crashes/137188.rs +++ /dev/null
@@ -1,6 +0,0 @@ -//@ known-bug: #137188 -#![feature(min_generic_const_args)] -trait Trait {} -impl Trait for [(); N] {} -fn N<T>() {} -pub fn main() {}
diff --git a/tests/crashes/138166.rs b/tests/crashes/138166.rs deleted file mode 100644 index 98003bd..0000000 --- a/tests/crashes/138166.rs +++ /dev/null
@@ -1,8 +0,0 @@ -//@ known-bug: #138166 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -struct a(Box<[u8; Box::b]>); -impl a { - fn c(self) { self.0.d() } -} -fn main() {}
diff --git a/tests/crashes/138240.rs b/tests/crashes/138240.rs deleted file mode 100644 index 6ffb786..0000000 --- a/tests/crashes/138240.rs +++ /dev/null
@@ -1,9 +0,0 @@ -//@ known-bug: #138240 -//@edition:2024 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -async fn _CF() -> Box<[u8; Box::b]> { - Box::new(true) -} - -fn main() {}
diff --git a/tests/crashes/138266.rs b/tests/crashes/138266.rs deleted file mode 100644 index 9a4de9a..0000000 --- a/tests/crashes/138266.rs +++ /dev/null
@@ -1,7 +0,0 @@ -//@ known-bug: #138266 -//@compile-flags: --crate-type=lib -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -pub fn f(mut x: [u8; Box::b]) { - x[72] = 1; -}
diff --git a/tests/crashes/138359.rs b/tests/crashes/138359.rs deleted file mode 100644 index d4376d5..0000000 --- a/tests/crashes/138359.rs +++ /dev/null
@@ -1,8 +0,0 @@ -//@ known-bug: #138359 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -struct a(Box<[u8; Box::b]>); -impl a { - fn c(self) { self.0.da } -} -fn main() {}
diff --git a/tests/crashes/140531.rs b/tests/crashes/140531.rs deleted file mode 100644 index f664481..0000000 --- a/tests/crashes/140531.rs +++ /dev/null
@@ -1,7 +0,0 @@ -//@ known-bug: #140531 -//@compile-flags: -Zlint-mir --crate-type lib -//@ edition:2024 -#![feature(async_drop)] -async fn call_once(f: impl AsyncFnOnce()) { - let fut = Box::pin(f()); -}
diff --git a/tests/crashes/79409.rs b/tests/crashes/79409.rs deleted file mode 100644 index 98b5f60..0000000 --- a/tests/crashes/79409.rs +++ /dev/null
@@ -1,16 +0,0 @@ -//@ known-bug: #79409 - -#![feature(extern_types)] -#![feature(unsized_locals)] - -extern { - type Device; -} - -unsafe fn make_device() -> Box<Device> { - Box::from_raw(0 as *mut _) -} - -fn main() { - let d: Device = unsafe { *make_device() }; -}
diff --git "a/tests/mir-opt/async_drop_live_dead.a-\173closure\0430\175.coroutine_drop_async.0.panic-abort.mir" "b/tests/mir-opt/async_drop_live_dead.a-\173closure\0430\175.coroutine_drop_async.0.panic-abort.mir" new file mode 100644 index 0000000..347e411 --- /dev/null +++ "b/tests/mir-opt/async_drop_live_dead.a-\173closure\0430\175.coroutine_drop_async.0.panic-abort.mir"
@@ -0,0 +1,100 @@ +// MIR for `a::{closure#0}` 0 coroutine_drop_async + +fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> { + debug _task_context => _19; + debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T); + let mut _0: std::task::Poll<()>; + let _3: T; + let mut _4: impl std::future::Future<Output = ()>; + let mut _5: &mut T; + let mut _6: std::pin::Pin<&mut T>; + let mut _7: &mut T; + let mut _8: *mut T; + let mut _9: (); + let mut _10: std::task::Poll<()>; + let mut _11: &mut std::task::Context<'_>; + let mut _12: &mut impl std::future::Future<Output = ()>; + let mut _13: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; + let mut _14: isize; + let mut _15: &mut std::task::Context<'_>; + let mut _16: &mut impl std::future::Future<Output = ()>; + let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; + let mut _18: isize; + let mut _19: &mut std::task::Context<'_>; + let mut _20: u32; + scope 1 { + debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T); + } + + bb0: { + _20 = discriminant((*(_1.0: &mut {async fn body of a<T>()}))); + switchInt(move _20) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14]; + } + + bb1: { + nop; + nop; + goto -> bb2; + } + + bb2: { + _0 = Poll::<()>::Ready(const ()); + return; + } + + bb3: { + _0 = Poll::<()>::Pending; + discriminant((*(_1.0: &mut {async fn body of a<T>()}))) = 4; + return; + } + + bb4: { + StorageLive(_17); + _16 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>); + _17 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _16) -> [return: bb7, unwind unreachable]; + } + + bb5: { + unreachable; + } + + bb6: { + StorageDead(_17); + _18 = discriminant(_10); + switchInt(move _18) -> [0: bb1, 1: bb3, otherwise: bb5]; + } + + bb7: { + _10 = <impl Future<Output = ()> as Future>::poll(move _17, move _15) -> [return: bb6, unwind unreachable]; + } + + bb8: { + _0 = Poll::<()>::Ready(const ()); + return; + } + + bb9: { + goto -> bb11; + } + + bb10: { + goto -> bb8; + } + + bb11: { + drop(((*(_1.0: &mut {async fn body of a<T>()})).0: T)) -> [return: bb10, unwind unreachable]; + } + + bb12: { + goto -> bb4; + } + + bb13: { + goto -> bb4; + } + + bb14: { + _0 = Poll::<()>::Ready(const ()); + return; + } +}
diff --git "a/tests/mir-opt/async_drop_live_dead.a-\173closure\0430\175.coroutine_drop_async.0.panic-unwind.mir" "b/tests/mir-opt/async_drop_live_dead.a-\173closure\0430\175.coroutine_drop_async.0.panic-unwind.mir" new file mode 100644 index 0000000..b1cf537 --- /dev/null +++ "b/tests/mir-opt/async_drop_live_dead.a-\173closure\0430\175.coroutine_drop_async.0.panic-unwind.mir"
@@ -0,0 +1,123 @@ +// MIR for `a::{closure#0}` 0 coroutine_drop_async + +fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> { + debug _task_context => _19; + debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T); + let mut _0: std::task::Poll<()>; + let _3: T; + let mut _4: impl std::future::Future<Output = ()>; + let mut _5: &mut T; + let mut _6: std::pin::Pin<&mut T>; + let mut _7: &mut T; + let mut _8: *mut T; + let mut _9: (); + let mut _10: std::task::Poll<()>; + let mut _11: &mut std::task::Context<'_>; + let mut _12: &mut impl std::future::Future<Output = ()>; + let mut _13: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; + let mut _14: isize; + let mut _15: &mut std::task::Context<'_>; + let mut _16: &mut impl std::future::Future<Output = ()>; + let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; + let mut _18: isize; + let mut _19: &mut std::task::Context<'_>; + let mut _20: u32; + scope 1 { + debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T); + } + + bb0: { + _20 = discriminant((*(_1.0: &mut {async fn body of a<T>()}))); + switchInt(move _20) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19]; + } + + bb1: { + nop; + nop; + goto -> bb2; + } + + bb2: { + _0 = Poll::<()>::Ready(const ()); + return; + } + + bb3 (cleanup): { + nop; + nop; + goto -> bb5; + } + + bb4 (cleanup): { + goto -> bb15; + } + + bb5 (cleanup): { + goto -> bb4; + } + + bb6: { + _0 = Poll::<()>::Pending; + discriminant((*(_1.0: &mut {async fn body of a<T>()}))) = 4; + return; + } + + bb7: { + StorageLive(_17); + _16 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>); + _17 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _16) -> [return: bb10, unwind: bb15]; + } + + bb8: { + unreachable; + } + + bb9: { + StorageDead(_17); + _18 = discriminant(_10); + switchInt(move _18) -> [0: bb1, 1: bb6, otherwise: bb8]; + } + + bb10: { + _10 = <impl Future<Output = ()> as Future>::poll(move _17, move _15) -> [return: bb9, unwind: bb3]; + } + + bb11: { + _0 = Poll::<()>::Ready(const ()); + return; + } + + bb12: { + goto -> bb14; + } + + bb13: { + goto -> bb11; + } + + bb14: { + drop(((*(_1.0: &mut {async fn body of a<T>()})).0: T)) -> [return: bb13, unwind: bb4]; + } + + bb15 (cleanup): { + discriminant((*(_1.0: &mut {async fn body of a<T>()}))) = 2; + resume; + } + + bb16: { + goto -> bb7; + } + + bb17: { + goto -> bb7; + } + + bb18: { + assert(const false, "`async fn` resumed after panicking") -> [success: bb18, unwind continue]; + } + + bb19: { + _0 = Poll::<()>::Ready(const ()); + return; + } +}
diff --git a/tests/mir-opt/async_drop_live_dead.rs b/tests/mir-opt/async_drop_live_dead.rs new file mode 100644 index 0000000..348866b --- /dev/null +++ b/tests/mir-opt/async_drop_live_dead.rs
@@ -0,0 +1,11 @@ +//@ edition:2024 +// skip-filecheck +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(async_drop)] +#![allow(incomplete_features)] + +// EMIT_MIR async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.mir +async fn a<T>(x: T) {} + +fn main() {}
diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff index 8ebd07b..e61a3e8 100644 --- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff
@@ -5,7 +5,7 @@ let mut _0: usize; bb0: { -- _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable]; +- _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable]; + _0 = AlignOf(T); + goto -> bb1; }
diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff index 8ebd07b..e61a3e8 100644 --- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff
@@ -5,7 +5,7 @@ let mut _0: usize; bb0: { -- _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable]; +- _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable]; + _0 = AlignOf(T); + goto -> bb1; }
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 1e4f202..7729e50 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs
@@ -51,7 +51,7 @@ pub fn size_of<T>() -> usize { pub fn align_of<T>() -> usize { // CHECK-LABEL: fn align_of( // CHECK: {{_.*}} = AlignOf(T); - core::intrinsics::min_align_of::<T>() + core::intrinsics::align_of::<T>() } // EMIT_MIR lower_intrinsics.forget.LowerIntrinsics.diff
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 30eafe8..2eee8a9 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
@@ -39,7 +39,7 @@ } scope 15 (inlined std::mem::size_of::<u8>) { } - scope 16 (inlined align_of::<u8>) { + scope 16 (inlined std::mem::align_of::<u8>) { } scope 17 (inlined slice_from_raw_parts::<u8>) { debug data => _3;
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 30eafe8..2eee8a9 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
@@ -39,7 +39,7 @@ } scope 15 (inlined std::mem::size_of::<u8>) { } - scope 16 (inlined align_of::<u8>) { + scope 16 (inlined std::mem::align_of::<u8>) { } scope 17 (inlined slice_from_raw_parts::<u8>) { debug data => _3;
diff --git a/tests/pretty/postfix-match/precedence.pp b/tests/pretty/postfix-match/precedence.pp index 967aa7b..2052b44 100644 --- a/tests/pretty/postfix-match/precedence.pp +++ b/tests/pretty/postfix-match/precedence.pp
@@ -26,7 +26,7 @@ _ => {} }; (4 as usize).match { _ => {} }; - (return).match { _ => {} }; + return.match { _ => {} }; (a = 42).match { _ => {} }; (|| {}).match { _ => {} }; (42..101).match { _ => {} };
diff --git a/tests/rustdoc-ui/extract-doctests-result.rs b/tests/rustdoc-ui/extract-doctests-result.rs new file mode 100644 index 0000000..88affb6 --- /dev/null +++ b/tests/rustdoc-ui/extract-doctests-result.rs
@@ -0,0 +1,11 @@ +// Test to ensure that it generates expected output for `--output-format=doctest` command-line +// flag. + +//@ compile-flags:-Z unstable-options --output-format=doctest +//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR" +//@ check-pass + +//! ``` +//! let x = 12; +//! Ok(()) +//! ```
diff --git a/tests/rustdoc-ui/extract-doctests-result.stdout b/tests/rustdoc-ui/extract-doctests-result.stdout new file mode 100644 index 0000000..44e6d33 --- /dev/null +++ b/tests/rustdoc-ui/extract-doctests-result.stdout
@@ -0,0 +1 @@ +{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests-result.rs","line":8,"doctest_attributes":{"original":"","should_panic":false,"no_run":false,"ignore":"None","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nOk(())","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nOk(())","wrapper":{"before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n","after":"\n} _inner().unwrap() }","returns_result":true}},"name":"$DIR/extract-doctests-result.rs - (line 8)"}]} \ No newline at end of file
diff --git a/tests/rustdoc-ui/extract-doctests.stdout b/tests/rustdoc-ui/extract-doctests.stdout index b11531b..796ecd8 100644 --- a/tests/rustdoc-ui/extract-doctests.stdout +++ b/tests/rustdoc-ui/extract-doctests.stdout
@@ -1 +1 @@ -{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]} \ No newline at end of file +{"format_version":2,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":{"crate_level":"#![allow(unused)]\n","code":"let x = 12;\nlet y = 14;","wrapper":{"before":"fn main() {\n","after":"\n}","returns_result":false}},"name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]} \ No newline at end of file
diff --git a/tests/rustdoc/cfg-bool.rs b/tests/rustdoc/cfg-bool.rs index 34fdfbe..0aaa132 100644 --- a/tests/rustdoc/cfg-bool.rs +++ b/tests/rustdoc/cfg-bool.rs
@@ -3,11 +3,15 @@ // regression test for https://github.com/rust-lang/rust/issues/138112 -//@ has 'foo/fn.foo.html' '//div[@class="stab portability"]' 'Available nowhere' +//@ has 'foo/index.html' +//@ has - '//*[@class="stab portability"]/@title' 'Available nowhere' + +//@ count 'foo/fn.foo.html' '//*[@class="stab portability"]' 1 +//@ has 'foo/fn.foo.html' '//*[@class="stab portability"]' 'Available nowhere' #[doc(cfg(false))] pub fn foo() {} -// a cfg(true) will simply be ommited, as it is the same as no cfg. -//@ !has 'foo/fn.bar.html' '//div[@class="stab portability"]' '' +// a cfg(true) will simply be omitted, as it is the same as no cfg. +//@ count 'foo/fn.bar.html' '//*[@class="stab portability"]' 0 #[doc(cfg(true))] pub fn bar() {}
diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html index 28f1552..4dcc811 100644 --- a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html +++ b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html
@@ -1,7 +1,7 @@ macro_rules! morestuff { ( - <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static - "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* + <= "space between most kinds of tokens" : 1 $x:ident + @ :: >>= + 'static "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* "space inside curly brace" : { 2 a } "no space inside empty delimiters" : () [] {} "no space before comma or semicolon" : a, (a), { a }, a; [T; 0];
diff --git a/tests/rustdoc/macro/macro-generated-macro.rs b/tests/rustdoc/macro/macro-generated-macro.rs index e77d0cf..dfb152b 100644 --- a/tests/rustdoc/macro/macro-generated-macro.rs +++ b/tests/rustdoc/macro/macro-generated-macro.rs
@@ -25,7 +25,7 @@ macro_rules! $macro_name { //@ snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text() make_macro!(morestuff - "space between most kinds of tokens": 1 $x + @ :: >>= 'static + "space between most kinds of tokens": 1 $x:ident + @ :: >>= 'static "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)* "space inside curly brace": { 2 a } "no space inside empty delimiters": () [] {}
diff --git a/tests/ui-fulldeps/auxiliary/parser.rs b/tests/ui-fulldeps/auxiliary/parser.rs index be51bd2..8a37051 100644 --- a/tests/ui-fulldeps/auxiliary/parser.rs +++ b/tests/ui-fulldeps/auxiliary/parser.rs
@@ -7,15 +7,17 @@ extern crate rustc_session; extern crate rustc_span; -use rustc_ast::ast::{DUMMY_NODE_ID, Expr}; -use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::ast::{AttrKind, Attribute, DUMMY_NODE_ID, Expr}; +use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::node_id::NodeId; use rustc_ast::ptr::P; -use rustc_ast::token; +use rustc_ast::token::{self, Token}; +use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, LazyAttrTokenStream}; use rustc_errors::Diag; use rustc_parse::parser::Recovery; use rustc_session::parse::ParseSess; -use rustc_span::{DUMMY_SP, FileName, Span}; +use rustc_span::{AttrId, DUMMY_SP, FileName, Span}; +use std::sync::Arc; pub fn parse_expr(psess: &ParseSess, source_code: &str) -> Option<P<Expr>> { let parser = rustc_parse::unwrap_or_emit_fatal(rustc_parse::new_parser_from_source_str( @@ -46,4 +48,36 @@ fn visit_id(&mut self, id: &mut NodeId) { fn visit_span(&mut self, span: &mut Span) { *span = DUMMY_SP; } + + fn visit_attribute(&mut self, attr: &mut Attribute) { + attr.id = AttrId::from_u32(0); + if let AttrKind::Normal(normal_attr) = &mut attr.kind { + if let Some(tokens) = &mut normal_attr.tokens { + let mut stream = tokens.to_attr_token_stream(); + normalize_attr_token_stream(&mut stream); + *tokens = LazyAttrTokenStream::new_direct(stream); + } + } + mut_visit::walk_attribute(self, attr); + } +} + +fn normalize_attr_token_stream(stream: &mut AttrTokenStream) { + Arc::make_mut(&mut stream.0) + .iter_mut() + .for_each(normalize_attr_token_tree); +} + +fn normalize_attr_token_tree(token: &mut AttrTokenTree) { + match token { + AttrTokenTree::Token(token, _spacing) => { + Normalize.visit_span(&mut token.span); + } + AttrTokenTree::Delimited(dspan, _spacing, _delim, stream) => { + normalize_attr_token_stream(stream); + Normalize.visit_span(&mut dspan.open); + Normalize.visit_span(&mut dspan.close); + } + AttrTokenTree::AttrsTarget(_) => unimplemented!("AttrTokenTree::AttrsTarget"), + } }
diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 656cfca..8449479 100644 --- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs
@@ -33,17 +33,10 @@ fn locale_resource(&self) -> &'static str { "" } - fn codegen_crate<'a, 'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: EncodedMetadata, - _need_metadata_module: bool, - ) -> Box<dyn Any> { + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> { Box::new(CodegenResults { modules: vec![], allocator_module: None, - metadata_module: None, - metadata, crate_info: CrateInfo::new(tcx, "fake_target_cpu".to_string()), }) } @@ -60,7 +53,13 @@ fn join_codegen( (*codegen_results, FxIndexMap::default()) } - fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) { + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + _metadata: EncodedMetadata, + outputs: &OutputFilenames, + ) { use std::io::Write; use rustc_session::config::{CrateType, OutFileName};
diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index c566ac4..08bed40 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
@@ -63,8 +63,8 @@ "(2 += 2) += 2", // Return has lower precedence than a binary operator. "(return 2) + 2", - "2 + (return 2)", // FIXME: no parenthesis needed. - "(return) + 2", // FIXME: no parenthesis needed. + "2 + return 2", + "return + 2", // These mean different things. "return - 2", "(return) - 2", @@ -88,6 +88,11 @@ // expressions. "match 2 { _ => 1 - 1 }", "match 2 { _ => ({ 1 }) - 1 }", + // Expressions with an outer attr have lower precedence than expressions + // with an inner attr. + "#[attr] loop {}.field", + "(#[attr] loop {}).field", + "loop { #![attr] }.field", // Grammar restriction: break value starting with a labeled loop is not // allowed, except if the break is also labeled. "break 'outer 'inner: loop {} + 2",
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 03fca17..001699b 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -583,18 +583,32 @@ | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | error: cannot find attribute `multipart_suggestion` in this scope --> $DIR/diagnostic-derive.rs:647:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | error: cannot find attribute `multipart_suggestion` in this scope --> $DIR/diagnostic-derive.rs:651:7 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated` --> $DIR/diagnostic-derive.rs:75:8
diff --git a/tests/ui-fulldeps/stable-mir/check_variant.rs b/tests/ui-fulldeps/stable-mir/check_variant.rs new file mode 100644 index 0000000..b0de336 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_variant.rs
@@ -0,0 +1,183 @@ +//@ run-pass +//! Test that users are able to use stable mir APIs to retrieve +//! discriminant value and type for AdtDef and Coroutine variants + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ edition: 2024 + +#![feature(rustc_private)] +#![feature(assert_matches)] + +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use std::io::Write; +use std::ops::ControlFlow; + +use stable_mir::CrateItem; +use stable_mir::crate_def::CrateDef; +use stable_mir::mir::{AggregateKind, Rvalue, Statement, StatementKind}; +use stable_mir::ty::{IntTy, RigidTy, Ty}; + +const CRATE_NAME: &str = "crate_variant_ty"; + +/// Test if we can retrieve discriminant info for different types. +fn test_def_tys() -> ControlFlow<()> { + check_adt_mono(); + check_adt_poly(); + check_adt_poly2(); + + ControlFlow::Continue(()) +} + +fn check_adt_mono() { + let mono = get_fn("mono").expect_body(); + + check_statement_is_aggregate_assign( + &mono.blocks[0].statements[0], + 0, + RigidTy::Int(IntTy::Isize), + ); + check_statement_is_aggregate_assign( + &mono.blocks[1].statements[0], + 1, + RigidTy::Int(IntTy::Isize), + ); + check_statement_is_aggregate_assign( + &mono.blocks[2].statements[0], + 2, + RigidTy::Int(IntTy::Isize), + ); +} + +fn check_adt_poly() { + let poly = get_fn("poly").expect_body(); + + check_statement_is_aggregate_assign( + &poly.blocks[0].statements[0], + 0, + RigidTy::Int(IntTy::Isize), + ); + check_statement_is_aggregate_assign( + &poly.blocks[1].statements[0], + 1, + RigidTy::Int(IntTy::Isize), + ); + check_statement_is_aggregate_assign( + &poly.blocks[2].statements[0], + 2, + RigidTy::Int(IntTy::Isize), + ); +} + +fn check_adt_poly2() { + let poly = get_fn("poly2").expect_body(); + + check_statement_is_aggregate_assign( + &poly.blocks[0].statements[0], + 0, + RigidTy::Int(IntTy::Isize), + ); + check_statement_is_aggregate_assign( + &poly.blocks[1].statements[0], + 1, + RigidTy::Int(IntTy::Isize), + ); + check_statement_is_aggregate_assign( + &poly.blocks[2].statements[0], + 2, + RigidTy::Int(IntTy::Isize), + ); +} + +fn get_fn(name: &str) -> CrateItem { + stable_mir::all_local_items().into_iter().find(|it| it.name().eq(name)).unwrap() +} + +fn check_statement_is_aggregate_assign( + statement: &Statement, + expected_discr_val: u128, + expected_discr_ty: RigidTy, +) { + if let Statement { kind: StatementKind::Assign(_, rvalue), .. } = statement + && let Rvalue::Aggregate(aggregate, _) = rvalue + && let AggregateKind::Adt(adt_def, variant_idx, ..) = aggregate + { + let discr = adt_def.discriminant_for_variant(*variant_idx); + + assert_eq!(discr.val, expected_discr_val); + assert_eq!(discr.ty, Ty::from_rigid_kind(expected_discr_ty)); + } else { + unreachable!("Unexpected statement"); + } +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "defs_ty_input.rs"; + generate_input(&path).unwrap(); + let args = &[ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_def_tys).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + use std::hint::black_box; + + enum Mono {{ + A, + B(i32), + C {{ a: i32, b: u32 }}, + }} + + enum Poly<T> {{ + A, + B(T), + C {{ t: T }}, + }} + + pub fn main() {{ + mono(); + poly(); + poly2::<i32>(1); + }} + + fn mono() {{ + black_box(Mono::A); + black_box(Mono::B(6)); + black_box(Mono::C {{a: 1, b: 10 }}); + }} + + fn poly() {{ + black_box(Poly::<i32>::A); + black_box(Poly::B(1i32)); + black_box(Poly::C {{ t: 1i32 }}); + }} + + fn poly2<T: Copy>(t: T) {{ + black_box(Poly::<T>::A); + black_box(Poly::B(t)); + black_box(Poly::C {{ t: t }}); + }} + "# + )?; + Ok(()) +}
diff --git a/tests/ui/abi/bad-custom.rs b/tests/ui/abi/bad-custom.rs new file mode 100644 index 0000000..e792f09 --- /dev/null +++ b/tests/ui/abi/bad-custom.rs
@@ -0,0 +1,121 @@ +//@ edition: 2021 +//@ check-fail +//@ needs-asm-support +#![feature(abi_custom)] + +#[unsafe(naked)] +extern "custom" fn must_be_unsafe(a: i64) -> i64 { + //~^ ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +#[unsafe(naked)] +unsafe extern "custom" fn no_parameters(a: i64) { + //~^ ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +#[unsafe(naked)] +unsafe extern "custom" fn no_return_type() -> i64 { + //~^ ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +unsafe extern "custom" fn double(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() +} + +struct Thing(i64); + +impl Thing { + unsafe extern "custom" fn is_even(self) -> bool { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() + } +} + +trait BitwiseNot { + unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() + } +} + +impl BitwiseNot for Thing {} + +trait Negate { + extern "custom" fn negate(a: i64) -> i64; + //~^ ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function +} + +impl Negate for Thing { + extern "custom" fn negate(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function + -a + } +} + +unsafe extern "custom" { + fn increment(a: i64) -> i64; + //~^ ERROR invalid signature for `extern "custom"` function + + safe fn extern_cannot_be_safe(); + //~^ ERROR foreign functions with the `"custom"` ABI cannot be safe +} + +fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +type Custom = unsafe extern "custom" fn(i64) -> i64; + +fn caller_alias(f: Custom, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +#[unsafe(naked)] +const unsafe extern "custom" fn no_const_fn() { + std::arch::naked_asm!("") + //~^ ERROR inline assembly is not allowed in constant functions +} + +async unsafe extern "custom" fn no_async_fn() { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR functions with the `"custom"` ABI cannot be `async` +} + +fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { + //~^ ERROR expected a `Fn()` closure, found `unsafe extern "custom" fn()` + f +} + +pub fn main() { + unsafe { + assert_eq!(double(21), 42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert_eq!(unsafe { increment(41) }, 42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert!(Thing(41).is_even()); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert_eq!(Thing::bitwise_not(42), !42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + } +}
diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr new file mode 100644 index 0000000..ec0f11a --- /dev/null +++ b/tests/ui/abi/bad-custom.stderr
@@ -0,0 +1,299 @@ +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:7:1 + | +LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:7:35 + | +LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn must_be_unsafe(a: i64) -> i64 { +LL + extern "custom" fn must_be_unsafe() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:14:41 + | +LL | unsafe extern "custom" fn no_parameters(a: i64) { + | ^^^^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn no_parameters(a: i64) { +LL + unsafe extern "custom" fn no_parameters() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:20:47 + | +LL | unsafe extern "custom" fn no_return_type() -> i64 { + | ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn no_return_type() -> i64 { +LL + unsafe extern "custom" fn no_return_type() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:25:34 + | +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn double(a: i64) -> i64 { +LL + unsafe extern "custom" fn double() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:34:39 + | +LL | unsafe extern "custom" fn is_even(self) -> bool { + | ^^^^ ^^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn is_even(self) -> bool { +LL + unsafe extern "custom" fn is_even() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:42:43 + | +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { +LL + unsafe extern "custom" fn bitwise_not() { + | + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:52:5 + | +LL | extern "custom" fn negate(a: i64) -> i64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn negate(a: i64) -> i64; + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:52:31 + | +LL | extern "custom" fn negate(a: i64) -> i64; + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn negate(a: i64) -> i64; +LL + extern "custom" fn negate(); + | + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:58:5 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn negate(a: i64) -> i64 { + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:58:31 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn negate(a: i64) -> i64 { +LL + extern "custom" fn negate() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:67:18 + | +LL | fn increment(a: i64) -> i64; + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - fn increment(a: i64) -> i64; +LL + fn increment(); + | + +error: foreign functions with the `"custom"` ABI cannot be safe + --> $DIR/bad-custom.rs:70:5 + | +LL | safe fn extern_cannot_be_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `safe` keyword from this definition + | +LL - safe fn extern_cannot_be_safe(); +LL + fn extern_cannot_be_safe(); + | + +error: functions with the `"custom"` ABI cannot be `async` + --> $DIR/bad-custom.rs:97:1 + | +LL | async unsafe extern "custom" fn no_async_fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `async` keyword from this definiton + | +LL - async unsafe extern "custom" fn no_async_fn() { +LL + unsafe extern "custom" fn no_async_fn() { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:97:1 + | +LL | async unsafe extern "custom" fn no_async_fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | async unsafe extern "custom" fn no_async_fn() { + | + +error[E0277]: expected a `Fn()` closure, found `unsafe extern "custom" fn()` + --> $DIR/bad-custom.rs:102:64 + | +LL | fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { + | ^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` +LL | +LL | f + | - return type was inferred to be `unsafe extern "custom" fn()` here + | + = help: the trait `Fn()` is not implemented for `unsafe extern "custom" fn()` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `unsafe extern "custom" fn()` in a closure with no arguments: `|| { /* code */ }` + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:25:1 + | +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:34:5 + | +LL | unsafe extern "custom" fn is_even(self) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn is_even(self) -> bool { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:42:5 + | +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:58:5 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | extern "custom" fn negate(a: i64) -> i64 { + | + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:75:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:80:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:87:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:109:20 + | +LL | assert_eq!(double(21), 42); + | ^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:112:29 + | +LL | assert_eq!(unsafe { increment(41) }, 42); + | ^^^^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:115:17 + | +LL | assert!(Thing(41).is_even()); + | ^^^^^^^^^^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:118:20 + | +LL | assert_eq!(Thing::bitwise_not(42), !42); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0015]: inline assembly is not allowed in constant functions + --> $DIR/bad-custom.rs:93:5 + | +LL | std::arch::naked_asm!("") + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 28 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/abi/custom.rs b/tests/ui/abi/custom.rs new file mode 100644 index 0000000..0f6ff77 --- /dev/null +++ b/tests/ui/abi/custom.rs
@@ -0,0 +1,88 @@ +// Test that `extern "custom"` functions can be called from assembly, and defined using a naked +// function, and `global_asm!` with an `extern "custom"` block. +// +//@ run-pass +//@ only-x86_64 +#![feature(abi_custom)] + +use std::arch::{asm, global_asm, naked_asm}; + +#[unsafe(naked)] +unsafe extern "custom" fn double() { + naked_asm!("add rax, rax", "ret"); +} + +global_asm!( + // work around macOS prefixing symbols with _ + " .globl {0}", + "{0}:", + " add rax, 1", + " ret", + sym increment, +); + +unsafe extern "custom" { + fn increment(); +} + +#[repr(transparent)] +struct Thing(u64); + +impl Thing { + #[unsafe(naked)] + unsafe extern "custom" fn is_even() { + naked_asm!("test al, 1", "sete al", "ret"); + } +} + +trait BitwiseNot { + #[unsafe(naked)] + unsafe extern "custom" fn bitwise_not() { + naked_asm!("not rax", "ret"); + } +} + +impl BitwiseNot for Thing {} + +#[unsafe(naked)] +unsafe extern "C" fn const_generic<const N: u64>() { + naked_asm!( + "mov rax, {}", + "ret", + const N, + ); +} + +pub fn main() { + let mut x: u64 = 21; + unsafe { asm!("call {}", sym double, inout("rax") x) }; + assert_eq!(x, 42); + + let mut x: u64 = 41; + unsafe { asm!("call {}", sym increment, inout("rax") x) }; + assert_eq!(x, 42); + + let mut x: u8; + unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) }; + assert!(x != 0); + + let mut x: u64 = 42; + unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) }; + assert_eq!(x, !42); + + // Create and call in `asm!` an `extern "custom"` function pointer. + fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 { + unsafe { asm!("call {}", in(reg) f, inout("rax") x) }; + x + } + + assert_eq!(caller(double, 2), 4); + + let x: u64; + unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) }; + assert_eq!(x, 42); + + let x: u64; + unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) }; + assert_eq!(x, 84); +}
diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr new file mode 100644 index 0000000..02015d2 --- /dev/null +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr
@@ -0,0 +1,536 @@ +error: fn_abi_of(i8) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + true, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776123356184577, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: i8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + true, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776123356184577, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 + | +LL | pub extern "sysv64" fn i8(x: i8) -> i8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(u8) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776127651151873, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776127651151873, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 + | +LL | pub extern "sysv64" fn u8(x: u8) -> u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(i16) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + true, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462603027808258, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: i16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + true, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462603027808258, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 + | +LL | pub extern "sysv64" fn i16(x: i16) -> i16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(u16) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + false, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462607322775554, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + false, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462607322775554, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 + | +LL | pub extern "sysv64" fn u16(x: u16) -> u16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(i32) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + true, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462603027873795, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: i32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + true, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462603027873795, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 + | +LL | pub extern "sysv64" fn i32(x: i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(u32) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462607322841091, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462607322841091, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 + | +LL | pub extern "sysv64" fn u32(x: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors +
diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr new file mode 100644 index 0000000..9bb2ab4 --- /dev/null +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr
@@ -0,0 +1,536 @@ +error: fn_abi_of(i8) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + true, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776123356184577, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: i8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + true, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776123356184577, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 + | +LL | pub extern "sysv64" fn i8(x: i8) -> i8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(u8) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776127651151873, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 71776127651151873, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 + | +LL | pub extern "sysv64" fn u8(x: u8) -> u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(i16) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + true, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462603027808258, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: i16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + true, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462603027808258, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 + | +LL | pub extern "sysv64" fn i16(x: i16) -> i16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(u16) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + false, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462607322775554, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u16, + layout: Layout { + size: Size(2 bytes), + align: AbiAlign { + abi: Align(2 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I16, + false, + ), + valid_range: 0..=65535, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(2 bytes), + randomization_seed: 18446462607322775554, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 + | +LL | pub extern "sysv64" fn u16(x: u16) -> u16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(i32) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + true, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462603027873795, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: i32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + true, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462603027873795, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 + | +LL | pub extern "sysv64" fn i32(x: i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(u32) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462607322841091, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: Size(4 bytes), + align: AbiAlign { + abi: Align(4 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=4294967295, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + randomization_seed: 18446462607322841091, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: X86( + SysV64, + ), + can_unwind: false, + } + --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 + | +LL | pub extern "sysv64" fn u32(x: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors +
diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.rs b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.rs new file mode 100644 index 0000000..29a3061 --- /dev/null +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.rs
@@ -0,0 +1,46 @@ +//@ only-x86_64 +//@ revisions: apple other +//@[apple] only-apple +//@[other] ignore-apple + +// Apple targets extend up to 32 bits for both arguments and returns, other targets only extend +// arguments. + +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +#[rustc_abi(debug)] +pub extern "sysv64" fn i8(x: i8) -> i8 { + //~^ ERROR fn_abi_of(i8) + x +} + +#[rustc_abi(debug)] +pub extern "sysv64" fn u8(x: u8) -> u8 { + //~^ ERROR fn_abi_of(u8) + x +} + +#[rustc_abi(debug)] +pub extern "sysv64" fn i16(x: i16) -> i16 { + //~^ ERROR fn_abi_of(i16) + x +} + +#[rustc_abi(debug)] +pub extern "sysv64" fn u16(x: u16) -> u16 { + //~^ ERROR fn_abi_of(u16) + x +} + +#[rustc_abi(debug)] +pub extern "sysv64" fn i32(x: i32) -> i32 { + //~^ ERROR fn_abi_of(i32) + x +} + +#[rustc_abi(debug)] +pub extern "sysv64" fn u32(x: u32) -> u32 { + //~^ ERROR fn_abi_of(u32) + x +}
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 22dca00..4721c26 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr
@@ -369,42 +369,6 @@ = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target --> $DIR/unsupported.rs:145:22 | @@ -437,15 +401,3 @@ = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default -
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 0ac6d88..ed9cd2a 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr
@@ -337,42 +337,6 @@ = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target --> $DIR/unsupported.rs:145:22 | @@ -405,15 +369,3 @@ = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default -
diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index ad57a89..9e75dfa 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr
@@ -337,42 +337,6 @@ = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target --> $DIR/unsupported.rs:145:22 | @@ -405,15 +369,3 @@ = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default -
diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index ad57a89..9e75dfa 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr
@@ -337,42 +337,6 @@ = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target --> $DIR/unsupported.rs:145:22 | @@ -405,15 +369,3 @@ = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default -
diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index f777fe8..5b55e57 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr
@@ -316,42 +316,6 @@ = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target --> $DIR/unsupported.rs:153:21 | @@ -373,15 +337,3 @@ = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default -
diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 328f4c3..93b5a27 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr
@@ -322,78 +322,6 @@ = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:112:19 - | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:119:1 - | -LL | extern "stdcall" {} - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:123:1 - | -LL | extern "stdcall-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target --> $DIR/unsupported.rs:153:21 | @@ -415,39 +343,3 @@ = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:171:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:108:1 - | -LL | extern "stdcall" fn stdcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default -
diff --git a/tests/ui/associated-types/associated-type-call.fixed b/tests/ui/associated-types/associated-type-call.fixed new file mode 100644 index 0000000..d450b3b --- /dev/null +++ b/tests/ui/associated-types/associated-type-call.fixed
@@ -0,0 +1,22 @@ +// issue: <https://github.com/rust-lang/rust/issues/142473> +// +//@ run-rustfix +#![allow(unused)] +struct T(); + +trait Trait { + type Assoc; + + fn f(); +} + +impl Trait for () { + type Assoc = T; + + fn f() { + T(); + //~^ ERROR no associated item named `Assoc` found for unit type `()` in the current scope + } +} + +fn main() {}
diff --git a/tests/ui/associated-types/associated-type-call.rs b/tests/ui/associated-types/associated-type-call.rs new file mode 100644 index 0000000..ffe540c --- /dev/null +++ b/tests/ui/associated-types/associated-type-call.rs
@@ -0,0 +1,22 @@ +// issue: <https://github.com/rust-lang/rust/issues/142473> +// +//@ run-rustfix +#![allow(unused)] +struct T(); + +trait Trait { + type Assoc; + + fn f(); +} + +impl Trait for () { + type Assoc = T; + + fn f() { + <Self>::Assoc(); + //~^ ERROR no associated item named `Assoc` found for unit type `()` in the current scope + } +} + +fn main() {}
diff --git a/tests/ui/associated-types/associated-type-call.stderr b/tests/ui/associated-types/associated-type-call.stderr new file mode 100644 index 0000000..eaef775 --- /dev/null +++ b/tests/ui/associated-types/associated-type-call.stderr
@@ -0,0 +1,15 @@ +error[E0599]: no associated item named `Assoc` found for unit type `()` in the current scope + --> $DIR/associated-type-call.rs:17:17 + | +LL | <Self>::Assoc(); + | ^^^^^ associated item not found in `()` + | +help: to construct a value of type `T`, use the explicit path + | +LL - <Self>::Assoc(); +LL + T(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/associated-types/associated-types-unsized.stderr b/tests/ui/associated-types/associated-types-unsized.stderr index e46b2a3..5a55e03 100644 --- a/tests/ui/associated-types/associated-types-unsized.stderr +++ b/tests/ui/associated-types/associated-types-unsized.stderr
@@ -6,7 +6,6 @@ | = help: the trait `Sized` is not implemented for `<T as Get>::Value` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type | LL | fn foo<T:Get>(t: T) where <T as Get>::Value: Sized {
diff --git a/tests/ui/async-await/async-drop/async-drop-initial.rs b/tests/ui/async-await/async-drop/async-drop-initial.rs index 263b706..cd33c14 100644 --- a/tests/ui/async-await/async-drop/async-drop-initial.rs +++ b/tests/ui/async-await/async-drop/async-drop-initial.rs
@@ -62,7 +62,7 @@ fn main() { test_async_drop(&j, 16).await; test_async_drop( AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, - if cfg!(panic = "unwind") { 168 } else { 136 }, + 136, ).await; test_async_drop(ManuallyDrop::new(AsyncInt(9)), 16).await;
diff --git a/tests/crashes/140429.rs b/tests/ui/async-await/async-drop/live-dead-storage.rs similarity index 62% rename from tests/crashes/140429.rs rename to tests/ui/async-await/async-drop/live-dead-storage.rs index 041eaf8..e6f25d3 100644 --- a/tests/crashes/140429.rs +++ b/tests/ui/async-await/async-drop/live-dead-storage.rs
@@ -1,6 +1,9 @@ -//@ known-bug: #140429 +// ex-ice: #140429 //@ compile-flags: -Zlint-mir --crate-type lib //@ edition:2024 +//@ check-pass #![feature(async_drop)] +#![allow(incomplete_features)] + async fn a<T>(x: T) {}
diff --git a/tests/ui/async-await/async-drop/live-dead-storage2.rs b/tests/ui/async-await/async-drop/live-dead-storage2.rs new file mode 100644 index 0000000..18df870 --- /dev/null +++ b/tests/ui/async-await/async-drop/live-dead-storage2.rs
@@ -0,0 +1,11 @@ +// ex-ice: #140531 +//@ compile-flags: -Zlint-mir --crate-type lib +//@ edition:2024 +//@ check-pass + +#![feature(async_drop)] +#![allow(incomplete_features)] + +async fn call_once(f: impl AsyncFnOnce()) { + let fut = Box::pin(f()); +}
diff --git a/tests/ui/async-await/async-drop/live-dead-storage3.rs b/tests/ui/async-await/async-drop/live-dead-storage3.rs new file mode 100644 index 0000000..d9fba57 --- /dev/null +++ b/tests/ui/async-await/async-drop/live-dead-storage3.rs
@@ -0,0 +1,56 @@ +// ex-ice: #141761 +//@ compile-flags: -Zlint-mir --crate-type lib +//@ edition:2024 +//@ check-pass + +#![feature(async_drop)] +#![allow(incomplete_features)] + +type BoxFuture<T> = std::pin::Pin<Box<dyn Future<Output = T>>>; +fn main() {} +async fn f() { + run("").await +} +struct InMemoryStorage; +struct User<'dep> { + dep: &'dep str, +} +impl<'a> StorageRequest<InMemoryStorage> for SaveUser<'a> { + fn execute(&self) -> BoxFuture<Result<(), String>> { + todo!() + } +} +trait Storage { + type Error; +} +impl Storage for InMemoryStorage { + type Error = String; +} +trait StorageRequestReturnType { + type Output; +} +trait StorageRequest<S: Storage>: StorageRequestReturnType { + fn execute(&self) -> BoxFuture<Result<<Self>::Output, S::Error>>; +} +struct SaveUser<'a> { + name: &'a str, +} +impl<'a> StorageRequestReturnType for SaveUser<'a> { + type Output = (); +} +impl<'dep> User<'dep> { + async fn save<S>(self) + where + S: Storage, + for<'a> SaveUser<'a>: StorageRequest<S>, + { + SaveUser { name: "" }.execute().await; + } +} +async fn run<S>(dep: &str) +where + S: Storage, + for<'a> SaveUser<'a>: StorageRequest<S>, +{ + User { dep }.save().await +}
diff --git a/tests/ui/async-await/async-drop/live-dead-storage4.rs b/tests/ui/async-await/async-drop/live-dead-storage4.rs new file mode 100644 index 0000000..d927cb9 --- /dev/null +++ b/tests/ui/async-await/async-drop/live-dead-storage4.rs
@@ -0,0 +1,56 @@ +// ex-ice: #141409 +//@ compile-flags: -Zmir-enable-passes=+Inline -Zvalidate-mir -Zlint-mir --crate-type lib +//@ edition:2024 +//@ check-pass + +#![feature(async_drop)] +#![allow(incomplete_features)] +#![allow(non_snake_case)] + +use std::mem::ManuallyDrop; +use std::{ + future::{async_drop_in_place, Future}, + pin::{pin, Pin}, + sync::{mpsc, Arc}, + task::{Context, Poll, Wake, Waker}, +}; +fn main() { + block_on(bar(0)) +} +async fn baz(ident_base: usize) {} +async fn bar(ident_base: usize) { + baz(1).await +} +fn block_on<F>(fut_unpin: F) -> F::Output +where + F: Future, +{ + let fut_pin = pin!(ManuallyDrop::new(fut_unpin)); + let mut fut = unsafe { Pin::map_unchecked_mut(fut_pin, |x| &mut **x) }; + let (waker, rx) = simple_waker(); + let mut context = Context::from_waker(&waker); + let rv = loop { + match fut.as_mut().poll(&mut context) { + Poll::Ready(out) => break out, + PollPending => (), + } + }; + let drop_fut_unpin = unsafe { async_drop_in_place(fut.get_unchecked_mut()) }; + let drop_fut = pin!(drop_fut_unpin); + loop { + match drop_fut.poll(&mut context) { + Poll => break, + } + } + rv +} +fn simple_waker() -> (Waker, mpsc::Receiver<()>) { + struct SimpleWaker { + tx: mpsc::Sender<()>, + } + impl Wake for SimpleWaker { + fn wake(self: Arc<Self>) {} + } + let (tx, rx) = mpsc::channel(); + (Waker::from(Arc::new(SimpleWaker { tx })), rx) +}
diff --git a/tests/ui/async-await/awaiting-unsized-param.rs b/tests/ui/async-await/awaiting-unsized-param.rs index 45611ea..d957e5b 100644 --- a/tests/ui/async-await/awaiting-unsized-param.rs +++ b/tests/ui/async-await/awaiting-unsized-param.rs
@@ -1,12 +1,11 @@ //@ edition: 2021 -#![feature(unsized_fn_params, unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete +#![feature(unsized_fn_params)] use std::future::Future; async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T { - //~^ ERROR the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time + //~^ ERROR the size for values of type `dyn Future<Output = T> + Unpin` cannot be known at compilation time (&mut f).await }
diff --git a/tests/ui/async-await/awaiting-unsized-param.stderr b/tests/ui/async-await/awaiting-unsized-param.stderr index 0104736..bcb0bcd 100644 --- a/tests/ui/async-await/awaiting-unsized-param.stderr +++ b/tests/ui/async-await/awaiting-unsized-param.stderr
@@ -1,21 +1,12 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/awaiting-unsized-param.rs:3:31 - | -LL | #![feature(unsized_fn_params, unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time - --> $DIR/awaiting-unsized-param.rs:8:17 +error[E0277]: the size for values of type `dyn Future<Output = T> + Unpin` cannot be known at compilation time + --> $DIR/awaiting-unsized-param.rs:7:17 | LL | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T { | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + Unpin + 'static)` - = note: all values captured by value by a closure must have a statically known size + = help: the trait `Sized` is not implemented for `dyn Future<Output = T> + Unpin` + = note: all local variables must have a statically known size -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/unsized-across-await.rs b/tests/ui/async-await/unsized-across-await.rs index b6bd556..3e8d58d 100644 --- a/tests/ui/async-await/unsized-across-await.rs +++ b/tests/ui/async-await/unsized-across-await.rs
@@ -1,8 +1,5 @@ //@ edition: 2021 -#![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete - async fn f() {} async fn g(x: Box<dyn std::fmt::Display>) {
diff --git a/tests/ui/async-await/unsized-across-await.stderr b/tests/ui/async-await/unsized-across-await.stderr index 5bb2b7f..f06c390 100644 --- a/tests/ui/async-await/unsized-across-await.stderr +++ b/tests/ui/async-await/unsized-across-await.stderr
@@ -1,21 +1,17 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsized-across-await.rs:3:12 - | -LL | #![feature(unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time - --> $DIR/unsized-across-await.rs:9:9 + --> $DIR/unsized-across-await.rs:6:9 | LL | let _x = *x; | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn std::fmt::Display` - = note: all values live across `await` must have a statically known size + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let _x = *x; +LL + let _x = x; + | -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/borrowck/issue-47646.stderr b/tests/ui/borrowck/issue-47646.stderr index 85adfc0..cfe6f3f 100644 --- a/tests/ui/borrowck/issue-47646.stderr +++ b/tests/ui/borrowck/issue-47646.stderr
@@ -11,7 +11,7 @@ | ^^^^ immutable borrow occurs here ... LL | }; - | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<PeekMut<'_, i32>>, ())` + | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<std::collections::binary_heap::PeekMut<'_, i32>>, ())` | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/borrowck/issue-85581.stderr b/tests/ui/borrowck/issue-85581.stderr index 80f1f4c..5fd457e 100644 --- a/tests/ui/borrowck/issue-85581.stderr +++ b/tests/ui/borrowck/issue-85581.stderr
@@ -10,7 +10,7 @@ | ^^^^ second mutable borrow occurs here ... LL | } - | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<PeekMut<'_, i32>>` + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<std::collections::binary_heap::PeekMut<'_, i32>>` error: aborting due to 1 previous error
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.fixed b/tests/ui/borrowck/span-semicolon-issue-139049.fixed new file mode 100644 index 0000000..0b263b2 --- /dev/null +++ b/tests/ui/borrowck/span-semicolon-issue-139049.fixed
@@ -0,0 +1,52 @@ +// Make sure the generated suggestion suggest editing the user +// code instead of the std macro implementation + +//@ run-rustfix + +#![allow(dead_code)] + +use std::fmt::{self, Display}; + +struct Mutex; + +impl Mutex { + fn lock(&self) -> MutexGuard<'_> { + MutexGuard(self) + } +} + +struct MutexGuard<'a>(&'a Mutex); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) {} +} + +struct Out; + +impl Out { + fn write_fmt(&self, _args: fmt::Arguments) {} +} + +impl<'a> Display for MutexGuard<'a> { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +fn main() { + let _write = { + let mutex = Mutex; + write!(Out, "{}", mutex.lock()); + //~^ ERROR `mutex` does not live long enough + //~| SUGGESTION ; + }; + + let _write = { + use std::io::Write as _; + + let mutex = Mutex; + let x = write!(std::io::stdout(), "{}", mutex.lock()); x + //~^ ERROR `mutex` does not live long enough + //~| SUGGESTION let x + }; +}
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.rs b/tests/ui/borrowck/span-semicolon-issue-139049.rs new file mode 100644 index 0000000..a92742a --- /dev/null +++ b/tests/ui/borrowck/span-semicolon-issue-139049.rs
@@ -0,0 +1,52 @@ +// Make sure the generated suggestion suggest editing the user +// code instead of the std macro implementation + +//@ run-rustfix + +#![allow(dead_code)] + +use std::fmt::{self, Display}; + +struct Mutex; + +impl Mutex { + fn lock(&self) -> MutexGuard<'_> { + MutexGuard(self) + } +} + +struct MutexGuard<'a>(&'a Mutex); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) {} +} + +struct Out; + +impl Out { + fn write_fmt(&self, _args: fmt::Arguments) {} +} + +impl<'a> Display for MutexGuard<'a> { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +fn main() { + let _write = { + let mutex = Mutex; + write!(Out, "{}", mutex.lock()) + //~^ ERROR `mutex` does not live long enough + //~| SUGGESTION ; + }; + + let _write = { + use std::io::Write as _; + + let mutex = Mutex; + write!(std::io::stdout(), "{}", mutex.lock()) + //~^ ERROR `mutex` does not live long enough + //~| SUGGESTION let x + }; +}
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.stderr b/tests/ui/borrowck/span-semicolon-issue-139049.stderr new file mode 100644 index 0000000..123bdf4 --- /dev/null +++ b/tests/ui/borrowck/span-semicolon-issue-139049.stderr
@@ -0,0 +1,47 @@ +error[E0597]: `mutex` does not live long enough + --> $DIR/span-semicolon-issue-139049.rs:39:27 + | +LL | let mutex = Mutex; + | ----- binding `mutex` declared here +LL | write!(Out, "{}", mutex.lock()) + | ^^^^^------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +... +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` + | | + | `mutex` dropped here while still borrowed + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | write!(Out, "{}", mutex.lock()); + | + + +error[E0597]: `mutex` does not live long enough + --> $DIR/span-semicolon-issue-139049.rs:48:41 + | +LL | let mutex = Mutex; + | ----- binding `mutex` declared here +LL | write!(std::io::stdout(), "{}", mutex.lock()) + | ^^^^^------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +... +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` + | | + | `mutex` dropped here while still borrowed + | + = note: the temporary is part of an expression at the end of a block; + consider forcing this temporary to be dropped sooner, before the block's local variables are dropped +help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block + | +LL | let x = write!(std::io::stdout(), "{}", mutex.lock()); x + | +++++++ +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs index 58370bf..1e0576b 100644 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs +++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs
@@ -1,15 +1,15 @@ //@ only-x86_64 fn efiapi(f: extern "efiapi" fn(usize, ...)) { - //~^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable + //~^ ERROR: unstable f(22, 44); } fn sysv(f: extern "sysv64" fn(usize, ...)) { - //~^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable + //~^ ERROR: unstable f(22, 44); } fn win(f: extern "win64" fn(usize, ...)) { - //~^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable + //~^ ERROR: unstable f(22, 44); }
diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr index 9565575..7ef54b6 100644 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr +++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr
@@ -1,4 +1,4 @@ -error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable +error[E0658]: C-variadic functions with the "efiapi" calling convention are unstable --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14 | LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { @@ -8,7 +8,7 @@ = help: add `#![feature(extended_varargs_abi_support)]` 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]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable +error[E0658]: C-variadic functions with the "sysv64" calling convention are unstable --> $DIR/feature-gate-extended_varargs_abi_support.rs:7:12 | LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { @@ -18,7 +18,7 @@ = help: add `#![feature(extended_varargs_abi_support)]` 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]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable +error[E0658]: C-variadic functions with the "win64" calling convention are unstable --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11 | LL | fn win(f: extern "win64" fn(usize, ...)) {
diff --git a/tests/ui/c-variadic/variadic-ffi-1.rs b/tests/ui/c-variadic/variadic-ffi-1.rs index 9dcd55d1..cd8f2a9 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.rs +++ b/tests/ui/c-variadic/variadic-ffi-1.rs
@@ -9,8 +9,7 @@ extern "stdcall" { fn printf(_: *const u8, ...); - //~^ ERROR: C-variadic function must have a compatible calling convention, - // like C, cdecl, win64, sysv64 or efiapi + //~^ ERROR: C-variadic functions with the "stdcall" calling convention are not supported } extern "C" {
diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr index f99abed..a49fc0c 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.stderr +++ b/tests/ui/c-variadic/variadic-ffi-1.stderr
@@ -1,17 +1,17 @@ -error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi` +error[E0045]: C-variadic functions with the "stdcall" calling convention are not supported --> $DIR/variadic-ffi-1.rs:11:5 | LL | fn printf(_: *const u8, ...); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied - --> $DIR/variadic-ffi-1.rs:24:9 + --> $DIR/variadic-ffi-1.rs:23:9 | LL | foo(); | ^^^-- two arguments of type `isize` and `u8` are missing | note: function defined here - --> $DIR/variadic-ffi-1.rs:17:8 + --> $DIR/variadic-ffi-1.rs:16:8 | LL | fn foo(f: isize, x: u8, ...); | ^^^ - - @@ -21,13 +21,13 @@ | +++++++++++++++++++++ error[E0060]: this function takes at least 2 arguments but 1 argument was supplied - --> $DIR/variadic-ffi-1.rs:25:9 + --> $DIR/variadic-ffi-1.rs:24:9 | LL | foo(1); | ^^^--- argument #2 of type `u8` is missing | note: function defined here - --> $DIR/variadic-ffi-1.rs:17:8 + --> $DIR/variadic-ffi-1.rs:16:8 | LL | fn foo(f: isize, x: u8, ...); | ^^^ - @@ -37,7 +37,7 @@ | ++++++++++ error[E0308]: mismatched types - --> $DIR/variadic-ffi-1.rs:27:56 + --> $DIR/variadic-ffi-1.rs:26:56 | LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; | ------------------------------------- ^^^ expected non-variadic fn, found variadic function @@ -48,7 +48,7 @@ found fn item `unsafe extern "C" fn(_, _, ...) {foo}` error[E0308]: mismatched types - --> $DIR/variadic-ffi-1.rs:28:54 + --> $DIR/variadic-ffi-1.rs:27:54 | LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; | ----------------------------------- ^^^ expected variadic fn, found non-variadic function @@ -59,7 +59,7 @@ found fn item `extern "C" fn(_, _) {bar}` error[E0617]: can't pass `f32` to variadic function - --> $DIR/variadic-ffi-1.rs:30:19 + --> $DIR/variadic-ffi-1.rs:29:19 | LL | foo(1, 2, 3f32); | ^^^^ @@ -70,7 +70,7 @@ | +++++++++++ error[E0617]: can't pass `bool` to variadic function - --> $DIR/variadic-ffi-1.rs:31:19 + --> $DIR/variadic-ffi-1.rs:30:19 | LL | foo(1, 2, true); | ^^^^ @@ -81,7 +81,7 @@ | ++++++++ error[E0617]: can't pass `i8` to variadic function - --> $DIR/variadic-ffi-1.rs:32:19 + --> $DIR/variadic-ffi-1.rs:31:19 | LL | foo(1, 2, 1i8); | ^^^ @@ -92,7 +92,7 @@ | ++++++++ error[E0617]: can't pass `u8` to variadic function - --> $DIR/variadic-ffi-1.rs:33:19 + --> $DIR/variadic-ffi-1.rs:32:19 | LL | foo(1, 2, 1u8); | ^^^ @@ -103,7 +103,7 @@ | +++++++++ error[E0617]: can't pass `i16` to variadic function - --> $DIR/variadic-ffi-1.rs:34:19 + --> $DIR/variadic-ffi-1.rs:33:19 | LL | foo(1, 2, 1i16); | ^^^^ @@ -114,7 +114,7 @@ | ++++++++ error[E0617]: can't pass `u16` to variadic function - --> $DIR/variadic-ffi-1.rs:35:19 + --> $DIR/variadic-ffi-1.rs:34:19 | LL | foo(1, 2, 1u16); | ^^^^
diff --git a/tests/ui/c-variadic/variadic-ffi-2.rs b/tests/ui/c-variadic/variadic-ffi-2.rs index da7bb76..adfd9bf 100644 --- a/tests/ui/c-variadic/variadic-ffi-2.rs +++ b/tests/ui/c-variadic/variadic-ffi-2.rs
@@ -1,8 +1,7 @@ #![feature(extended_varargs_abi_support)] fn baz(f: extern "Rust" fn(usize, ...)) { - //~^ ERROR: C-variadic function must have a compatible calling convention, - // like C, cdecl, system, aapcs, win64, sysv64 or efiapi + //~^ ERROR: C-variadic functions with the "Rust" calling convention are not supported f(22, 44); }
diff --git a/tests/ui/c-variadic/variadic-ffi-2.stderr b/tests/ui/c-variadic/variadic-ffi-2.stderr index 9f8dcef..2ac0a9f 100644 --- a/tests/ui/c-variadic/variadic-ffi-2.stderr +++ b/tests/ui/c-variadic/variadic-ffi-2.stderr
@@ -1,4 +1,4 @@ -error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi` +error[E0045]: C-variadic functions with the "Rust" calling convention are not supported --> $DIR/variadic-ffi-2.rs:3:11 | LL | fn baz(f: extern "Rust" fn(usize, ...)) {
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index ec81ba2..f29a41d 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr
@@ -212,6 +212,9 @@ `relax` `relaxed-simd` `reserve-x18` +`retpoline-external-thunk` +`retpoline-indirect-branches` +`retpoline-indirect-calls` `rtm` `sb` `scq`
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs index 18041b0..8408089 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs
@@ -38,4 +38,4 @@ trait Trait {} //~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798] type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...); -//~^ ERROR C-variadic function must have a compatible calling convention, like `C` +//~^ ERROR C-variadic functions with the "C-cmse-nonsecure-call" calling convention are not supported
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr index ab7c9ce..2b51f48 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr
@@ -69,7 +69,7 @@ = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi` +error[E0045]: C-variadic functions with the "C-cmse-nonsecure-call" calling convention are not supported --> $DIR/generics.rs:40:20 | LL | type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...);
diff --git a/tests/ui/const-generics/mgca/missing_generic_params.rs b/tests/ui/const-generics/mgca/missing_generic_params.rs new file mode 100644 index 0000000..ab1db33 --- /dev/null +++ b/tests/ui/const-generics/mgca/missing_generic_params.rs
@@ -0,0 +1,16 @@ +// This used to ICE: #137188 +// The missing parameter list on `N` was set to +// "infer from use site" in ast lowering, which +// caused later code to not emit a missing generic +// param error. The missing param was then attempted +// to be inferred, but inference of generic params +// is only possible within bodies. So a delayed +// bug was generated with no error ever reported. + +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] +trait Trait {} +impl Trait for [(); N] {} +//~^ ERROR: missing generics for function `N` +fn N<T>() {} +pub fn main() {}
diff --git a/tests/ui/const-generics/mgca/missing_generic_params.stderr b/tests/ui/const-generics/mgca/missing_generic_params.stderr new file mode 100644 index 0000000..78010c7 --- /dev/null +++ b/tests/ui/const-generics/mgca/missing_generic_params.stderr
@@ -0,0 +1,19 @@ +error[E0107]: missing generics for function `N` + --> $DIR/missing_generic_params.rs:13:21 + | +LL | impl Trait for [(); N] {} + | ^ expected 1 generic argument + | +note: function defined here, with 1 generic parameter: `T` + --> $DIR/missing_generic_params.rs:15:4 + | +LL | fn N<T>() {} + | ^ - +help: add missing generic argument + | +LL | impl Trait for [(); N<T>] {} + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs index 45631df..c1c7571 100644 --- a/tests/ui/consts/auxiliary/unstable_intrinsic.rs +++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
@@ -8,4 +8,4 @@ #[unstable(feature = "unstable", issue = "42")] #[rustc_const_unstable(feature = "unstable", issue = "42")] #[rustc_intrinsic] -pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize; +pub const unsafe fn align_of_val<T>(x: *const T) -> usize;
diff --git a/tests/ui/consts/const-adt-align-mismatch.rs b/tests/ui/consts/const-adt-align-mismatch.rs index 8faddbf..6ff74ad 100644 --- a/tests/ui/consts/const-adt-align-mismatch.rs +++ b/tests/ui/consts/const-adt-align-mismatch.rs
@@ -18,5 +18,5 @@ enum Foo { fn main() { assert_eq!(FOO, Foo::C); assert_eq!(mem::size_of::<Foo>(), 12); - assert_eq!(mem::min_align_of::<Foo>(), 4); + assert_eq!(mem::align_of::<Foo>(), 4); }
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 29474c7..28facc1 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
@@ -18,7 +18,7 @@ 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 temporary value dropped while borrowed +const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR mutable references are not allowed 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
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 834ea34..122e5c1 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
@@ -4,15 +4,11 @@ LL | const B: *mut i32 = &mut 4; | ^^^^^^ -error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:21:40 +error[E0764]: mutable references are not allowed in the final value of constants + --> $DIR/mut_ref_in_final.rs:21:35 | LL | const B3: Option<&mut i32> = Some(&mut 42); - | ----------^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary value which is freed while still in use - | using this value as a constant requires that borrow lasts for `'static` + | ^^^^^^^ error[E0716]: temporary value dropped while borrowed --> $DIR/mut_ref_in_final.rs:24:42
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs index 14cdf6b..423ff37 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
@@ -1,13 +1,13 @@ #![feature(extern_types)] #![feature(core_intrinsics)] -use std::intrinsics::{min_align_of_val, size_of_val}; +use std::intrinsics::{align_of_val, size_of_val}; extern "C" { type Opaque; } const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout -const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout +const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout fn main() {}
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index 64b7a41..c78626b 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
@@ -7,8 +7,8 @@ error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32 | -LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here +LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here error: aborting due to 2 previous errors
diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index 890a30c..d130eb6 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs
@@ -17,13 +17,13 @@ const fn const_main() { unstable_intrinsic::size_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: not yet stable as a const intrinsic - unstable_intrinsic::min_align_of_val(&x); + unstable_intrinsic::align_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: not yet stable as a const intrinsic size_of_val(&x); //~^ERROR: cannot use `#[feature(local)]` - min_align_of_val(&x); + align_of_val(&x); //~^ERROR: cannot use `#[feature(local)]` } } @@ -35,7 +35,7 @@ const fn const_main() { #[unstable(feature = "local", issue = "42")] #[rustc_const_unstable(feature = "local", issue = "42")] #[rustc_intrinsic] -pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize; +pub const unsafe fn align_of_val<T>(x: *const T) -> usize; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 7e7ba96..973c7ba 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr
@@ -11,8 +11,8 @@ error[E0658]: use of unstable library feature `unstable` --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information = help: add `#![feature(unstable)]` to the crate attributes to enable @@ -29,11 +29,11 @@ LL + #![feature(unstable)] | -error: `min_align_of_val` is not yet stable as a const intrinsic +error: `align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: add `#![feature(unstable)]` to the crate attributes to enable | @@ -55,8 +55,8 @@ error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:26:9 | -LL | min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^ +LL | align_of_val(&x); + | ^^^^^^^^^^^^^^^^ | help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` |
diff --git a/tests/ui/consts/gate-do-not-const-check.rs b/tests/ui/consts/gate-do-not-const-check.rs index be7e70d..0ebb1e7c 100644 --- a/tests/ui/consts/gate-do-not-const-check.rs +++ b/tests/ui/consts/gate-do-not-const-check.rs
@@ -1,5 +1,7 @@ #[rustc_do_not_const_check] -//~^ ERROR this is an internal attribute that will never be stable +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable +//~| NOTE `#[rustc_do_not_const_check]` skips const-check for this function's body const fn foo() {} fn main() {}
diff --git a/tests/ui/consts/gate-do-not-const-check.stderr b/tests/ui/consts/gate-do-not-const-check.stderr index 74ea71c..778ee50 100644 --- a/tests/ui/consts/gate-do-not-const-check.stderr +++ b/tests/ui/consts/gate-do-not-const-check.stderr
@@ -1,11 +1,12 @@ -error[E0658]: this is an internal attribute that will never be stable +error[E0658]: use of an internal attribute --> $DIR/gate-do-not-const-check.rs:1:1 | LL | #[rustc_do_not_const_check] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable + = note: `#[rustc_do_not_const_check]` skips const-check for this function's body error: aborting due to 1 previous error
diff --git a/tests/ui/consts/issue-54224.rs b/tests/ui/consts/issue-54224.rs deleted file mode 100644 index f194793..0000000 --- a/tests/ui/consts/issue-54224.rs +++ /dev/null
@@ -1,12 +0,0 @@ -const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed - -use std::borrow::Cow; - -pub const X: [u8; 3] = *b"ABC"; -pub const Y: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[X]); - - -pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]); -//~^ ERROR temporary value dropped while borrowed - -fn main() {}
diff --git a/tests/ui/consts/issue-54224.stderr b/tests/ui/consts/issue-54224.stderr deleted file mode 100644 index 55fe557..0000000 --- a/tests/ui/consts/issue-54224.stderr +++ /dev/null
@@ -1,23 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-54224.rs:1:39 - | -LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); - | ------^^^^^^^^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary value which is freed while still in use - | using this value as a constant requires that borrow lasts for `'static` - -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-54224.rs:9:57 - | -LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]); - | ---------------^^^^^^^^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary value which is freed while still in use - | using this value as a constant requires that borrow lasts for `'static` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/consts/promote-not.rs b/tests/ui/consts/promote-not.rs index 207bacc..74e0efb 100644 --- a/tests/ui/consts/promote-not.rs +++ b/tests/ui/consts/promote-not.rs
@@ -3,10 +3,11 @@ #![allow(unconditional_panic)] use std::cell::Cell; +use std::convert::identity; use std::mem::ManuallyDrop; // We do not promote mutable references. -static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed +static mut TEST1: &mut [i32] = identity(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed static mut TEST2: &'static mut [i32] = { let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr index d8b6091..ec552d9 100644 --- a/tests/ui/consts/promote-not.stderr +++ b/tests/ui/consts/promote-not.stderr
@@ -1,15 +1,15 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:9:50 + --> $DIR/promote-not.rs:10:46 | -LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); - | ----------^^^^^^^^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary value which is freed while still in use - | using this value as a static requires that borrow lasts for `'static` +LL | static mut TEST1: &mut [i32] = identity(&mut [1, 2, 3]); + | --------------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:12:18 + --> $DIR/promote-not.rs:13:18 | LL | let x = &mut [1,2,3]; | ^^^^^^^ creates a temporary value which is freed while still in use @@ -19,7 +19,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:34:29 + --> $DIR/promote-not.rs:35:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -29,7 +29,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:40:29 + --> $DIR/promote-not.rs:41:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).1; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -39,7 +39,7 @@ | - temporary value is freed at the end of this statement error[E0493]: destructor of `String` cannot be evaluated at compile-time - --> $DIR/promote-not.rs:47:14 + --> $DIR/promote-not.rs:48:14 | LL | let x = &String::new(); | ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants @@ -48,7 +48,7 @@ | - value is dropped here error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:59:33 + --> $DIR/promote-not.rs:60:33 | LL | let _x: &'static u32 = &mk_panic(); | ------------ ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -58,7 +58,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:21:32 + --> $DIR/promote-not.rs:22:32 | LL | let _x: &'static () = &foo(); | ----------- ^^^^^ creates a temporary value which is freed while still in use @@ -68,7 +68,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:29:29 + --> $DIR/promote-not.rs:30:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -78,7 +78,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:65:29 + --> $DIR/promote-not.rs:66:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).0; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -89,7 +89,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:66:29 + --> $DIR/promote-not.rs:67:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).1; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -100,7 +100,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:69:29 + --> $DIR/promote-not.rs:70:29 | LL | let _val: &'static _ = &(1/0); | ---------- ^^^^^ creates a temporary value which is freed while still in use @@ -111,7 +111,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:70:29 + --> $DIR/promote-not.rs:71:29 | LL | let _val: &'static _ = &(1/(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -122,7 +122,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:71:29 + --> $DIR/promote-not.rs:72:29 | LL | let _val: &'static _ = &((1+1)/(1-1)); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -133,7 +133,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:72:29 + --> $DIR/promote-not.rs:73:29 | LL | let _val: &'static _ = &(i32::MIN/-1); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -144,7 +144,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:73:29 + --> $DIR/promote-not.rs:74:29 | LL | let _val: &'static _ = &(i32::MIN/(0-1)); | ---------- ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -155,7 +155,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:74:29 + --> $DIR/promote-not.rs:75:29 | LL | let _val: &'static _ = &(-128i8/-1); | ---------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -166,7 +166,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:75:29 + --> $DIR/promote-not.rs:76:29 | LL | let _val: &'static _ = &(1%0); | ---------- ^^^^^ creates a temporary value which is freed while still in use @@ -177,7 +177,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:76:29 + --> $DIR/promote-not.rs:77:29 | LL | let _val: &'static _ = &(1%(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -188,7 +188,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:77:29 + --> $DIR/promote-not.rs:78:29 | LL | let _val: &'static _ = &([1,2,3][4]+1); | ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -199,7 +199,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:81:29 + --> $DIR/promote-not.rs:82:29 | LL | let _val: &'static _ = &TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -210,7 +210,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:83:29 + --> $DIR/promote-not.rs:84:29 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -221,7 +221,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:83:30 + --> $DIR/promote-not.rs:84:30 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -232,7 +232,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:86:29 + --> $DIR/promote-not.rs:87:29 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -243,7 +243,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:86:31 + --> $DIR/promote-not.rs:87:31 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -254,7 +254,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:89:29 + --> $DIR/promote-not.rs:90:29 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -265,7 +265,7 @@ | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:89:31 + --> $DIR/promote-not.rs:90:31 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement @@ -274,7 +274,7 @@ | type annotation requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:98:26 + --> $DIR/promote-not.rs:99:26 | LL | let x: &'static _ = &UnionWithCell { f1: 0 }; | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
diff --git a/tests/ui/coroutine/auto-trait-regions.rs b/tests/ui/coroutine/auto-trait-regions.rs index 1c7f030..f115896 100644 --- a/tests/ui/coroutine/auto-trait-regions.rs +++ b/tests/ui/coroutine/auto-trait-regions.rs
@@ -43,8 +43,8 @@ fn main() { // Disallow impls which relates lifetimes in the coroutine interior let gen = #[coroutine] move || { let a = A(&mut true, &mut true, No); - //~^ ERROR temporary value dropped while borrowed - //~| ERROR temporary value dropped while borrowed + //~^ ERROR borrow may still be in use when coroutine yields + //~| ERROR borrow may still be in use when coroutine yields yield; assert_foo(a); };
diff --git a/tests/ui/coroutine/auto-trait-regions.stderr b/tests/ui/coroutine/auto-trait-regions.stderr index a9a0bde..77b5f3c 100644 --- a/tests/ui/coroutine/auto-trait-regions.stderr +++ b/tests/ui/coroutine/auto-trait-regions.stderr
@@ -1,36 +1,34 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/auto-trait-regions.rs:45:24 +error[E0626]: borrow may still be in use when coroutine yields + --> $DIR/auto-trait-regions.rs:45:19 | +LL | let gen = #[coroutine] move || { + | ------- within this coroutine LL | let a = A(&mut true, &mut true, No); - | ^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use + | ^^^^^^^^^ ... -LL | assert_foo(a); - | - borrow later used here +LL | yield; + | ----- possible yield occurs here | -help: consider using a `let` binding to create a longer lived value +help: add `static` to mark this coroutine as unmovable | -LL ~ let binding = true; -LL ~ let a = A(&mut binding, &mut true, No); - | +LL | let gen = #[coroutine] static move || { + | ++++++ -error[E0716]: temporary value dropped while borrowed - --> $DIR/auto-trait-regions.rs:45:35 +error[E0626]: borrow may still be in use when coroutine yields + --> $DIR/auto-trait-regions.rs:45:30 | +LL | let gen = #[coroutine] move || { + | ------- within this coroutine LL | let a = A(&mut true, &mut true, No); - | ^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use + | ^^^^^^^^^ ... -LL | assert_foo(a); - | - borrow later used here +LL | yield; + | ----- possible yield occurs here | -help: consider using a `let` binding to create a longer lived value +help: add `static` to mark this coroutine as unmovable | -LL ~ let binding = true; -LL ~ let a = A(&mut true, &mut binding, No); - | +LL | let gen = #[coroutine] static move || { + | ++++++ error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:31:5 @@ -52,4 +50,4 @@ error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0716`. +For more information about this error, try `rustc --explain E0626`.
diff --git a/tests/ui/coroutine/unsized-capture-across-yield.rs b/tests/ui/coroutine/unsized-capture-across-yield.rs index c86b182..ee27ea0 100644 --- a/tests/ui/coroutine/unsized-capture-across-yield.rs +++ b/tests/ui/coroutine/unsized-capture-across-yield.rs
@@ -1,16 +1,13 @@ #![feature(coroutine_trait)] #![feature(coroutines)] -#![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes use std::ops::Coroutine; fn capture() -> impl Coroutine { - let b: [u8] = *(Box::new([]) as Box<[u8]>); + let b: [u8] = *(Box::new([]) as Box<[u8]>); //~ERROR he size for values of type `[u8]` cannot be known at compilation time #[coroutine] move || { println!("{:?}", &b); - //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time yield;
diff --git a/tests/ui/coroutine/unsized-capture-across-yield.stderr b/tests/ui/coroutine/unsized-capture-across-yield.stderr index 03551f1..c46c08f 100644 --- a/tests/ui/coroutine/unsized-capture-across-yield.stderr +++ b/tests/ui/coroutine/unsized-capture-across-yield.stderr
@@ -1,23 +1,16 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsized-capture-across-yield.rs:3:12 - | -LL | #![feature(unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-capture-across-yield.rs:12:27 + --> $DIR/unsized-capture-across-yield.rs:7:9 | -LL | move || { - | -- this closure captures all values by move -LL | println!("{:?}", &b); - | ^ doesn't have a size known at compile-time +LL | let b: [u8] = *(Box::new([]) as Box<[u8]>); + | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` - = note: all values captured by value by a closure must have a statically known size + = note: all local variables must have a statically known size +help: consider borrowing here + | +LL | let b: &[u8] = *(Box::new([]) as Box<[u8]>); + | + -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/coroutine/unsized-local-across-yield.rs b/tests/ui/coroutine/unsized-local-across-yield.rs index cb8ced1..4c688e5 100644 --- a/tests/ui/coroutine/unsized-local-across-yield.rs +++ b/tests/ui/coroutine/unsized-local-across-yield.rs
@@ -1,7 +1,5 @@ #![feature(coroutine_trait)] #![feature(coroutines)] -#![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes use std::ops::Coroutine;
diff --git a/tests/ui/coroutine/unsized-local-across-yield.stderr b/tests/ui/coroutine/unsized-local-across-yield.stderr index 4fe0f13..fd6cd46 100644 --- a/tests/ui/coroutine/unsized-local-across-yield.stderr +++ b/tests/ui/coroutine/unsized-local-across-yield.stderr
@@ -1,21 +1,16 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsized-local-across-yield.rs:3:12 - | -LL | #![feature(unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-local-across-yield.rs:11:13 + --> $DIR/unsized-local-across-yield.rs:9:13 | LL | let b: [u8] = *(Box::new([]) as Box<[u8]>); | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` - = note: all values live across `yield` must have a statically known size + = note: all local variables must have a statically known size +help: consider borrowing here + | +LL | let b: &[u8] = *(Box::new([]) as Box<[u8]>); + | + -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/multiline_spans.rs b/tests/ui/diagnostic_namespace/multiline_spans.rs new file mode 100644 index 0000000..994dd9f --- /dev/null +++ b/tests/ui/diagnostic_namespace/multiline_spans.rs
@@ -0,0 +1,55 @@ +#![crate_type = "lib"] +#![deny(unknown_or_malformed_diagnostic_attributes)] + + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string \ + {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine2` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine2 {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine3` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine3 {} + + +#[diagnostic::on_unimplemented(message = "here is a big \ +\ + \ + \ + \ + multiline string {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine4` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine4 {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string \ + {Self:+}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {Self:X}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt2 {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {Self:#}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt3 {} + + +#[diagnostic::on_unimplemented(message = "here is a big \ +\ + \ + \ + \ + multiline string {Self:?}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt4 {}
diff --git a/tests/ui/diagnostic_namespace/multiline_spans.stderr b/tests/ui/diagnostic_namespace/multiline_spans.stderr new file mode 100644 index 0000000..894bfe3 --- /dev/null +++ b/tests/ui/diagnostic_namespace/multiline_spans.stderr
@@ -0,0 +1,71 @@ +error: there is no parameter `unknown` on trait `MultiLine` + --> $DIR/multiline_spans.rs:7:43 + | +LL | ... {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument +note: the lint level is defined here + --> $DIR/multiline_spans.rs:2:9 + | +LL | #![deny(unknown_or_malformed_diagnostic_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: there is no parameter `unknown` on trait `MultiLine2` + --> $DIR/multiline_spans.rs:12:60 + | +LL | ... multiline string {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +error: there is no parameter `unknown` on trait `MultiLine3` + --> $DIR/multiline_spans.rs:17:23 + | +LL | multiline string {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +error: there is no parameter `unknown` on trait `MultiLine4` + --> $DIR/multiline_spans.rs:27:23 + | +LL | multiline string {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +error: invalid format specifier + --> $DIR/multiline_spans.rs:33:47 + | +LL | ... {Self:+}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: invalid format specifier + --> $DIR/multiline_spans.rs:38:64 + | +LL | ... multiline string {Self:X}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: invalid format specifier + --> $DIR/multiline_spans.rs:43:27 + | +LL | multiline string {Self:#}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: invalid format specifier + --> $DIR/multiline_spans.rs:53:27 + | +LL | multiline string {Self:?}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: aborting due to 8 previous errors +
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs index 44f269e..4762d9e 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
@@ -12,6 +12,8 @@ trait ImportantTrait2 {} #[diagnostic::on_unimplemented(message = "Test {1:}")] //~^WARN positional format arguments are not allowed here //~|WARN positional format arguments are not allowed here +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] trait ImportantTrait3 {} #[diagnostic::on_unimplemented(message = "Test {Self:123}")] @@ -20,17 +22,22 @@ trait ImportantTrait3 {} trait ImportantTrait4 {} #[diagnostic::on_unimplemented(message = "Test {Self:!}")] -//~^WARN expected `}`, found `!` -//~|WARN expected `}`, found `!` -//~|WARN unmatched `}` found -//~|WARN unmatched `}` found +//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] trait ImportantTrait5 {} +#[diagnostic::on_unimplemented(message = "Test {Self:}")] +//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +trait ImportantTrait6 {} + + fn check_1(_: impl ImportantTrait1) {} fn check_2(_: impl ImportantTrait2) {} fn check_3(_: impl ImportantTrait3) {} fn check_4(_: impl ImportantTrait4) {} fn check_5(_: impl ImportantTrait5) {} +fn check_6(_: impl ImportantTrait6) {} fn main() { check_1(()); @@ -42,5 +49,7 @@ fn main() { check_4(()); //~^ERROR Test () check_5(()); - //~^ERROR Test {Self:!} + //~^ERROR Test () + check_6(()); + //~^ERROR Test () }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr index a82a1e7..2670d06 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
@@ -14,6 +14,14 @@ | = help: only named format arguments with the name of one of the generic types are allowed in this context +warning: invalid format specifier + --> $DIR/broken_format.rs:12:50 + | +LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] + | ^ + | + = help: no format specifier are supported in this position + warning: positional format arguments are not allowed here --> $DIR/broken_format.rs:12:49 | @@ -23,24 +31,28 @@ = help: only named format arguments with the name of one of the generic types are allowed in this context warning: invalid format specifier - --> $DIR/broken_format.rs:17:42 + --> $DIR/broken_format.rs:19:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^ | = help: no format specifier are supported in this position -warning: expected `}`, found `!` - --> $DIR/broken_format.rs:22:42 +warning: invalid format specifier + --> $DIR/broken_format.rs:24:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ + | ^^ + | + = help: no format specifier are supported in this position -warning: unmatched `}` found - --> $DIR/broken_format.rs:22:42 +warning: invalid format specifier + --> $DIR/broken_format.rs:29:53 | -LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ +LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")] + | ^ + | + = help: no format specifier are supported in this position warning: unmatched `}` found --> $DIR/broken_format.rs:2:42 @@ -51,7 +63,7 @@ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {{Test } thing - --> $DIR/broken_format.rs:36:13 + --> $DIR/broken_format.rs:43:13 | LL | check_1(()); | ------- ^^ the trait `ImportantTrait1` is not implemented for `()` @@ -64,7 +76,7 @@ LL | trait ImportantTrait1 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_1` - --> $DIR/broken_format.rs:29:20 + --> $DIR/broken_format.rs:35:20 | LL | fn check_1(_: impl ImportantTrait1) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_1` @@ -79,7 +91,7 @@ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {} - --> $DIR/broken_format.rs:38:13 + --> $DIR/broken_format.rs:45:13 | LL | check_2(()); | ------- ^^ the trait `ImportantTrait2` is not implemented for `()` @@ -92,11 +104,20 @@ LL | trait ImportantTrait2 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_2` - --> $DIR/broken_format.rs:30:20 + --> $DIR/broken_format.rs:36:20 | LL | fn check_2(_: impl ImportantTrait2) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_2` +warning: invalid format specifier + --> $DIR/broken_format.rs:12:50 + | +LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] + | ^ + | + = help: no format specifier are supported in this position + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + warning: positional format arguments are not allowed here --> $DIR/broken_format.rs:12:49 | @@ -107,7 +128,7 @@ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {1} - --> $DIR/broken_format.rs:40:13 + --> $DIR/broken_format.rs:47:13 | LL | check_3(()); | ------- ^^ the trait `ImportantTrait3` is not implemented for `()` @@ -115,27 +136,27 @@ | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:15:1 + --> $DIR/broken_format.rs:17:1 | LL | trait ImportantTrait3 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_3` - --> $DIR/broken_format.rs:31:20 + --> $DIR/broken_format.rs:37:20 | LL | fn check_3(_: impl ImportantTrait3) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_3` warning: invalid format specifier - --> $DIR/broken_format.rs:17:42 + --> $DIR/broken_format.rs:19:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^ | = help: no format specifier are supported in this position = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test () - --> $DIR/broken_format.rs:42:13 + --> $DIR/broken_format.rs:49:13 | LL | check_4(()); | ------- ^^ the trait `ImportantTrait4` is not implemented for `()` @@ -143,34 +164,27 @@ | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:20:1 + --> $DIR/broken_format.rs:22:1 | LL | trait ImportantTrait4 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_4` - --> $DIR/broken_format.rs:32:20 + --> $DIR/broken_format.rs:38:20 | LL | fn check_4(_: impl ImportantTrait4) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_4` -warning: expected `}`, found `!` - --> $DIR/broken_format.rs:22:42 +warning: invalid format specifier + --> $DIR/broken_format.rs:24:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ + | ^^ | + = help: no format specifier are supported in this position = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -warning: unmatched `}` found - --> $DIR/broken_format.rs:22:42 - | -LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0277]: Test {Self:!} - --> $DIR/broken_format.rs:44:13 +error[E0277]: Test () + --> $DIR/broken_format.rs:51:13 | LL | check_5(()); | ------- ^^ the trait `ImportantTrait5` is not implemented for `()` @@ -183,11 +197,39 @@ LL | trait ImportantTrait5 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_5` - --> $DIR/broken_format.rs:33:20 + --> $DIR/broken_format.rs:39:20 | LL | fn check_5(_: impl ImportantTrait5) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_5` -error: aborting due to 5 previous errors; 12 warnings emitted +warning: invalid format specifier + --> $DIR/broken_format.rs:29:53 + | +LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")] + | ^ + | + = help: no format specifier are supported in this position + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: Test () + --> $DIR/broken_format.rs:53:13 + | +LL | check_6(()); + | ------- ^^ the trait `ImportantTrait6` is not implemented for `()` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/broken_format.rs:32:1 + | +LL | trait ImportantTrait6 {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `check_6` + --> $DIR/broken_format.rs:40:20 + | +LL | fn check_6(_: impl ImportantTrait6) {} + | ^^^^^^^^^^^^^^^ required by this bound in `check_6` + +error: aborting due to 6 previous errors; 14 warnings emitted For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr index 4ca1791..6b84a64 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
@@ -96,3 +96,108 @@ warning: 5 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:18:1 + | +LL | fn m() { + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:22:17 + | +LL | true => Default::default(), + | ^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let x: () = match true { + | ++++ + +Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:30:1 + | +LL | fn q() -> Option<()> { + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:37:5 + | +LL | deserialize()?; + | ^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | deserialize::<()>()?; + | ++++++ + +Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:47:1 + | +LL | fn meow() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `(): From<!>` will fail + --> $DIR/never-type-fallback-breaking.rs:50:5 + | +LL | help(1)?; + | ^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | help::<(), _>(1)?; + | +++++++++ + +Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:59:1 + | +LL | pub fn fallback_return() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:62:19 + | +LL | takes_apit(|| Default::default())?; + | ^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | takes_apit::<()>(|| Default::default())?; + | ++++++ + +Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:73:1 + | +LL | fn fully_apit() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:76:17 + | +LL | takes_apit2(mk()?); + | ^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | takes_apit2(mk::<()>()?); + | ++++++ +
diff --git a/tests/ui/enum/dead-code-associated-function.rs b/tests/ui/enum/dead-code-associated-function.rs new file mode 100644 index 0000000..d172ceb --- /dev/null +++ b/tests/ui/enum/dead-code-associated-function.rs
@@ -0,0 +1,20 @@ +//@ check-pass +#![warn(dead_code)] + +enum E { + F(), + C(), +} + +impl E { + #[expect(non_snake_case)] + fn F() {} + //~^ WARN: associated items `F` and `C` are never used + + const C: () = (); +} + +fn main() { + let _: E = E::F(); + let _: E = E::C(); +}
diff --git a/tests/ui/enum/dead-code-associated-function.stderr b/tests/ui/enum/dead-code-associated-function.stderr new file mode 100644 index 0000000..e3c1a4c --- /dev/null +++ b/tests/ui/enum/dead-code-associated-function.stderr
@@ -0,0 +1,30 @@ +warning: associated items `F` and `C` are never used + --> $DIR/dead-code-associated-function.rs:11:8 + | +LL | impl E { + | ------ associated items in this implementation +LL | #[expect(non_snake_case)] +LL | fn F() {} + | ^ +... +LL | const C: () = (); + | ^ + | +note: it is impossible to refer to the associated function `F` because it is shadowed by this enum variant with the same name + --> $DIR/dead-code-associated-function.rs:5:5 + | +LL | F(), + | ^ +note: it is impossible to refer to the associated constant `C` because it is shadowed by this enum variant with the same name + --> $DIR/dead-code-associated-function.rs:6:5 + | +LL | C(), + | ^ +note: the lint level is defined here + --> $DIR/dead-code-associated-function.rs:2:9 + | +LL | #![warn(dead_code)] + | ^^^^^^^^^ + +warning: 1 warning emitted +
diff --git a/tests/ui/error-codes/E0045.stderr b/tests/ui/error-codes/E0045.stderr index b8ee31a..ecf5f4e 100644 --- a/tests/ui/error-codes/E0045.stderr +++ b/tests/ui/error-codes/E0045.stderr
@@ -1,4 +1,4 @@ -error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi` +error[E0045]: C-variadic functions with the "Rust" calling convention are not supported --> $DIR/E0045.rs:1:17 | LL | extern "Rust" { fn foo(x: u8, ...); }
diff --git a/tests/ui/error-codes/E0161.rs b/tests/ui/error-codes/E0161.rs index 3a9b93d..1ae2a67 100644 --- a/tests/ui/error-codes/E0161.rs +++ b/tests/ui/error-codes/E0161.rs
@@ -1,12 +1,7 @@ // Check that E0161 is a hard error in all possible configurations that might // affect it. -//@ revisions: base ul -//@[base] check-fail -//@[ul] check-pass - -#![allow(incomplete_features)] -#![cfg_attr(ul, feature(unsized_locals))] +#![crate_type = "lib"] trait Bar { fn f(self); @@ -14,7 +9,5 @@ trait Bar { fn foo(x: Box<dyn Bar>) { x.f(); - //[base]~^ ERROR E0161 + //~^ ERROR E0161 } - -fn main() {}
diff --git a/tests/ui/error-codes/E0161.base.stderr b/tests/ui/error-codes/E0161.stderr similarity index 90% rename from tests/ui/error-codes/E0161.base.stderr rename to tests/ui/error-codes/E0161.stderr index d80de66..f84f348 100644 --- a/tests/ui/error-codes/E0161.base.stderr +++ b/tests/ui/error-codes/E0161.stderr
@@ -1,5 +1,5 @@ error[E0161]: cannot move a value of type `dyn Bar` - --> $DIR/E0161.rs:16:5 + --> $DIR/E0161.rs:11:5 | LL | x.f(); | ^ the size of `dyn Bar` cannot be statically determined
diff --git a/tests/ui/extern/unsized-extern-derefmove.rs b/tests/ui/extern/unsized-extern-derefmove.rs new file mode 100644 index 0000000..4ec9e53 --- /dev/null +++ b/tests/ui/extern/unsized-extern-derefmove.rs
@@ -0,0 +1,15 @@ +//! Regression test for #79409 + +#![feature(extern_types)] + +unsafe extern "C" { + type Device; +} + +unsafe fn make_device() -> Box<Device> { + Box::from_raw(0 as *mut _) +} + +fn main() { + let d: Device = unsafe { *make_device() }; //~ERROR the size for values of type `Device` cannot be known at compilation time +}
diff --git a/tests/ui/extern/unsized-extern-derefmove.stderr b/tests/ui/extern/unsized-extern-derefmove.stderr new file mode 100644 index 0000000..c43184d --- /dev/null +++ b/tests/ui/extern/unsized-extern-derefmove.stderr
@@ -0,0 +1,16 @@ +error[E0277]: the size for values of type `Device` cannot be known at compilation time + --> $DIR/unsized-extern-derefmove.rs:14:9 + | +LL | let d: Device = unsafe { *make_device() }; + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `Device` + = note: all local variables must have a statically known size +help: consider borrowing here + | +LL | let d: &Device = unsafe { *make_device() }; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.rs b/tests/ui/feature-gates/feature-gate-abi-custom.rs new file mode 100644 index 0000000..3ddce97 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi-custom.rs
@@ -0,0 +1,51 @@ +//@ add-core-stubs +//@ needs-asm-support +#![no_core] +#![feature(no_core, lang_items)] +#![crate_type = "rlib"] + +extern crate minicore; +use minicore::*; + +#[unsafe(naked)] +unsafe extern "custom" fn f7() { + //~^ ERROR "custom" ABI is experimental + naked_asm!("") +} +trait Tr { + extern "custom" fn m7(); + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + #[unsafe(naked)] + extern "custom" fn dm7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +struct S; + +// Methods in trait impl +impl Tr for S { + #[unsafe(naked)] + extern "custom" fn m7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +// Methods in inherent impl +impl S { + #[unsafe(naked)] + extern "custom" fn im7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +type A7 = extern "custom" fn(); //~ ERROR "custom" ABI is experimental + +extern "custom" {} //~ ERROR "custom" ABI is experimental
diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.stderr b/tests/ui/feature-gates/feature-gate-abi-custom.stderr new file mode 100644 index 0000000..e6dce01 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi-custom.stderr
@@ -0,0 +1,117 @@ +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:16:5 + | +LL | extern "custom" fn m7(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn m7(); + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:20:5 + | +LL | extern "custom" fn dm7() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn dm7() { + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:32:5 + | +LL | extern "custom" fn m7() { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn m7() { + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:42:5 + | +LL | extern "custom" fn im7() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn im7() { + | ++++++ + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:11:15 + | +LL | unsafe extern "custom" fn f7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:16:12 + | +LL | extern "custom" fn m7(); + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:20:12 + | +LL | extern "custom" fn dm7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:32:12 + | +LL | extern "custom" fn m7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:42:12 + | +LL | extern "custom" fn im7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:49:18 + | +LL | type A7 = extern "custom" fn(); + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:51:8 + | +LL | extern "custom" {} + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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 11 previous errors + +For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr new file mode 100644 index 0000000..fca32c5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr
@@ -0,0 +1,73 @@ +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 + | +LL | extern "gpu-kernel" fn f1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 + | +LL | extern "gpu-kernel" fn m1(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 + | +LL | extern "gpu-kernel" fn dm1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 + | +LL | extern "gpu-kernel" fn m1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 + | +LL | extern "gpu-kernel" fn im1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 + | +LL | type A1 = extern "gpu-kernel" fn(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 + | +LL | extern "gpu-kernel" {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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 7 previous errors + +For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr similarity index 88% rename from tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr rename to tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr index aa9c67f..cc81289 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr
@@ -1,5 +1,5 @@ error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:11:8 + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 | LL | extern "gpu-kernel" fn f1(_: ()) {} | ^^^^^^^^^^^^ @@ -9,7 +9,7 @@ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:16:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 | LL | extern "gpu-kernel" fn m1(_: ()); | ^^^^^^^^^^^^ @@ -19,7 +19,7 @@ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:18:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 | LL | extern "gpu-kernel" fn dm1(_: ()) {} | ^^^^^^^^^^^^ @@ -29,7 +29,7 @@ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:26:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 | LL | extern "gpu-kernel" fn m1(_: ()) {} | ^^^^^^^^^^^^ @@ -39,7 +39,7 @@ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 | LL | extern "gpu-kernel" fn im1(_: ()) {} | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:18 + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^ @@ -59,7 +59,7 @@ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:8 + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 | LL | extern "gpu-kernel" {} | ^^^^^^^^^^^^ @@ -69,7 +69,7 @@ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: the calling convention "gpu-kernel" is not supported on this target - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:11 + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,31 +79,31 @@ = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:1 + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:1 | LL | extern "gpu-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:11:1 + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:1 | LL | extern "gpu-kernel" fn f1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:18:5 + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:5 | LL | extern "gpu-kernel" fn dm1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:26:5 + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:5 | LL | extern "gpu-kernel" fn m1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:32:5 + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:5 | LL | extern "gpu-kernel" fn im1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ For more information about an error, try `rustc --explain E0570`. Future incompatibility report: Future breakage diagnostic: warning: the calling convention "gpu-kernel" is not supported on this target - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:11 + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr new file mode 100644 index 0000000..fca32c5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr
@@ -0,0 +1,73 @@ +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 + | +LL | extern "gpu-kernel" fn f1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 + | +LL | extern "gpu-kernel" fn m1(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 + | +LL | extern "gpu-kernel" fn dm1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 + | +LL | extern "gpu-kernel" fn m1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 + | +LL | extern "gpu-kernel" fn im1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 + | +LL | type A1 = extern "gpu-kernel" fn(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 + | +LL | extern "gpu-kernel" {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information + = help: add `#![feature(abi_gpu_kernel)]` 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 7 previous errors + +For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs index d9027b4..7b1ee681 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs
@@ -1,5 +1,10 @@ +//@ revisions: HOST AMDGPU NVPTX //@ add-core-stubs //@ compile-flags: --crate-type=rlib +//@[AMDGPU] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx1100 +//@[AMDGPU] needs-llvm-components: amdgpu +//@[NVPTX] compile-flags: --target nvptx64-nvidia-cuda +//@[NVPTX] needs-llvm-components: nvptx #![feature(no_core, lang_items)] #![no_core] @@ -9,14 +14,14 @@ // Functions extern "gpu-kernel" fn f1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change -//~^ ERROR is not a supported ABI +//[HOST]~^ ERROR is not a supported ABI // Methods in trait definition trait Tr { extern "gpu-kernel" fn m1(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change extern "gpu-kernel" fn dm1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change - //~^ ERROR is not a supported ABI + //[HOST]~^ ERROR is not a supported ABI } struct S; @@ -24,20 +29,20 @@ extern "gpu-kernel" fn dm1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental // Methods in trait impl impl Tr for S { extern "gpu-kernel" fn m1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change - //~^ ERROR is not a supported ABI + //[HOST]~^ ERROR is not a supported ABI } // Methods in inherent impl impl S { extern "gpu-kernel" fn im1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change - //~^ ERROR is not a supported ABI + //[HOST]~^ ERROR is not a supported ABI } // Function pointer types type A1 = extern "gpu-kernel" fn(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change -//~^ WARN the calling convention "gpu-kernel" is not supported on this target -//~^^ WARN this was previously accepted by the compiler but is being phased out +//[HOST]~^ WARNING the calling convention "gpu-kernel" is not supported on this target [unsupported_fn_ptr_calling_conventions] +//[HOST]~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! // Foreign modules extern "gpu-kernel" {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change -//~^ ERROR is not a supported ABI +//[HOST]~^ ERROR is not a supported ABI
diff --git a/tests/ui/feature-gates/feature-gate-extern_system_varargs.rs b/tests/ui/feature-gates/feature-gate-extern_system_varargs.rs index f5cfbe7..2206776 100644 --- a/tests/ui/feature-gates/feature-gate-extern_system_varargs.rs +++ b/tests/ui/feature-gates/feature-gate-extern_system_varargs.rs
@@ -1,5 +1,5 @@ fn system(f: extern "system" fn(usize, ...)) { - //~^ ERROR using calling conventions other than `C` or `cdecl` for varargs functions is unstable + //~^ ERROR unstable f(22, 44); }
diff --git a/tests/ui/feature-gates/feature-gate-extern_system_varargs.stderr b/tests/ui/feature-gates/feature-gate-extern_system_varargs.stderr index f3206b2..1209275 100644 --- a/tests/ui/feature-gates/feature-gate-extern_system_varargs.stderr +++ b/tests/ui/feature-gates/feature-gate-extern_system_varargs.stderr
@@ -1,4 +1,4 @@ -error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable +error[E0658]: C-variadic functions with the "system" calling convention are unstable --> $DIR/feature-gate-extern_system_varargs.rs:1:14 | LL | fn system(f: extern "system" fn(usize, ...)) {
diff --git a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs index d1f6f47..ffb444c 100644 --- a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs +++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs
@@ -1,6 +1,8 @@ // check that `pattern_complexity_limit` is feature-gated #![pattern_complexity_limit = "42"] -//~^ ERROR: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests +//~^ ERROR: use of an internal attribute [E0658] +//~| NOTE the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable +//~| NOTE: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr index e6f1771..9ddea86 100644 --- a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr +++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr
@@ -1,11 +1,12 @@ -error[E0658]: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests and will never be stable +error[E0658]: use of an internal attribute --> $DIR/feature-gate-pattern-complexity-limit.rs:3:1 | LL | #![pattern_complexity_limit = "42"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable + = note: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests error: aborting due to 1 previous error
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs index 025b4b5..1755672 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs
@@ -1,6 +1,12 @@ // Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate. -#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable -#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable - +#[rustc_variance] +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests +#[rustc_nonnull_optimization_guaranteed] +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library +//~| NOTE the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 0f760e0..159d383 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
@@ -1,21 +1,23 @@ -error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable +error[E0658]: use of an internal attribute --> $DIR/feature-gate-rustc-attrs-1.rs:3:1 | LL | #[rustc_variance] | ^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_variance]` attribute is used for rustc unit tests -error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable - (note that the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized) - --> $DIR/feature-gate-rustc-attrs-1.rs:4:1 +error[E0658]: use of an internal attribute + --> $DIR/feature-gate-rustc-attrs-1.rs:7:1 | LL | #[rustc_nonnull_optimization_guaranteed] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library + = note: the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized error: aborting due to 2 previous errors
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs index c985298..e7b2eca 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs
@@ -8,15 +8,19 @@ mod unknown { pub macro rustc() {} } #[rustc::unknown] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~| ERROR expected attribute, found macro `rustc::unknown` +//~| NOTE not an attribute fn f() {} #[unknown::rustc] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~| ERROR expected attribute, found macro `unknown::rustc` +//~| NOTE not an attribute fn g() {} #[rustc_dummy] -//~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_dummy]` attribute is used for rustc unit tests #[rustc_unknown] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~| ERROR cannot find attribute `rustc_unknown` in this scope
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr index c7a5ef3..d586038 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
@@ -11,37 +11,38 @@ | ^^^^^^^^^^^^^^ not an attribute error: attributes starting with `rustc` are reserved for use by the `rustc` compiler - --> $DIR/feature-gate-rustc-attrs.rs:13:12 + --> $DIR/feature-gate-rustc-attrs.rs:14:12 | LL | #[unknown::rustc] | ^^^^^ error: expected attribute, found macro `unknown::rustc` - --> $DIR/feature-gate-rustc-attrs.rs:13:3 + --> $DIR/feature-gate-rustc-attrs.rs:14:3 | LL | #[unknown::rustc] | ^^^^^^^^^^^^^^ not an attribute error: attributes starting with `rustc` are reserved for use by the `rustc` compiler - --> $DIR/feature-gate-rustc-attrs.rs:20:3 + --> $DIR/feature-gate-rustc-attrs.rs:24:3 | LL | #[rustc_unknown] | ^^^^^^^^^^^^^ error: cannot find attribute `rustc_unknown` in this scope - --> $DIR/feature-gate-rustc-attrs.rs:20:3 + --> $DIR/feature-gate-rustc-attrs.rs:24:3 | LL | #[rustc_unknown] | ^^^^^^^^^^^^^ -error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests and will never be stable - --> $DIR/feature-gate-rustc-attrs.rs:18:1 +error[E0658]: use of an internal attribute + --> $DIR/feature-gate-rustc-attrs.rs:20:1 | LL | #[rustc_dummy] | ^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_dummy]` attribute is used for rustc unit tests error: aborting due to 7 previous errors
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index 02a56c7..7fb11b7 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -11,9 +11,11 @@ #![macro_export] //~^ ERROR: `macro_export` attribute cannot be used at crate level -#![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify +#![rustc_main] //~^ ERROR: `rustc_main` attribute cannot be used at crate level -//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +//~| ERROR: use of an internal attribute [E0658] +//~| NOTE: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable +//~| NOTE: the `#[rustc_main]` attribute is used internally to specify test entry point function #![repr()] //~^ ERROR: `repr` attribute cannot be used at crate level #![path = "3800"]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 5c2a3ae..bdca616 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -1,14 +1,15 @@ -error[E0658]: the `#[rustc_main]` attribute is used internally to specify test entry point function +error[E0658]: use of an internal attribute --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1 | LL | #![rustc_main] | ^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_main]` attribute is used internally to specify test entry point function error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ @@ -18,7 +19,7 @@ = note: `#[deny(ill_formed_attribute_input)]` on by default error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1 | LL | #[inline] | ^^^^^^^^^ @@ -29,7 +30,7 @@ | |_- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:1 | LL | #[no_link] | ^^^^^^^^^^ @@ -43,7 +44,7 @@ | |_- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1 | LL | #[export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +58,7 @@ | |_- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:8 | LL | #[repr(C)] | ^ @@ -70,7 +71,7 @@ | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:8 | LL | #[repr(Rust)] | ^^^^ @@ -83,19 +84,19 @@ | |_- not a struct, enum, or union error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 | LL | #![no_link] | ^^^^^^^^^^^ not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 | LL | #![export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 | LL | #![inline] | ^^^^^^^^^^ not a function or closure @@ -131,7 +132,7 @@ | error: `path` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ @@ -146,7 +147,7 @@ | error: `automatically_derived` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1 | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -161,7 +162,7 @@ | error: `repr` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 | LL | #![repr()] | ^^^^^^^^^^ @@ -176,139 +177,139 @@ | error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17 | LL | mod inner { #![inline] } | ------------^^^^^^^^^^-- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5 | LL | #[inline] struct S; | ^^^^^^^^^ --------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:5 | LL | #[inline] type T = S; | ^^^^^^^^^ ----------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:5 | LL | #[inline] impl S { } | ^^^^^^^^^ ---------- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:17 | LL | mod inner { #![no_link] } | ------------^^^^^^^^^^^-- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:74:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ --------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^----------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17 | LL | mod inner { #![export_name="2200"] } | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5 | LL | #[export_name = "2200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5 | LL | #[export_name = "2200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5 | LL | #[export_name = "2200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:9 | LL | #[export_name = "2200"] fn foo(); | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:9 | LL | #[export_name = "2200"] fn bar() {} | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:25 | LL | mod inner { #![repr(C)] } | --------------------^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:12 | LL | #[repr(C)] fn f() { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12 | LL | #[repr(C)] type T = S; | ^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12 | LL | #[repr(C)] impl S { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:153:25 | LL | mod inner { #![repr(Rust)] } | --------------------^^^^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:157:12 | LL | #[repr(Rust)] fn f() { } | ^^^^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:163:12 | LL | #[repr(Rust)] type T = S; | ^^^^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:167:12 | LL | #[repr(Rust)] impl S { } | ^^^^ ---------- not a struct, enum, or union
diff --git a/tests/ui/force-inlining/gate.rs b/tests/ui/force-inlining/gate.rs index cea094c..5918b0d 100644 --- a/tests/ui/force-inlining/gate.rs +++ b/tests/ui/force-inlining/gate.rs
@@ -2,11 +2,15 @@ #![allow(internal_features)] #[rustc_force_inline] -//~^ ERROR #[rustc_force_inline] forces a free function to be inlined +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable +//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined pub fn bare() { } #[rustc_force_inline = "the test requires it"] -//~^ ERROR #[rustc_force_inline] forces a free function to be inlined +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable +//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined pub fn justified() { }
diff --git a/tests/ui/force-inlining/gate.stderr b/tests/ui/force-inlining/gate.stderr index 964d43f..6c2df08 100644 --- a/tests/ui/force-inlining/gate.stderr +++ b/tests/ui/force-inlining/gate.stderr
@@ -1,20 +1,22 @@ -error[E0658]: #[rustc_force_inline] forces a free function to be inlined +error[E0658]: use of an internal attribute --> $DIR/gate.rs:4:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable + = note: `#[rustc_force_inline]` forces a free function to be inlined -error[E0658]: #[rustc_force_inline] forces a free function to be inlined - --> $DIR/gate.rs:9:1 +error[E0658]: use of an internal attribute + --> $DIR/gate.rs:11:1 | LL | #[rustc_force_inline = "the test requires it"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable + = note: `#[rustc_force_inline]` forces a free function to be inlined error: aborting due to 2 previous errors
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs index e00a31e..cca6085 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs
@@ -20,7 +20,7 @@ pub trait Inject Self: Sized, { type I: for<'a> FamilyLt<'a>; - fn inject(_: &()) -> <Self::I as FamilyLt>::Out; + fn inject(_: &()) -> <Self::I as FamilyLt<'_>>::Out; } impl<T: 'static> Inject for RefMutFamily<T> {
diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr index 54ceec0..5caf0eb 100644 --- a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr
@@ -1,9 +1,22 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` - --> $DIR/auto-trait-selection-freeze.rs:19:5 +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection-freeze.rs:19:16 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` + | ^^^^^^^^ ----- type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `is_trait` + | + = note: cannot satisfy `_: Trait<_>` +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection-freeze.rs:11:16 + | +LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } + | ++++++++ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr index 7acb9fd..d34fdcc 100644 --- a/tests/ui/impl-trait/auto-trait-selection.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr
@@ -1,9 +1,22 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` - --> $DIR/auto-trait-selection.rs:15:5 +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection.rs:15:16 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` + | ^^^^^^^^ ----- type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `is_trait` + | + = note: cannot satisfy `_: Trait<_>` +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection.rs:7:16 + | +LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } + | ++++++++ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr index 9632d2c..f2e249f 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr
@@ -25,7 +25,7 @@ | = note: `LineStream` must be used in combination with a concrete type within the same impl -error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` +error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()` --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs index 0b507ed..7cf155c 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
@@ -29,7 +29,7 @@ impl X for Y { fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} //~^ ERROR method `line_stream` is not a member of trait `X` //[current]~^^ ERROR `()` is not a future - //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` + //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()` //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` }
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr index a3609b9..db57be7 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
@@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` - --> $DIR/recursive-in-exhaustiveness.rs:19:17 +error[E0284]: type annotations needed: cannot normalize `build<_>::{opaque#0}` + --> $DIR/recursive-in-exhaustiveness.rs:20:5 | -LL | let (x,) = (build(x),); - | ^^^^^^^^ cannot satisfy `impl Sized == _` +LL | build(x) + | ^^^^^^^^ cannot normalize `build<_>::{opaque#0}` error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` --> $DIR/recursive-in-exhaustiveness.rs:30:6
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs index fa8fa0e..dabef22 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
@@ -17,8 +17,8 @@ fn build<T>(x: T) -> impl Sized { //[current]~^ ERROR cannot resolve opaque type let (x,) = (build(x),); - //[next]~^ ERROR type annotations needed build(x) + //[next]~^ ERROR type annotations needed: cannot normalize `build<_>::{opaque#0}` } // Opaque<T> = (Opaque<T>,)
diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr index 1a4c0f5..fac4776 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr
@@ -1,9 +1,9 @@ -error[E0284]: type annotations needed: cannot satisfy `_ == A` - --> $DIR/two_tait_defining_each_other2.rs:12:8 +error[E0282]: type annotations needed + --> $DIR/two_tait_defining_each_other2.rs:12:11 | LL | fn muh(x: A) -> B { - | ^ cannot satisfy `_ == A` + | ^ cannot infer type error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs index 6c454bb..ec29632 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs
@@ -10,7 +10,7 @@ trait Foo {} #[define_opaque(A, B)] fn muh(x: A) -> B { - //[next]~^ ERROR: cannot satisfy `_ == A` + //[next]~^ ERROR: type annotations needed x // B's hidden type is A (opaquely) //[current]~^ ERROR opaque type's hidden type cannot be another opaque type }
diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index 30a523f..904da71 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs
@@ -23,12 +23,12 @@ mod m { #[cfg(target_arch = "x86")] pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 4); + assert_eq!(crate::rusti::align_of::<u64>(), 4); } #[cfg(not(target_arch = "x86"))] pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } } @@ -36,21 +36,21 @@ pub fn main() { mod m { #[cfg(target_arch = "x86_64")] pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } } #[cfg(target_os = "windows")] mod m { pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } } #[cfg(target_family = "wasm")] mod m { pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } }
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr index d92836a..8d120ae 100644 --- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
@@ -19,7 +19,7 @@ help: try using a const generic argument instead | LL - std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); -LL + std::arch::x86_64::_mm_blend_ps::<{ 5 + (|| ()) }>(loop {}, loop {}); +LL + std::arch::x86_64::_mm_blend_ps::<{ 5 + || () }>(loop {}, loop {}); | error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items @@ -81,7 +81,7 @@ help: try using a const generic argument instead | LL - std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()); -LL + std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + (|| ()) }>(loop {}, loop {}); +LL + std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + || () }>(loop {}, loop {}); | error: aborting due to 7 previous errors
diff --git a/tests/ui/issues/issue-15756.stderr b/tests/ui/issues/issue-15756.stderr index af50fe46..a487d36 100644 --- a/tests/ui/issues/issue-15756.stderr +++ b/tests/ui/issues/issue-15756.stderr
@@ -6,7 +6,6 @@ | = help: the trait `Sized` is not implemented for `[T]` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature error: aborting due to 1 previous error
diff --git a/tests/ui/issues/issue-28561.rs b/tests/ui/issues/issue-28561.rs index f9b0ceb..642b219 100644 --- a/tests/ui/issues/issue-28561.rs +++ b/tests/ui/issues/issue-28561.rs
@@ -37,6 +37,7 @@ struct Array<T> { } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[allow(unpredictable_function_pointer_comparisons)] struct Fn<A, B, C, D, E, F, G, H, I, J, K, L> { f00: fn(), f01: fn(A),
diff --git a/tests/ui/iterators/collect-into-slice.stderr b/tests/ui/iterators/collect-into-slice.stderr index 56f1bf7..e5729a2 100644 --- a/tests/ui/iterators/collect-into-slice.stderr +++ b/tests/ui/iterators/collect-into-slice.stderr
@@ -16,7 +16,6 @@ | = help: the trait `Sized` is not implemented for `[i32]` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `[i32]` cannot be known at compilation time --> $DIR/collect-into-slice.rs:6:38
diff --git a/tests/ui/label/label_misspelled.stderr b/tests/ui/label/label_misspelled.stderr index 3f4020e..9f9d32d 100644 --- a/tests/ui/label/label_misspelled.stderr +++ b/tests/ui/label/label_misspelled.stderr
@@ -78,6 +78,14 @@ | not found in this scope | help: use the similarly named label: `'for_loop` +warning: denote infinite loops with `loop { ... }` + --> $DIR/label_misspelled.rs:4:5 + | +LL | 'while_loop: while true { + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` + | + = note: `#[warn(while_true)]` on by default + warning: unused label --> $DIR/label_misspelled.rs:4:5 | @@ -90,14 +98,6 @@ LL | #![warn(unused_labels)] | ^^^^^^^^^^^^^ -warning: denote infinite loops with `loop { ... }` - --> $DIR/label_misspelled.rs:4:5 - | -LL | 'while_loop: while true { - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` - | - = note: `#[warn(while_true)]` on by default - warning: unused label --> $DIR/label_misspelled.rs:9:5 | @@ -122,12 +122,6 @@ LL | 'while_loop: while true { | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` -warning: unused label - --> $DIR/label_misspelled.rs:47:5 - | -LL | 'while_loop: while true { - | ^^^^^^^^^^^ - warning: denote infinite loops with `loop { ... }` --> $DIR/label_misspelled.rs:47:5 | @@ -135,6 +129,12 @@ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` warning: unused label + --> $DIR/label_misspelled.rs:47:5 + | +LL | 'while_loop: while true { + | ^^^^^^^^^^^ + +warning: unused label --> $DIR/label_misspelled.rs:52:5 | LL | 'while_let: while let Some(_) = Some(()) {
diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr index 1a43fd4..5f6a609 100644 --- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
@@ -24,7 +24,7 @@ LL | static CHECK: () = assert!(align_of::<P2>() == 1); | ^^^^^^^^^^^^^^^^ evaluation of `CHECK` failed inside this call | -note: inside `align_of::<P2>` +note: inside `std::mem::align_of::<P2>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: aborting due to 2 previous errors
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs index 6d8487b..b98423a 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
@@ -220,6 +220,45 @@ fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { } } +/// Trait functions are represented differently in the HIR. Make sure +/// we visit them. +mod trait_functions { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + trait TheTrait { + fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; + //~^ ERROR lifetime flowing from input to output with different syntax + + fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; + //~^ ERROR lifetime flowing from input to output with different syntax + } + + impl TheTrait for &u8 { + fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) + } + + fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(self) + } + } +} + +/// Extern functions are represented differently in the HIR. Make sure +/// we visit them. +mod foreign_functions { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + extern "Rust" { + fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; + //~^ ERROR lifetime flowing from input to output with different syntax + } +} + /// These usages are expected to **not** trigger the lint mod acceptable_uses { #[derive(Copy, Clone)]
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr index 0ec16a2..108b3f1 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
@@ -469,5 +469,70 @@ LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { | ++ ++ -error: aborting due to 34 previous errors +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:230:45 + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; + | ^^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>; + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:233:49 + | +LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; + | ^^^^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_>; + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:238:45 + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { + | ^^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:243:49 + | +LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { + | ^^^^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:257:45 + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; + | ^^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>; + | ++++ + +error: aborting due to 39 previous errors
diff --git a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs new file mode 100644 index 0000000..bb537f8 --- /dev/null +++ b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs
@@ -0,0 +1,36 @@ +//@ edition:2024 + +fn temp() -> String { + String::from("Hello") +} + +#[derive(Debug)] +struct X<'a>(&'a String); + +trait T<'a> { + const A: X<'a>; + const B: X<'a>; +} + +impl<'a> T<'a> for X<'a> { + // Check both Self() and X() syntax: + const A: X<'a> = Self(&String::new()); + const B: X<'a> = X(&String::new()); +} + +fn main() { + let a = &temp(); + let b = Some(&temp()); + let c = Option::Some::<&String>(&temp()); + use Option::Some as S; + let d = S(&temp()); + let e = X(&temp()); + let f = Some(Ok::<_, ()>(std::borrow::Cow::Borrowed(if true { + &temp() + } else { + panic!() + }))); + let some = Some; // Turn the ctor into a regular function. + let g = some(&temp()); //~ERROR temporary value dropped while borrowe + println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}"); +}
diff --git a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr new file mode 100644 index 0000000..66f9140 --- /dev/null +++ b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr
@@ -0,0 +1,19 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/temporary-lifetime-extension-tuple-ctor.rs:34:19 + | +LL | let g = some(&temp()); + | ^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}"); + | ----- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = temp(); +LL ~ let g = some(&binding); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs index df69782..9babc20 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs
@@ -1,6 +1,14 @@ -//@ only-x86_64 -//@ only-windows +//@ add-core-stubs +//@ compile-flags: --target x86_64-pc-windows-msvc //@ compile-flags: --crate-type lib --emit link +//@ needs-llvm-components: x86 +#![no_core] +#![feature(no_core)] +extern crate minicore; + +// It may seem weird this is a cross-platform-testable thing, since doesn't it test linkage? +// However the main thing we are testing is an *error*, so it works fine! + #[link(name = "foo", kind = "raw-dylib")] extern "stdcall" { //~^ WARN: calling convention not supported on this target
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr index e7a32f4..95ea908 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
@@ -1,5 +1,5 @@ warning: use of calling convention not supported on this target - --> $DIR/unsupported-abi.rs:5:1 + --> $DIR/unsupported-abi.rs:13:1 | LL | / extern "stdcall" { LL | | @@ -15,27 +15,10 @@ = note: `#[warn(unsupported_calling_conventions)]` on by default error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture - --> $DIR/unsupported-abi.rs:8:5 + --> $DIR/unsupported-abi.rs:16:5 | LL | fn f(x: i32); | ^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted -Future incompatibility report: Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported-abi.rs:5:1 - | -LL | / extern "stdcall" { -LL | | -LL | | -LL | | fn f(x: i32); -LL | | -LL | | } - | |_^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default -
diff --git a/tests/ui/lint/expansion-time.rs b/tests/ui/lint/expansion-time.rs index 5ffb0c7..2c59bf0 100644 --- a/tests/ui/lint/expansion-time.rs +++ b/tests/ui/lint/expansion-time.rs
@@ -5,10 +5,6 @@ macro_rules! foo { ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator } -#[warn(missing_fragment_specifier)] -macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier - //~| WARN this was previously accepted - #[deprecated = "reason"] macro_rules! deprecated { () => {}
diff --git a/tests/ui/lint/expansion-time.stderr b/tests/ui/lint/expansion-time.stderr index f24d1b6..b1154d1 100644 --- a/tests/ui/lint/expansion-time.stderr +++ b/tests/ui/lint/expansion-time.stderr
@@ -12,20 +12,6 @@ LL | #[warn(meta_variable_misuse)] | ^^^^^^^^^^^^^^^^^^^^ -warning: missing fragment specifier - --> $DIR/expansion-time.rs:9:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 - | -LL | #[warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - warning: include macro expected single expression in source --> $DIR/expansion-time-include.rs:4:1 | @@ -33,25 +19,10 @@ | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:22:8 + --> $DIR/expansion-time.rs:18:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/expansion-time.rs:9:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 - | -LL | #[warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: 2 warnings emitted
diff --git a/tests/ui/lint/fn-ptr-comparisons-some.rs b/tests/ui/lint/fn-ptr-comparisons-some.rs index 152e16b..c6ddd75 100644 --- a/tests/ui/lint/fn-ptr-comparisons-some.rs +++ b/tests/ui/lint/fn-ptr-comparisons-some.rs
@@ -12,6 +12,6 @@ fn main() { let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn()); //~^ WARN function pointer comparisons - // Undecided as of https://github.com/rust-lang/rust/pull/134536 assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn())); + //~^ WARN function pointer comparisons }
diff --git a/tests/ui/lint/fn-ptr-comparisons-some.stderr b/tests/ui/lint/fn-ptr-comparisons-some.stderr index eefad05..522c439 100644 --- a/tests/ui/lint/fn-ptr-comparisons-some.stderr +++ b/tests/ui/lint/fn-ptr-comparisons-some.stderr
@@ -9,5 +9,16 @@ = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default -warning: 1 warning emitted +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-some.rs:15:5 + | +LL | assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 2 warnings emitted
diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.rs b/tests/ui/lint/fn-ptr-comparisons-weird.rs index 171fbfb..4d756cb 100644 --- a/tests/ui/lint/fn-ptr-comparisons-weird.rs +++ b/tests/ui/lint/fn-ptr-comparisons-weird.rs
@@ -1,5 +1,23 @@ //@ check-pass +#[derive(PartialEq, Eq)] +struct A { + f: fn(), + //~^ WARN function pointer comparisons +} + +#[allow(unpredictable_function_pointer_comparisons)] +#[derive(PartialEq, Eq)] +struct AllowedAbove { + f: fn(), +} + +#[derive(PartialEq, Eq)] +#[allow(unpredictable_function_pointer_comparisons)] +struct AllowedBelow { + f: fn(), +} + fn main() { let f: fn() = main; let g: fn() = main; @@ -12,4 +30,8 @@ fn main() { //~^ WARN function pointer comparisons let _ = f < g; //~^ WARN function pointer comparisons + let _ = assert_eq!(g, g); + //~^ WARN function pointer comparisons + let _ = assert_ne!(g, g); + //~^ WARN function pointer comparisons }
diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.stderr b/tests/ui/lint/fn-ptr-comparisons-weird.stderr index f237166..2014e51 100644 --- a/tests/ui/lint/fn-ptr-comparisons-weird.stderr +++ b/tests/ui/lint/fn-ptr-comparisons-weird.stderr
@@ -1,8 +1,11 @@ warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:7:13 + --> $DIR/fn-ptr-comparisons-weird.rs:5:5 | -LL | let _ = f > g; - | ^^^^^ +LL | #[derive(PartialEq, Eq)] + | --------- in this derive macro expansion +LL | struct A { +LL | f: fn(), + | ^^^^^^^ | = note: the address of the same function can vary between different codegen units = note: furthermore, different functions could have the same address after being merged together @@ -10,7 +13,17 @@ = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:9:13 + --> $DIR/fn-ptr-comparisons-weird.rs:25:13 + | +LL | let _ = f > g; + | ^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-weird.rs:27:13 | LL | let _ = f >= g; | ^^^^^^ @@ -20,7 +33,7 @@ = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:11:13 + --> $DIR/fn-ptr-comparisons-weird.rs:29:13 | LL | let _ = f <= g; | ^^^^^^ @@ -30,7 +43,7 @@ = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:13:13 + --> $DIR/fn-ptr-comparisons-weird.rs:31:13 | LL | let _ = f < g; | ^^^^^ @@ -39,5 +52,27 @@ = note: furthermore, different functions could have the same address after being merged together = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> -warning: 4 warnings emitted +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-weird.rs:33:13 + | +LL | let _ = assert_eq!(g, g); + | ^^^^^^^^^^^^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-weird.rs:35:13 + | +LL | let _ = assert_ne!(g, g); + | ^^^^^^^^^^^^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + = note: this warning originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 7 warnings emitted
diff --git a/tests/ui/lint/fn-ptr-comparisons.fixed b/tests/ui/lint/fn-ptr-comparisons.fixed index 22f1617..41cdb7b 100644 --- a/tests/ui/lint/fn-ptr-comparisons.fixed +++ b/tests/ui/lint/fn-ptr-comparisons.fixed
@@ -11,7 +11,6 @@ extern "C" fn args(_a: i32) -> i32 { 0 } -#[derive(PartialEq, Eq)] struct A { f: fn(), } @@ -52,7 +51,6 @@ let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn()); //~^ WARN function pointer comparisons - let _ = a1 == a2; // should not warn let _ = std::ptr::fn_addr_eq(a1.f, a2.f); //~^ WARN function pointer comparisons }
diff --git a/tests/ui/lint/fn-ptr-comparisons.rs b/tests/ui/lint/fn-ptr-comparisons.rs index 90a8ab5..c2601d6 100644 --- a/tests/ui/lint/fn-ptr-comparisons.rs +++ b/tests/ui/lint/fn-ptr-comparisons.rs
@@ -11,7 +11,6 @@ extern "C" fn c() {} extern "C" fn args(_a: i32) -> i32 { 0 } -#[derive(PartialEq, Eq)] struct A { f: fn(), } @@ -52,7 +51,6 @@ fn main() { let _ = t == test; //~^ WARN function pointer comparisons - let _ = a1 == a2; // should not warn let _ = a1.f == a2.f; //~^ WARN function pointer comparisons }
diff --git a/tests/ui/lint/fn-ptr-comparisons.stderr b/tests/ui/lint/fn-ptr-comparisons.stderr index e699332..5913acc 100644 --- a/tests/ui/lint/fn-ptr-comparisons.stderr +++ b/tests/ui/lint/fn-ptr-comparisons.stderr
@@ -1,5 +1,5 @@ warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:26:13 + --> $DIR/fn-ptr-comparisons.rs:25:13 | LL | let _ = f == a; | ^^^^^^ @@ -15,7 +15,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:28:13 + --> $DIR/fn-ptr-comparisons.rs:27:13 | LL | let _ = f != a; | ^^^^^^ @@ -30,7 +30,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:30:13 + --> $DIR/fn-ptr-comparisons.rs:29:13 | LL | let _ = f == g; | ^^^^^^ @@ -45,7 +45,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:32:13 + --> $DIR/fn-ptr-comparisons.rs:31:13 | LL | let _ = f == f; | ^^^^^^ @@ -60,7 +60,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:34:13 + --> $DIR/fn-ptr-comparisons.rs:33:13 | LL | let _ = g == g; | ^^^^^^ @@ -75,7 +75,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:36:13 + --> $DIR/fn-ptr-comparisons.rs:35:13 | LL | let _ = g == g; | ^^^^^^ @@ -90,7 +90,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:38:13 + --> $DIR/fn-ptr-comparisons.rs:37:13 | LL | let _ = &g == &g; | ^^^^^^^^ @@ -105,7 +105,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:40:13 + --> $DIR/fn-ptr-comparisons.rs:39:13 | LL | let _ = a as fn() == g; | ^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:44:13 + --> $DIR/fn-ptr-comparisons.rs:43:13 | LL | let _ = cfn == c; | ^^^^^^^^ @@ -135,7 +135,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:48:13 + --> $DIR/fn-ptr-comparisons.rs:47:13 | LL | let _ = argsfn == args; | ^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:52:13 + --> $DIR/fn-ptr-comparisons.rs:51:13 | LL | let _ = t == test; | ^^^^^^^^^ @@ -165,7 +165,7 @@ | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:56:13 + --> $DIR/fn-ptr-comparisons.rs:54:13 | LL | let _ = a1.f == a2.f; | ^^^^^^^^^^^^
diff --git a/tests/ui/lint/future-incompatible-lint-group.rs b/tests/ui/lint/future-incompatible-lint-group.rs index d1adcf2..22a7ccb 100644 --- a/tests/ui/lint/future-incompatible-lint-group.rs +++ b/tests/ui/lint/future-incompatible-lint-group.rs
@@ -4,14 +4,23 @@ // lints for changes that are not tied to an edition #![deny(future_incompatible)] -// Error since this is a `future_incompatible` lint -macro_rules! m { - ($i) => {}; - //~^ ERROR missing fragment specifier +enum E { V } + +trait Tr1 { + type V; + fn foo() -> Self::V; +} + +impl Tr1 for E { + type V = u8; + + // Error since this is a `future_incompatible` lint + fn foo() -> Self::V { 0 } + //~^ ERROR ambiguous associated item //~| WARN this was previously accepted } -trait Tr { +trait Tr2 { // Warn only since this is not a `future_incompatible` lint fn f(u8) {} //~^ WARN anonymous parameters are deprecated
diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr index 264911b..87b9ebe 100644 --- a/tests/ui/lint/future-incompatible-lint-group.stderr +++ b/tests/ui/lint/future-incompatible-lint-group.stderr
@@ -1,20 +1,5 @@ -error: missing fragment specifier - --> $DIR/future-incompatible-lint-group.rs:9:6 - | -LL | ($i) => {}; - | ^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/future-incompatible-lint-group.rs:5:9 - | -LL | #![deny(future_incompatible)] - | ^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` - warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/future-incompatible-lint-group.rs:16:10 + --> $DIR/future-incompatible-lint-group.rs:25:10 | LL | fn f(u8) {} | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` @@ -23,21 +8,30 @@ = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686> = note: `#[warn(anonymous_parameters)]` on by default -error: aborting due to 1 previous error; 1 warning emitted - -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/future-incompatible-lint-group.rs:9:6 +error: ambiguous associated item + --> $DIR/future-incompatible-lint-group.rs:18:17 | -LL | ($i) => {}; - | ^^ +LL | fn foo() -> Self::V { 0 } + | ^^^^^^^ help: use fully-qualified syntax: `<E as Tr1>::V` | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + = note: for more information, see issue #57644 <https://github.com/rust-lang/rust/issues/57644> +note: `V` could refer to the variant defined here + --> $DIR/future-incompatible-lint-group.rs:7:10 + | +LL | enum E { V } + | ^ +note: `V` could also refer to the associated type defined here + --> $DIR/future-incompatible-lint-group.rs:10:5 + | +LL | type V; + | ^^^^^^ note: the lint level is defined here --> $DIR/future-incompatible-lint-group.rs:5:9 | LL | #![deny(future_incompatible)] | ^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` + = note: `#[deny(ambiguous_associated_items)]` implied by `#[deny(future_incompatible)]` + +error: aborting due to 1 previous error; 1 warning emitted
diff --git a/tests/ui/lint/wasm_c_abi_transition.rs b/tests/ui/lint/wasm_c_abi_transition.rs deleted file mode 100644 index 411772a..0000000 --- a/tests/ui/lint/wasm_c_abi_transition.rs +++ /dev/null
@@ -1,57 +0,0 @@ -//@ compile-flags: --target wasm32-unknown-unknown -//@ needs-llvm-components: webassembly -//@ add-core-stubs -//@ build-fail - -#![feature(no_core, repr_simd)] -#![no_core] -#![crate_type = "lib"] -#![deny(wasm_c_abi)] - -extern crate minicore; -use minicore::*; - -pub extern "C" fn my_fun_trivial(_x: i32, _y: f32) {} - -#[repr(C)] -pub struct MyType(i32, i32); -pub extern "C" fn my_fun(_x: MyType) {} //~ERROR: wasm ABI transition -//~^WARN: previously accepted - -// This one is ABI-safe as it only wraps a single field, -// and the return type can be anything. -#[repr(C)] -pub struct MySafeType(i32); -pub extern "C" fn my_fun_safe(_x: MySafeType) -> MyType { loop {} } - -// This one not ABI-safe due to the alignment. -#[repr(C, align(16))] -pub struct MyAlignedType(i32); -pub extern "C" fn my_fun_aligned(_x: MyAlignedType) {} //~ERROR: wasm ABI transition -//~^WARN: previously accepted - -// Check call-site warning -extern "C" { - fn other_fun(x: MyType); -} - -pub fn call_other_fun(x: MyType) { - unsafe { other_fun(x) } //~ERROR: wasm ABI transition - //~^WARN: previously accepted -} - -// Zero-sized types are safe in both ABIs -#[repr(C)] -pub struct MyZstType; -#[allow(improper_ctypes_definitions)] -pub extern "C" fn zst_safe(_x: (), _y: MyZstType) {} - -// The old and new wasm ABI treats simd types like `v128` the same way, so no -// wasm_c_abi warning should be emitted. -#[repr(simd)] -#[allow(non_camel_case_types)] -pub struct v128([i32; 4]); -#[target_feature(enable = "simd128")] -pub extern "C" fn my_safe_simd(x: v128) -> v128 { x } -//~^ WARN `extern` fn uses type `v128`, which is not FFI-safe -//~| WARN `extern` fn uses type `v128`, which is not FFI-safe
diff --git a/tests/ui/lint/wasm_c_abi_transition.stderr b/tests/ui/lint/wasm_c_abi_transition.stderr deleted file mode 100644 index b4526bf..0000000 --- a/tests/ui/lint/wasm_c_abi_transition.stderr +++ /dev/null
@@ -1,114 +0,0 @@ -warning: `extern` fn uses type `v128`, which is not FFI-safe - --> $DIR/wasm_c_abi_transition.rs:55:35 - | -LL | pub extern "C" fn my_safe_simd(x: v128) -> v128 { x } - | ^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct - = note: this struct has unspecified layout -note: the type is defined here - --> $DIR/wasm_c_abi_transition.rs:53:1 - | -LL | pub struct v128([i32; 4]); - | ^^^^^^^^^^^^^^^ - = note: `#[warn(improper_ctypes_definitions)]` on by default - -warning: `extern` fn uses type `v128`, which is not FFI-safe - --> $DIR/wasm_c_abi_transition.rs:55:44 - | -LL | pub extern "C" fn my_safe_simd(x: v128) -> v128 { x } - | ^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct - = note: this struct has unspecified layout -note: the type is defined here - --> $DIR/wasm_c_abi_transition.rs:53:1 - | -LL | pub struct v128([i32; 4]); - | ^^^^^^^^^^^^^^^ - -error: this function definition involves an argument of type `MyType` which is affected by the wasm ABI transition - --> $DIR/wasm_c_abi_transition.rs:18:1 - | -LL | pub extern "C" fn my_fun(_x: MyType) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762> - = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target -note: the lint level is defined here - --> $DIR/wasm_c_abi_transition.rs:9:9 - | -LL | #![deny(wasm_c_abi)] - | ^^^^^^^^^^ - -error: this function definition involves an argument of type `MyAlignedType` which is affected by the wasm ABI transition - --> $DIR/wasm_c_abi_transition.rs:30:1 - | -LL | pub extern "C" fn my_fun_aligned(_x: MyAlignedType) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762> - = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target - -error: this function call involves an argument of type `MyType` which is affected by the wasm ABI transition - --> $DIR/wasm_c_abi_transition.rs:39:14 - | -LL | unsafe { other_fun(x) } - | ^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762> - = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target - -error: aborting due to 3 previous errors; 2 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -error: this function definition involves an argument of type `MyType` which is affected by the wasm ABI transition - --> $DIR/wasm_c_abi_transition.rs:18:1 - | -LL | pub extern "C" fn my_fun(_x: MyType) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762> - = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target -note: the lint level is defined here - --> $DIR/wasm_c_abi_transition.rs:9:9 - | -LL | #![deny(wasm_c_abi)] - | ^^^^^^^^^^ - -Future breakage diagnostic: -error: this function definition involves an argument of type `MyAlignedType` which is affected by the wasm ABI transition - --> $DIR/wasm_c_abi_transition.rs:30:1 - | -LL | pub extern "C" fn my_fun_aligned(_x: MyAlignedType) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762> - = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target -note: the lint level is defined here - --> $DIR/wasm_c_abi_transition.rs:9:9 - | -LL | #![deny(wasm_c_abi)] - | ^^^^^^^^^^ - -Future breakage diagnostic: -error: this function call involves an argument of type `MyType` which is affected by the wasm ABI transition - --> $DIR/wasm_c_abi_transition.rs:39:14 - | -LL | unsafe { other_fun(x) } - | ^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762> - = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target -note: the lint level is defined here - --> $DIR/wasm_c_abi_transition.rs:9:9 - | -LL | #![deny(wasm_c_abi)] - | ^^^^^^^^^^ -
diff --git a/tests/ui/macros/auxiliary/serde.rs b/tests/ui/macros/auxiliary/serde.rs new file mode 100644 index 0000000..355b650 --- /dev/null +++ b/tests/ui/macros/auxiliary/serde.rs
@@ -0,0 +1,19 @@ +//@ force-host +//@ no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_derive(Serialize, attributes(serde))] +pub fn serialize(ts: TokenStream) -> TokenStream { + quote!{} +} + +#[proc_macro_derive(Deserialize, attributes(serde))] +pub fn deserialize(ts: TokenStream) -> TokenStream { + quote!{} +}
diff --git a/tests/ui/macros/format-args-temporaries-in-write.stderr b/tests/ui/macros/format-args-temporaries-in-write.stderr index e05246c..e58a433 100644 --- a/tests/ui/macros/format-args-temporaries-in-write.stderr +++ b/tests/ui/macros/format-args-temporaries-in-write.stderr
@@ -14,6 +14,10 @@ | | | `mutex` dropped here while still borrowed | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | write!(Out, "{}", mutex.lock()); /* no semicolon */ + | + error[E0597]: `mutex` does not live long enough --> $DIR/format-args-temporaries-in-write.rs:47:29 @@ -31,6 +35,10 @@ | | | `mutex` dropped here while still borrowed | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | writeln!(Out, "{}", mutex.lock()); /* no semicolon */ + | + error: aborting due to 2 previous errors
diff --git a/tests/ui/macros/issue-39404.rs b/tests/ui/macros/issue-39404.rs index 2229f2c..ceeb623 100644 --- a/tests/ui/macros/issue-39404.rs +++ b/tests/ui/macros/issue-39404.rs
@@ -1,7 +1,7 @@ #![allow(unused)] -macro_rules! m { ($i) => {} } -//~^ ERROR missing fragment specifier -//~| WARN previously accepted +macro_rules! m { + ($i) => {}; //~ ERROR missing fragment specifier +} fn main() {}
diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr index 176c8e9..62d0bc1 100644 --- a/tests/ui/macros/issue-39404.stderr +++ b/tests/ui/macros/issue-39404.stderr
@@ -1,23 +1,15 @@ error: missing fragment specifier - --> $DIR/issue-39404.rs:3:19 + --> $DIR/issue-39404.rs:4:6 | -LL | macro_rules! m { ($i) => {} } - | ^^ +LL | ($i) => {}; + | ^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | ($i:spec) => {}; + | +++++ error: aborting due to 1 previous error -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/issue-39404.rs:3:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default -
diff --git a/tests/ui/macros/macro-match-nonterminal.rs b/tests/ui/macros/macro-match-nonterminal.rs index 5d9eb55..fa2af94 100644 --- a/tests/ui/macros/macro-match-nonterminal.rs +++ b/tests/ui/macros/macro-match-nonterminal.rs
@@ -3,8 +3,6 @@ //~^ ERROR missing fragment //~| ERROR missing fragment //~| ERROR missing fragment - //~| WARN this was previously accepted - //~| WARN this was previously accepted () }; }
diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr index f221f92..8196d79 100644 --- a/tests/ui/macros/macro-match-nonterminal.stderr +++ b/tests/ui/macros/macro-match-nonterminal.stderr
@@ -3,16 +3,13 @@ | LL | ($a, $b) => { | ^^ - -error: missing fragment specifier - --> $DIR/macro-match-nonterminal.rs:2:6 | -LL | ($a, $b) => { - | ^^ + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default +LL | ($a:spec, $b) => { + | +++++ error: missing fragment specifier --> $DIR/macro-match-nonterminal.rs:2:10 @@ -20,30 +17,18 @@ LL | ($a, $b) => { | ^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | ($a, $b:spec) => { + | +++++ + +error: missing fragment specifier + --> $DIR/macro-match-nonterminal.rs:2:6 + | +LL | ($a, $b) => { + | ^^ error: aborting due to 3 previous errors -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/macro-match-nonterminal.rs:2:6 - | -LL | ($a, $b) => { - | ^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default - -Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/macro-match-nonterminal.rs:2:10 - | -LL | ($a, $b) => { - | ^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default -
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.rs b/tests/ui/macros/macro-missing-fragment-deduplication.rs index b77c51e..481f08f 100644 --- a/tests/ui/macros/macro-missing-fragment-deduplication.rs +++ b/tests/ui/macros/macro-missing-fragment-deduplication.rs
@@ -1,10 +1,8 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes macro_rules! m { - ($name) => {} - //~^ ERROR missing fragment - //~| ERROR missing fragment - //~| WARN this was previously accepted + ($name) => {}; //~ ERROR missing fragment + //~| ERROR missing fragment } fn main() {
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr index c46712f..820f7eb 100644 --- a/tests/ui/macros/macro-missing-fragment-deduplication.stderr +++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
@@ -1,29 +1,21 @@ error: missing fragment specifier --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} +LL | ($name) => {}; | ^^^^^ + | + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | ($name:spec) => {}; + | +++++ error: missing fragment specifier --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} +LL | ($name) => {}; | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default error: aborting due to 2 previous errors -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/macro-missing-fragment-deduplication.rs:4:6 - | -LL | ($name) => {} - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default -
diff --git a/tests/ui/macros/macro-missing-fragment.e2015.stderr b/tests/ui/macros/macro-missing-fragment.e2015.stderr deleted file mode 100644 index 3d32f20..0000000 --- a/tests/ui/macros/macro-missing-fragment.e2015.stderr +++ /dev/null
@@ -1,85 +0,0 @@ -error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - -error: aborting due to 1 previous error; 3 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -
diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs index 42387e8..533aa14 100644 --- a/tests/ui/macros/macro-missing-fragment.rs +++ b/tests/ui/macros/macro-missing-fragment.rs
@@ -1,31 +1,17 @@ -//@ revisions: e2015 e2024 -//@[e2015] edition:2015 -//@[e2024] edition:2024 - -#![warn(missing_fragment_specifier)] +//! Ensure that macros produce an error if fragment specifiers are missing. macro_rules! used_arm { - ( $( any_token $field_rust_type )* ) => {}; - //[e2015]~^ ERROR missing fragment - //[e2015]~| WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^^ ERROR missing fragment - //[e2024]~| ERROR missing fragment + ( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment + //~| ERROR missing fragment } macro_rules! used_macro_unused_arm { () => {}; - ( $name ) => {}; - //[e2015]~^ WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^ ERROR missing fragment + ( $name ) => {}; //~ ERROR missing fragment } macro_rules! unused_macro { - ( $name ) => {}; - //[e2015]~^ WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^ ERROR missing fragment + ( $name ) => {}; //~ ERROR missing fragment } fn main() {
diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.stderr similarity index 79% rename from tests/ui/macros/macro-missing-fragment.e2024.stderr rename to tests/ui/macros/macro-missing-fragment.stderr index a9195063..4a99d7d 100644 --- a/tests/ui/macros/macro-missing-fragment.e2024.stderr +++ b/tests/ui/macros/macro-missing-fragment.stderr
@@ -1,10 +1,10 @@ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 + --> $DIR/macro-missing-fragment.rs:4:20 | LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -12,12 +12,12 @@ | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 + --> $DIR/macro-missing-fragment.rs:10:7 | LL | ( $name ) => {}; | ^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -25,12 +25,12 @@ | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 + --> $DIR/macro-missing-fragment.rs:14:7 | LL | ( $name ) => {}; | ^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -38,7 +38,7 @@ | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 + --> $DIR/macro-missing-fragment.rs:4:20 | LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/macros/missing-derive-1.rs b/tests/ui/macros/missing-derive-1.rs new file mode 100644 index 0000000..e23ef7b --- /dev/null +++ b/tests/ui/macros/missing-derive-1.rs
@@ -0,0 +1,33 @@ +//@aux-build:serde.rs + +// derive macros imported and used + +extern crate serde; +use serde::{Serialize, Deserialize}; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + B, +} + +enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute +} + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +enum D { + A, + B, +} + +fn main() {}
diff --git a/tests/ui/macros/missing-derive-1.stderr b/tests/ui/macros/missing-derive-1.stderr new file mode 100644 index 0000000..1558410 --- /dev/null +++ b/tests/ui/macros/missing-derive-1.stderr
@@ -0,0 +1,47 @@ +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-1.rs:8:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-1.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum A { + | + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-1.rs:16:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-1.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum B { + | + +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-1.rs:22:7 + | +LL | #[sede(untagged)] + | ^^^^ + | +help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute + | +LL | #[serde(untagged)] + | + + +error: aborting due to 3 previous errors +
diff --git a/tests/ui/macros/missing-derive-2.rs b/tests/ui/macros/missing-derive-2.rs new file mode 100644 index 0000000..027d465 --- /dev/null +++ b/tests/ui/macros/missing-derive-2.rs
@@ -0,0 +1,26 @@ +//@aux-build:serde.rs + +// derive macros imported but unused + +extern crate serde; +use serde::{Serialize, Deserialize}; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + B, +} + +enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute +} + +fn main() {}
diff --git a/tests/ui/macros/missing-derive-2.stderr b/tests/ui/macros/missing-derive-2.stderr new file mode 100644 index 0000000..6c8e9e1 --- /dev/null +++ b/tests/ui/macros/missing-derive-2.stderr
@@ -0,0 +1,47 @@ +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-2.rs:22:7 + | +LL | #[sede(untagged)] + | ^^^^ + | +help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute + | +LL | #[serde(untagged)] + | + + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-2.rs:16:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-2.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum B { + | + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-2.rs:8:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-2.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum A { + | + +error: aborting due to 3 previous errors +
diff --git a/tests/ui/macros/missing-derive-3.rs b/tests/ui/macros/missing-derive-3.rs new file mode 100644 index 0000000..8add819 --- /dev/null +++ b/tests/ui/macros/missing-derive-3.rs
@@ -0,0 +1,24 @@ +//@aux-build:serde.rs + +// derive macros not imported, but namespace imported. Not yet handled. +extern crate serde; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { + A, + B, +} + +enum B { + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, +} + +fn main() {}
diff --git a/tests/ui/macros/missing-derive-3.stderr b/tests/ui/macros/missing-derive-3.stderr new file mode 100644 index 0000000..0a7ed8d --- /dev/null +++ b/tests/ui/macros/missing-derive-3.stderr
@@ -0,0 +1,32 @@ +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-3.rs:20:7 + | +LL | #[sede(untagged)] + | ^^^^ + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-3.rs:14:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-3.rs:4:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-3.rs:6:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-3.rs:4:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors +
diff --git a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs index 5ef1d0c..6ceec11 100644 --- a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs +++ b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs
@@ -1,8 +1,7 @@ //@ dont-require-annotations: NOTE #![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize)] -#![feature(unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete +#![feature(unsized_fn_params)] // This tests a few edge-cases around `arbitrary_self_types`. Most specifically, // it checks that the `ObjectCandidate` you get from method matching can't
diff --git a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 213139a..32cff62 100644 --- a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
@@ -1,14 +1,5 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:4:12 - | -LL | #![feature(unsized_locals, unsized_fn_params)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:89:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:88:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` @@ -16,7 +7,7 @@ | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:106:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:105:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u64` @@ -24,23 +15,23 @@ | expected due to this error[E0034]: multiple applicable items in scope - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:124:15 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:123:15 | LL | let z = x.foo(); | ^^^ multiple `foo` found | note: candidate #1 is defined in the trait `FinalFoo` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:61:5 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:60:5 | LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:74:9 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:73:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ note: candidate #3 is defined in an impl of the trait `X` for the type `T` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:47:9 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:46:9 | LL | fn foo(self: Smaht<Self, u64>) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +52,7 @@ | error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:141:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:140:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u8` @@ -69,7 +60,7 @@ | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:159:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:158:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` @@ -77,14 +68,14 @@ | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:176:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:175:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` | | | expected due to this -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors Some errors have detailed explanations: E0034, E0308. For more information about an error, try `rustc --explain E0034`.
diff --git a/tests/ui/methods/missing-bound-on-tuple.rs b/tests/ui/methods/missing-bound-on-tuple.rs new file mode 100644 index 0000000..25deabf --- /dev/null +++ b/tests/ui/methods/missing-bound-on-tuple.rs
@@ -0,0 +1,39 @@ +trait WorksOnDefault { + fn do_something() {} +} + +impl<T: Default> WorksOnDefault for T {} +//~^ NOTE the following trait bounds were not satisfied +//~| NOTE unsatisfied trait bound introduced here + +trait Foo {} + +trait WorksOnFoo { + fn do_be_do() {} +} + +impl<T: Foo> WorksOnFoo for T {} +//~^ NOTE the following trait bounds were not satisfied +//~| NOTE unsatisfied trait bound introduced here + +impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {} +//~^ NOTE `Foo` is implemented for `(i32, u32, String)` +impl Foo for i32 {} +impl Foo for &i32 {} +impl Foo for u32 {} +impl Foo for String {} + +fn main() { + let _success = <(i32, u32, String)>::do_something(); + let _failure = <(i32, &u32, String)>::do_something(); //~ ERROR E0599 + //~^ NOTE `Default` is implemented for `(i32, u32, String)` + //~| NOTE function or associated item cannot be called on + let _success = <(i32, u32, String)>::do_be_do(); + let _failure = <(i32, &u32, String)>::do_be_do(); //~ ERROR E0599 + //~^ NOTE function or associated item cannot be called on + let _success = <(i32, u32, String)>::default(); + let _failure = <(i32, &u32, String)>::default(); //~ ERROR E0599 + //~^ NOTE `Default` is implemented for `(i32, u32, String)` + //~| NOTE function or associated item cannot be called on + //~| NOTE the following trait bounds were not satisfied +}
diff --git a/tests/ui/methods/missing-bound-on-tuple.stderr b/tests/ui/methods/missing-bound-on-tuple.stderr new file mode 100644 index 0000000..f3e0897 --- /dev/null +++ b/tests/ui/methods/missing-bound-on-tuple.stderr
@@ -0,0 +1,58 @@ +error[E0599]: the function or associated item `do_something` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied + --> $DIR/missing-bound-on-tuple.rs:28:43 + | +LL | let _failure = <(i32, &u32, String)>::do_something(); + | ^^^^^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&(i32, &u32, String): Default` + `&mut (i32, &u32, String): Default` + `(i32, &u32, String): Default` + --> $DIR/missing-bound-on-tuple.rs:5:9 + | +LL | impl<T: Default> WorksOnDefault for T {} + | ^^^^^^^ -------------- - + | | + | unsatisfied trait bound introduced here +note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` + --> $SRC_DIR/core/src/tuple.rs:LL:COL + = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the function or associated item `do_be_do` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied + --> $DIR/missing-bound-on-tuple.rs:32:43 + | +LL | let _failure = <(i32, &u32, String)>::do_be_do(); + | ^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&(i32, &u32, String): Foo` + `&mut (i32, &u32, String): Foo` + `(i32, &u32, String): Foo` + --> $DIR/missing-bound-on-tuple.rs:15:9 + | +LL | impl<T: Foo> WorksOnFoo for T {} + | ^^^ ---------- - + | | + | unsatisfied trait bound introduced here +note: `Foo` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` + --> $DIR/missing-bound-on-tuple.rs:19:1 + | +LL | impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: the function or associated item `default` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied + --> $DIR/missing-bound-on-tuple.rs:35:43 + | +LL | let _failure = <(i32, &u32, String)>::default(); + | ^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `&u32: Default` + which is required by `(i32, &u32, String): Default` +note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` + --> $SRC_DIR/core/src/tuple.rs:LL:COL + = note: this error originates in the macro `tuple_impls` (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 E0599`.
diff --git a/tests/ui/mir/mir_refs_correct.rs b/tests/ui/mir/mir_refs_correct.rs index fc23c8c..f1832d9 100644 --- a/tests/ui/mir/mir_refs_correct.rs +++ b/tests/ui/mir/mir_refs_correct.rs
@@ -1,6 +1,8 @@ //@ run-pass //@ aux-build:mir_external_refs.rs +#![allow(unpredictable_function_pointer_comparisons)] + extern crate mir_external_refs as ext; struct S(#[allow(dead_code)] u8);
diff --git a/tests/ui/moves/move-out-of-slice-2.rs b/tests/ui/moves/move-out-of-slice-2.rs index 2f7394f..6428dc4 100644 --- a/tests/ui/moves/move-out-of-slice-2.rs +++ b/tests/ui/moves/move-out-of-slice-2.rs
@@ -1,5 +1,3 @@ -#![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete #![allow(unused)] struct A; @@ -9,28 +7,24 @@ fn main() { let a: Box<[A]> = Box::new([A]); match *a { - //~^ ERROR cannot move out of type `[A]`, a non-copy slice - [a @ ..] => {} + [a @ ..] => {} //~ERROR the size for values of type `[A]` cannot be known at compilation time [E0277] _ => {} } let b: Box<[A]> = Box::new([A, A, A]); match *b { - //~^ ERROR cannot move out of type `[A]`, a non-copy slice - [_, _, b @ .., _] => {} + [_, _, b @ .., _] => {} //~ERROR the size for values of type `[A]` cannot be known at compilation time [E0277] _ => {} } // `[C]` isn't `Copy`, even if `C` is. let c: Box<[C]> = Box::new([C]); match *c { - //~^ ERROR cannot move out of type `[C]`, a non-copy slice - [c @ ..] => {} + [c @ ..] => {} //~ERROR the size for values of type `[C]` cannot be known at compilation time [E0277] _ => {} } let d: Box<[C]> = Box::new([C, C, C]); match *d { - //~^ ERROR cannot move out of type `[C]`, a non-copy slice - [_, _, d @ .., _] => {} + [_, _, d @ .., _] => {} //~ERROR the size for values of type `[C]` cannot be known at compilation time [E0277] _ => {} } }
diff --git a/tests/ui/moves/move-out-of-slice-2.stderr b/tests/ui/moves/move-out-of-slice-2.stderr index b46854c..2071946 100644 --- a/tests/ui/moves/move-out-of-slice-2.stderr +++ b/tests/ui/moves/move-out-of-slice-2.stderr
@@ -1,80 +1,39 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/move-out-of-slice-2.rs:1:12 +error[E0277]: the size for values of type `[A]` cannot be known at compilation time + --> $DIR/move-out-of-slice-2.rs:10:10 | -LL | #![feature(unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0508]: cannot move out of type `[A]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:11:11 - | -LL | match *a { - | ^^ cannot move out of here -LL | LL | [a @ ..] => {} - | - - | | - | data moved here - | move occurs because `a` has type `[A]`, which does not implement the `Copy` trait + | ^^^^^^ doesn't have a size known at compile-time | -help: consider borrowing the pattern binding - | -LL | [ref a @ ..] => {} - | +++ + = help: the trait `Sized` is not implemented for `[A]` + = note: all local variables must have a statically known size -error[E0508]: cannot move out of type `[A]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:17:11 +error[E0277]: the size for values of type `[A]` cannot be known at compilation time + --> $DIR/move-out-of-slice-2.rs:15:16 | -LL | match *b { - | ^^ cannot move out of here -LL | LL | [_, _, b @ .., _] => {} - | - - | | - | data moved here - | move occurs because `b` has type `[A]`, which does not implement the `Copy` trait + | ^^^^^^ doesn't have a size known at compile-time | -help: consider borrowing the pattern binding - | -LL | [_, _, ref b @ .., _] => {} - | +++ + = help: the trait `Sized` is not implemented for `[A]` + = note: all local variables must have a statically known size -error[E0508]: cannot move out of type `[C]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:25:11 +error[E0277]: the size for values of type `[C]` cannot be known at compilation time + --> $DIR/move-out-of-slice-2.rs:22:10 | -LL | match *c { - | ^^ cannot move out of here -LL | LL | [c @ ..] => {} - | - - | | - | data moved here - | move occurs because `c` has type `[C]`, which does not implement the `Copy` trait + | ^^^^^^ doesn't have a size known at compile-time | -help: consider borrowing the pattern binding - | -LL | [ref c @ ..] => {} - | +++ + = help: the trait `Sized` is not implemented for `[C]` + = note: all local variables must have a statically known size -error[E0508]: cannot move out of type `[C]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:31:11 +error[E0277]: the size for values of type `[C]` cannot be known at compilation time + --> $DIR/move-out-of-slice-2.rs:27:16 | -LL | match *d { - | ^^ cannot move out of here -LL | LL | [_, _, d @ .., _] => {} - | - - | | - | data moved here - | move occurs because `d` has type `[C]`, which does not implement the `Copy` trait + | ^^^^^^ doesn't have a size known at compile-time | -help: consider borrowing the pattern binding - | -LL | [_, _, ref d @ .., _] => {} - | +++ + = help: the trait `Sized` is not implemented for `[C]` + = note: all local variables must have a statically known size -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0508`. +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr index 2abff61..6de323a 100644 --- a/tests/ui/never_type/defaulted-never-note.nofallback.stderr +++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr
@@ -20,3 +20,24 @@ warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/defaulted-never-note.rs:28:1 + | +LL | fn smeg() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail + --> $DIR/defaulted-never-note.rs:32:9 + | +LL | foo(_x); + | ^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let _x: () = return; + | ++++ +
diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr index bf37cc7..be80756 100644 --- a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
@@ -40,3 +40,46 @@ warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/dependency-on-fallback-to-unit.rs:8:1 + | +LL | fn def() { + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/dependency-on-fallback-to-unit.rs:12:19 + | +LL | false => <_>::default(), + | ^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL - false => <_>::default(), +LL + false => <()>::default(), + | + +Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/dependency-on-fallback-to-unit.rs:19:1 + | +LL | fn question_mark() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/dependency-on-fallback-to-unit.rs:22:5 + | +LL | deserialize()?; + | ^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | deserialize::<()>()?; + | ++++++ +
diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr index 4b8a5d5..44ebdb4 100644 --- a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
@@ -39,3 +39,45 @@ warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-control-flow.rs:30:1 + | +LL | fn assignment() { + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitDefault` will fail + --> $DIR/diverging-fallback-control-flow.rs:36:13 + | +LL | x = UnitDefault::default(); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let x: (); + | ++++ + +Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-control-flow.rs:42:1 + | +LL | fn assignment_rev() { + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitDefault` will fail + --> $DIR/diverging-fallback-control-flow.rs:50:13 + | +LL | x = UnitDefault::default(); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let x: (); + | ++++ +
diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr index 94af02a..4a8dea4 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
@@ -20,3 +20,24 @@ warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-no-leak.rs:14:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Test` will fail + --> $DIR/diverging-fallback-no-leak.rs:20:23 + | +LL | unconstrained_arg(return); + | ^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | unconstrained_arg::<()>(return); + | ++++++ +
diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr index 22349d3..803af39 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
@@ -20,3 +20,24 @@ warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-unconstrained-return.rs:28:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitReturn` will fail + --> $DIR/diverging-fallback-unconstrained-return.rs:39:23 + | +LL | let _ = if true { unconstrained_return() } else { panic!() }; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let _: () = if true { unconstrained_return() } else { panic!() }; + | ++++ +
diff --git a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr index 3fe642a..365e886 100644 --- a/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr +++ b/tests/ui/never_type/dont-suggest-turbofish-from-expansion.stderr
@@ -24,3 +24,28 @@ error: aborting due to 1 previous error +Future incompatibility report: Future breakage diagnostic: +error: this function depends on never type fallback being `()` + --> $DIR/dont-suggest-turbofish-from-expansion.rs:10:1 + | +LL | fn main() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/dont-suggest-turbofish-from-expansion.rs:14:23 + | +LL | let created = create_ok_default()?; + | ^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/dont-suggest-turbofish-from-expansion.rs:1:9 + | +LL | #![deny(dependency_on_unit_never_type_fallback)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use `()` annotations to avoid fallback changes + | +LL | let created: () = create_ok_default()?; + | ++++ +
diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr index d7463be..cf19363 100644 --- a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr +++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
@@ -20,3 +20,24 @@ warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/fallback-closure-ret.rs:21:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Bar` will fail + --> $DIR/fallback-closure-ret.rs:24:5 + | +LL | foo(|| panic!()); + | ^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | foo::<()>(|| panic!()); + | ++++++ +
diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr index 72788a6..7250db1 100644 --- a/tests/ui/never_type/impl_trait_fallback.stderr +++ b/tests/ui/never_type/impl_trait_fallback.stderr
@@ -16,3 +16,20 @@ warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: this function depends on never type fallback being `()` + --> $DIR/impl_trait_fallback.rs:8:1 + | +LL | fn should_ret_unit() -> impl T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: T` will fail + --> $DIR/impl_trait_fallback.rs:8:25 + | +LL | fn should_ret_unit() -> impl T { + | ^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default +
diff --git a/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr b/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr index 86786c3..945db40 100644 --- a/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr +++ b/tests/ui/never_type/lint-breaking-2024-assign-underscore.stderr
@@ -24,3 +24,28 @@ error: aborting due to 1 previous error +Future incompatibility report: Future breakage diagnostic: +error: this function depends on never type fallback being `()` + --> $DIR/lint-breaking-2024-assign-underscore.rs:10:1 + | +LL | fn test() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/lint-breaking-2024-assign-underscore.rs:13:9 + | +LL | _ = foo()?; + | ^^^^^ +note: the lint level is defined here + --> $DIR/lint-breaking-2024-assign-underscore.rs:4:9 + | +LL | #![deny(dependency_on_unit_never_type_fallback)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use `()` annotations to avoid fallback changes + | +LL | _ = foo::<()>()?; + | ++++++ +
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr index 49b966f..c90efd2 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
@@ -133,3 +133,155 @@ warning: 10 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:12:18 + | +LL | unsafe { mem::zeroed() } + | ^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | unsafe { mem::zeroed::<()>() } + | ++++++ + +Future breakage diagnostic: +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:29:13 + | +LL | core::mem::transmute(Zst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | core::mem::transmute::<_, ()>(Zst) + | +++++++++ + +Future breakage diagnostic: +warning: never type fallback affects this union access + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:46:18 + | +LL | unsafe { Union { a: () }.b } + | ^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default + +Future breakage diagnostic: +warning: never type fallback affects this raw pointer dereference + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:57:18 + | +LL | unsafe { *ptr::from_ref(&()).cast() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | unsafe { *ptr::from_ref(&()).cast::<()>() } + | ++++++ + +Future breakage diagnostic: +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:78:18 + | +LL | unsafe { internally_create(x) } + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | unsafe { internally_create::<()>(x) } + | ++++++ + +Future breakage diagnostic: +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:96:18 + | +LL | unsafe { zeroed() } + | ^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let zeroed = mem::zeroed::<()>; + | ++++++ + +Future breakage diagnostic: +warning: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:91:22 + | +LL | let zeroed = mem::zeroed; + | ^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let zeroed = mem::zeroed::<()>; + | ++++++ + +Future breakage diagnostic: +warning: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:114:17 + | +LL | let f = internally_create; + | ^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let f = internally_create::<()>; + | ++++++ + +Future breakage diagnostic: +warning: never type fallback affects this call to an `unsafe` method + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:139:13 + | +LL | S(marker::PhantomData).create_out_of_thin_air() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default + +Future breakage diagnostic: +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:157:19 + | +LL | match send_message::<_ /* ?0 */>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | msg_send!(); + | ----------- in this macro invocation + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default + = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) +
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr index 4d3692a..858d738 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
@@ -142,3 +142,155 @@ error: aborting due to 10 previous errors; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:12:18 + | +LL | unsafe { mem::zeroed() } + | ^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | unsafe { mem::zeroed::<()>() } + | ++++++ + +Future breakage diagnostic: +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:29:13 + | +LL | core::mem::transmute(Zst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | core::mem::transmute::<_, ()>(Zst) + | +++++++++ + +Future breakage diagnostic: +error: never type fallback affects this union access + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:46:18 + | +LL | unsafe { Union { a: () }.b } + | ^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default + +Future breakage diagnostic: +error: never type fallback affects this raw pointer dereference + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:57:18 + | +LL | unsafe { *ptr::from_ref(&()).cast() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | unsafe { *ptr::from_ref(&()).cast::<()>() } + | ++++++ + +Future breakage diagnostic: +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:78:18 + | +LL | unsafe { internally_create(x) } + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | unsafe { internally_create::<()>(x) } + | ++++++ + +Future breakage diagnostic: +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:96:18 + | +LL | unsafe { zeroed() } + | ^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let zeroed = mem::zeroed::<()>; + | ++++++ + +Future breakage diagnostic: +error: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:91:22 + | +LL | let zeroed = mem::zeroed; + | ^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let zeroed = mem::zeroed::<()>; + | ++++++ + +Future breakage diagnostic: +error: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:114:17 + | +LL | let f = internally_create; + | ^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default +help: use `()` annotations to avoid fallback changes + | +LL | let f = internally_create::<()>; + | ++++++ + +Future breakage diagnostic: +error: never type fallback affects this call to an `unsafe` method + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:139:13 + | +LL | S(marker::PhantomData).create_out_of_thin_air() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default + +Future breakage diagnostic: +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:157:19 + | +LL | match send_message::<_ /* ?0 */>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | msg_send!(); + | ----------- in this macro invocation + | + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default + = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) +
diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed b/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed new file mode 100644 index 0000000..ee9d9a3 --- /dev/null +++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed
@@ -0,0 +1,23 @@ +//@ run-rustfix +#![allow(unused_assignments)] + +use std::pin::Pin; +fn main() { + let mut s = String::from("hello"); + let mut ref_s = &mut s; + + let mut binding = String::from("world"); + ref_s = &mut binding; //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); + + let mut val: u8 = 5; + let mut s = Pin::new(&mut val); + let mut ref_s = &mut s; + + let mut val2: u8 = 10; + let mut binding = Pin::new(&mut val2); + ref_s = &mut binding; //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); +}
diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs b/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs new file mode 100644 index 0000000..8f7ea756 --- /dev/null +++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs
@@ -0,0 +1,21 @@ +//@ run-rustfix +#![allow(unused_assignments)] + +use std::pin::Pin; +fn main() { + let mut s = String::from("hello"); + let mut ref_s = &mut s; + + ref_s = &mut String::from("world"); //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); + + let mut val: u8 = 5; + let mut s = Pin::new(&mut val); + let mut ref_s = &mut s; + + let mut val2: u8 = 10; + ref_s = &mut Pin::new(&mut val2); //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); +}
diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr b/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr new file mode 100644 index 0000000..8432725 --- /dev/null +++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr
@@ -0,0 +1,37 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/sugg-mut-for-binding-issue-137486.rs:9:18 + | +LL | ref_s = &mut String::from("world"); + | ^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | print!("r1 = {}", ref_s); + | ----- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let mut binding = String::from("world"); +LL ~ ref_s = &mut binding; + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/sugg-mut-for-binding-issue-137486.rs:18:18 + | +LL | ref_s = &mut Pin::new(&mut val2); + | ^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | print!("r1 = {}", ref_s); + | ----- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let mut binding = Pin::new(&mut val2); +LL ~ ref_s = &mut binding; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/nullable-pointer-iotareduction.rs b/tests/ui/nullable-pointer-iotareduction.rs index fa837da..1b73164 100644 --- a/tests/ui/nullable-pointer-iotareduction.rs +++ b/tests/ui/nullable-pointer-iotareduction.rs
@@ -8,6 +8,8 @@ // trying to get assert failure messages that at least identify which case // failed. +#![allow(unpredictable_function_pointer_comparisons)] + enum E<T> { Thing(isize, T), #[allow(dead_code)] Nothing((), ((), ()), [i8; 0]) } impl<T> E<T> { fn is_none(&self) -> bool {
diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs index 3cc50e3..436caab 100644 --- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs +++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs
@@ -1,8 +1,9 @@ // Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate. #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] -//~^ ERROR this is an internal attribute that will never be stable -trait Foo<Bar> -{} +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable +//~| NOTE see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute +trait Foo<Bar> {} fn main() {}
diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr index 2733f747..d198308 100644 --- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr +++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr
@@ -1,11 +1,12 @@ -error[E0658]: this is an internal attribute that will never be stable +error[E0658]: use of an internal attribute --> $DIR/feature-gate-on-unimplemented.rs:3:1 | LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable + = note: see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute error: aborting due to 1 previous error
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.fixed b/tests/ui/parser/bad-fn-ptr-qualifier.fixed index 8a97a2f..e9b87a7 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.fixed +++ b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
@@ -23,4 +23,12 @@ //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` +// Tests with qualifiers in the wrong order +pub type W1 = unsafe fn(); +//~^ ERROR an `fn` pointer type cannot be `const` +pub type W2 = unsafe fn(); +//~^ ERROR an `fn` pointer type cannot be `async` +pub type W3 = for<'a> unsafe fn(); +//~^ ERROR an `fn` pointer type cannot be `const` + fn main() {}
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.rs b/tests/ui/parser/bad-fn-ptr-qualifier.rs index f2611c9..f110375 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.rs +++ b/tests/ui/parser/bad-fn-ptr-qualifier.rs
@@ -23,4 +23,12 @@ //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` +// Tests with qualifiers in the wrong order +pub type W1 = unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` +pub type W2 = unsafe async fn(); +//~^ ERROR an `fn` pointer type cannot be `async` +pub type W3 = for<'a> unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` + fn main() {}
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr index b9d2625..f3fbbf6 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr +++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
@@ -2,10 +2,9 @@ --> $DIR/bad-fn-ptr-qualifier.rs:5:15 | LL | pub type T0 = const fn(); - | -----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T0 = const fn(); @@ -16,10 +15,9 @@ --> $DIR/bad-fn-ptr-qualifier.rs:6:15 | LL | pub type T1 = const extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T1 = const extern "C" fn(); @@ -30,10 +28,9 @@ --> $DIR/bad-fn-ptr-qualifier.rs:7:15 | LL | pub type T2 = const unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T2 = const unsafe extern "C" fn(); @@ -44,10 +41,9 @@ --> $DIR/bad-fn-ptr-qualifier.rs:8:15 | LL | pub type T3 = async fn(); - | -----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T3 = async fn(); @@ -58,10 +54,9 @@ --> $DIR/bad-fn-ptr-qualifier.rs:9:15 | LL | pub type T4 = async extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T4 = async extern "C" fn(); @@ -72,10 +67,9 @@ --> $DIR/bad-fn-ptr-qualifier.rs:10:15 | LL | pub type T5 = async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T5 = async unsafe extern "C" fn(); @@ -86,10 +80,9 @@ --> $DIR/bad-fn-ptr-qualifier.rs:11:15 | LL | pub type T6 = const async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T6 = const async unsafe extern "C" fn(); @@ -97,13 +90,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:11:15 + --> $DIR/bad-fn-ptr-qualifier.rs:11:21 | LL | pub type T6 = const async unsafe extern "C" fn(); - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T6 = const async unsafe extern "C" fn(); @@ -111,13 +103,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:15:17 + --> $DIR/bad-fn-ptr-qualifier.rs:15:25 | LL | pub type FTT0 = for<'a> const fn(); - | ^^^^^^^^-----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT0 = for<'a> const fn(); @@ -125,13 +116,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:16:17 + --> $DIR/bad-fn-ptr-qualifier.rs:16:25 | LL | pub type FTT1 = for<'a> const extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT1 = for<'a> const extern "C" fn(); @@ -139,13 +129,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:17:17 + --> $DIR/bad-fn-ptr-qualifier.rs:17:25 | LL | pub type FTT2 = for<'a> const unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT2 = for<'a> const unsafe extern "C" fn(); @@ -153,13 +142,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:18:17 + --> $DIR/bad-fn-ptr-qualifier.rs:18:25 | LL | pub type FTT3 = for<'a> async fn(); - | ^^^^^^^^-----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT3 = for<'a> async fn(); @@ -167,13 +155,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:19:17 + --> $DIR/bad-fn-ptr-qualifier.rs:19:25 | LL | pub type FTT4 = for<'a> async extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT4 = for<'a> async extern "C" fn(); @@ -181,13 +168,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:20:17 + --> $DIR/bad-fn-ptr-qualifier.rs:20:25 | LL | pub type FTT5 = for<'a> async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT5 = for<'a> async unsafe extern "C" fn(); @@ -195,13 +181,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:22:17 + --> $DIR/bad-fn-ptr-qualifier.rs:22:25 | LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); @@ -209,18 +194,56 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:22:17 + --> $DIR/bad-fn-ptr-qualifier.rs:22:31 | LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); LL + pub type FTT6 = for<'a> const unsafe extern "C" fn(); | -error: aborting due to 16 previous errors +error: an `fn` pointer type cannot be `const` + --> $DIR/bad-fn-ptr-qualifier.rs:27:22 + | +LL | pub type W1 = unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - pub type W1 = unsafe const fn(); +LL + pub type W1 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `async` + --> $DIR/bad-fn-ptr-qualifier.rs:29:22 + | +LL | pub type W2 = unsafe async fn(); + | ^^^^^ `async` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `async` qualifier + | +LL - pub type W2 = unsafe async fn(); +LL + pub type W2 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `const` + --> $DIR/bad-fn-ptr-qualifier.rs:31:30 + | +LL | pub type W3 = for<'a> unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - pub type W3 = for<'a> unsafe const fn(); +LL + pub type W3 = for<'a> unsafe fn(); + | + +error: aborting due to 19 previous errors
diff --git a/tests/ui/parser/macro/issue-33569.rs b/tests/ui/parser/macro/issue-33569.rs index 069d181..e0a5352 100644 --- a/tests/ui/parser/macro/issue-33569.rs +++ b/tests/ui/parser/macro/issue-33569.rs
@@ -2,7 +2,6 @@ { $+ } => { //~ ERROR expected identifier, found `+` //~^ ERROR missing fragment specifier //~| ERROR missing fragment specifier - //~| WARN this was previously accepted $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?` } }
diff --git a/tests/ui/parser/macro/issue-33569.stderr b/tests/ui/parser/macro/issue-33569.stderr index d1b6abf..0d53c04 100644 --- a/tests/ui/parser/macro/issue-33569.stderr +++ b/tests/ui/parser/macro/issue-33569.stderr
@@ -5,7 +5,7 @@ | ^ error: expected one of: `*`, `+`, or `?` - --> $DIR/issue-33569.rs:6:13 + --> $DIR/issue-33569.rs:5:13 | LL | $(x)(y) | ^^^ @@ -15,27 +15,19 @@ | LL | { $+ } => { | ^ + | + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | { $+:spec } => { + | +++++ error: missing fragment specifier --> $DIR/issue-33569.rs:2:8 | LL | { $+ } => { | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default error: aborting due to 4 previous errors -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/issue-33569.rs:2:8 - | -LL | { $+ } => { - | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default -
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs index 45d7534..a74b618 100644 --- a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs +++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
@@ -20,6 +20,14 @@ //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` +// Tests with qualifiers in the wrong order +type W1 = unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` +type W2 = unsafe async fn(); +//~^ ERROR an `fn` pointer type cannot be `async` +type W3 = for<'a> unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` + fn main() { let _recovery_witness: () = 0; //~ ERROR mismatched types }
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr index 4e59279..3700bee 100644 --- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr +++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
@@ -2,10 +2,9 @@ --> $DIR/recover-const-async-fn-ptr.rs:3:11 | LL | type T0 = const fn(); - | -----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T0 = const fn(); @@ -16,10 +15,9 @@ --> $DIR/recover-const-async-fn-ptr.rs:4:11 | LL | type T1 = const extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T1 = const extern "C" fn(); @@ -30,10 +28,9 @@ --> $DIR/recover-const-async-fn-ptr.rs:5:11 | LL | type T2 = const unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T2 = const unsafe extern "C" fn(); @@ -44,10 +41,9 @@ --> $DIR/recover-const-async-fn-ptr.rs:6:11 | LL | type T3 = async fn(); - | -----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T3 = async fn(); @@ -58,10 +54,9 @@ --> $DIR/recover-const-async-fn-ptr.rs:7:11 | LL | type T4 = async extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T4 = async extern "C" fn(); @@ -72,10 +67,9 @@ --> $DIR/recover-const-async-fn-ptr.rs:8:11 | LL | type T5 = async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T5 = async unsafe extern "C" fn(); @@ -86,10 +80,9 @@ --> $DIR/recover-const-async-fn-ptr.rs:9:11 | LL | type T6 = const async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T6 = const async unsafe extern "C" fn(); @@ -97,13 +90,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:9:11 + --> $DIR/recover-const-async-fn-ptr.rs:9:17 | LL | type T6 = const async unsafe extern "C" fn(); - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T6 = const async unsafe extern "C" fn(); @@ -111,13 +103,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:13:12 + --> $DIR/recover-const-async-fn-ptr.rs:13:20 | LL | type FT0 = for<'a> const fn(); - | ^^^^^^^^-----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT0 = for<'a> const fn(); @@ -125,13 +116,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:14:12 + --> $DIR/recover-const-async-fn-ptr.rs:14:20 | LL | type FT1 = for<'a> const extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT1 = for<'a> const extern "C" fn(); @@ -139,13 +129,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:15:12 + --> $DIR/recover-const-async-fn-ptr.rs:15:20 | LL | type FT2 = for<'a> const unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT2 = for<'a> const unsafe extern "C" fn(); @@ -153,13 +142,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:16:12 + --> $DIR/recover-const-async-fn-ptr.rs:16:20 | LL | type FT3 = for<'a> async fn(); - | ^^^^^^^^-----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT3 = for<'a> async fn(); @@ -167,13 +155,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:17:12 + --> $DIR/recover-const-async-fn-ptr.rs:17:20 | LL | type FT4 = for<'a> async extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT4 = for<'a> async extern "C" fn(); @@ -181,13 +168,12 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:18:12 + --> $DIR/recover-const-async-fn-ptr.rs:18:20 | LL | type FT5 = for<'a> async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT5 = for<'a> async unsafe extern "C" fn(); @@ -195,13 +181,12 @@ | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:19:12 + --> $DIR/recover-const-async-fn-ptr.rs:19:20 | LL | type FT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT6 = for<'a> const async unsafe extern "C" fn(); @@ -209,27 +194,65 @@ | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:19:12 + --> $DIR/recover-const-async-fn-ptr.rs:19:26 | LL | type FT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT6 = for<'a> const async unsafe extern "C" fn(); LL + type FT6 = for<'a> const unsafe extern "C" fn(); | +error: an `fn` pointer type cannot be `const` + --> $DIR/recover-const-async-fn-ptr.rs:24:18 + | +LL | type W1 = unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - type W1 = unsafe const fn(); +LL + type W1 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `async` + --> $DIR/recover-const-async-fn-ptr.rs:26:18 + | +LL | type W2 = unsafe async fn(); + | ^^^^^ `async` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `async` qualifier + | +LL - type W2 = unsafe async fn(); +LL + type W2 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `const` + --> $DIR/recover-const-async-fn-ptr.rs:28:26 + | +LL | type W3 = for<'a> unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - type W3 = for<'a> unsafe const fn(); +LL + type W3 = for<'a> unsafe fn(); + | + error[E0308]: mismatched types - --> $DIR/recover-const-async-fn-ptr.rs:24:33 + --> $DIR/recover-const-async-fn-ptr.rs:32:33 | LL | let _recovery_witness: () = 0; | -- ^ expected `()`, found integer | | | expected due to this -error: aborting due to 17 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index feee8cc..7b5ae49 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout
@@ -9,6 +9,7 @@ avr-non-blocking-interrupt cdecl cdecl-unwind +custom efiapi fastcall fastcall-unwind
diff --git a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr index f5cd455..df3c5c4 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr +++ b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr
@@ -3,6 +3,12 @@ | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S2; + | error: aborting due to 1 previous error
diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index f284b1c5..1206778 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr
@@ -16,6 +16,7 @@ LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export | @@ -31,6 +32,7 @@ LL | gen_helper_use!(); | ----------------- in this macro invocation | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export |
diff --git a/tests/ui/proc-macro/disappearing-resolution.stderr b/tests/ui/proc-macro/disappearing-resolution.stderr index 734e0cd..6c0f1a5 100644 --- a/tests/ui/proc-macro/disappearing-resolution.stderr +++ b/tests/ui/proc-macro/disappearing-resolution.stderr
@@ -3,6 +3,12 @@ | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S; + | error[E0603]: derive macro import `Empty` is private --> $DIR/disappearing-resolution.rs:11:8
diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.rs b/tests/ui/rustdoc/feature-gate-doc_primitive.rs index 78fcd90..dbf92f1 100644 --- a/tests/ui/rustdoc/feature-gate-doc_primitive.rs +++ b/tests/ui/rustdoc/feature-gate-doc_primitive.rs
@@ -1,5 +1,7 @@ #[rustc_doc_primitive = "usize"] -//~^ ERROR `rustc_doc_primitive` is a rustc internal attribute +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types /// Some docs mod usize {}
diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr index e74b132..0b1af78 100644 --- a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr +++ b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr
@@ -1,11 +1,12 @@ -error[E0658]: `rustc_doc_primitive` is a rustc internal attribute +error[E0658]: use of an internal attribute --> $DIR/feature-gate-doc_primitive.rs:1:1 | LL | #[rustc_doc_primitive = "usize"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types error: aborting due to 1 previous error
diff --git a/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs b/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs index 76d7754..4dc170c 100644 --- a/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs +++ b/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs
@@ -50,10 +50,6 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {} trait Trait { - // This method isn't dyn-compatible yet. Unsized by-value `self` is dyn-compatible (but not - // callable without unsized_locals), but wrappers arond `Self` currently are not. - // FIXME (mikeyhew) uncomment this when unsized rvalues dyn-compatibility is implemented - // fn wrapper(self: Wrapper<Self>) -> i32; fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32; fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32; fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
diff --git a/tests/ui/simd/size-align.rs b/tests/ui/simd/size-align.rs index ff23ea5..53acb68 100644 --- a/tests/ui/simd/size-align.rs +++ b/tests/ui/simd/size-align.rs
@@ -7,12 +7,12 @@ use std::mem; -/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec<T>` properly +/// `T` should satisfy `size_of T (mod align_of T) === 0` to be stored at `Vec<T>` properly /// Please consult the issue #20460 fn check<T>() { - assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); - assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); - assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0); } #[repr(simd)]
diff --git a/tests/ui/sized/unsized-binding.stderr b/tests/ui/sized/unsized-binding.stderr index 8de236c..da3ba53 100644 --- a/tests/ui/sized/unsized-binding.stderr +++ b/tests/ui/sized/unsized-binding.stderr
@@ -6,7 +6,6 @@ | = help: the trait `Sized` is not implemented for `str` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | LL - let x = *"";
diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs index 35abbb8..fff6806 100644 --- a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs +++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
@@ -16,7 +16,6 @@ fn main() { //~^ ERROR the size for values of type `str` cannot be known at compilation time //~| HELP consider not dereferencing the expression //~| HELP the trait `Sized` is not implemented for `str` - //~| HELP unsized locals are gated as an unstable feature bar(x); S.baz(x); bar(*"");
diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr index 9b7258a..29cedf3 100644 --- a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr +++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr
@@ -22,7 +22,6 @@ | = help: the trait `Sized` is not implemented for `str` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | LL - let x = *""; @@ -30,7 +29,7 @@ | error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:22:9 + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:21:9 | LL | bar(*""); | --- ^^^ doesn't have a size known at compile-time @@ -50,7 +49,7 @@ | error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:26:11 + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:25:11 | LL | S.baz(*""); | --- ^^^ doesn't have a size known at compile-time
diff --git a/tests/ui/stability-attribute/renamed_feature.rs b/tests/ui/stability-attribute/renamed_feature.rs new file mode 100644 index 0000000..249c2ab --- /dev/null +++ b/tests/ui/stability-attribute/renamed_feature.rs
@@ -0,0 +1,3 @@ +#![feature(try_trait)] //~ ERROR feature `try_trait` has been renamed to `try_trait_v2` [E0635] + +fn main() {}
diff --git a/tests/ui/stability-attribute/renamed_feature.stderr b/tests/ui/stability-attribute/renamed_feature.stderr new file mode 100644 index 0000000..293a2fe --- /dev/null +++ b/tests/ui/stability-attribute/renamed_feature.stderr
@@ -0,0 +1,9 @@ +error[E0635]: feature `try_trait` has been renamed to `try_trait_v2` + --> $DIR/renamed_feature.rs:1:12 + | +LL | #![feature(try_trait)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0635`.
diff --git a/tests/ui/static/static-drop-scope.rs b/tests/ui/static/static-drop-scope.rs index 74b224c..ddcabeb 100644 --- a/tests/ui/static/static-drop-scope.rs +++ b/tests/ui/static/static-drop-scope.rs
@@ -4,12 +4,6 @@ impl Drop for WithDtor { fn drop(&mut self) {} } -static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); -//~^ ERROR destructor of - -const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); -//~^ ERROR destructor of - static EARLY_DROP_S: i32 = (WithDtor, 0).1; //~^ ERROR destructor of
diff --git a/tests/ui/static/static-drop-scope.stderr b/tests/ui/static/static-drop-scope.stderr index 24658bc..0fdf081 100644 --- a/tests/ui/static/static-drop-scope.stderr +++ b/tests/ui/static/static-drop-scope.stderr
@@ -1,21 +1,5 @@ -error[E0493]: destructor of `WithDtor` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:7:60 - | -LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^- value is dropped here - | | - | the destructor for this type cannot be evaluated in statics - -error[E0493]: destructor of `WithDtor` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:10:59 - | -LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^- value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - error[E0493]: destructor of `(WithDtor, i32)` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:13:28 + --> $DIR/static-drop-scope.rs:7:28 | LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1; | ^^^^^^^^^^^^^ - value is dropped here @@ -23,7 +7,7 @@ | the destructor for this type cannot be evaluated in statics error[E0493]: destructor of `(WithDtor, i32)` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:16:27 + --> $DIR/static-drop-scope.rs:10:27 | LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1; | ^^^^^^^^^^^^^ - value is dropped here @@ -31,7 +15,7 @@ | the destructor for this type cannot be evaluated in constants error[E0493]: destructor of `(Option<WithDtor>, i32)` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:27:34 + --> $DIR/static-drop-scope.rs:21:34 | LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1; | ^^^^^^^^^^^^^^^^^^^ - value is dropped here @@ -39,7 +23,7 @@ | the destructor for this type cannot be evaluated in constants error[E0493]: destructor of `(Option<WithDtor>, i32)` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:32:43 + --> $DIR/static-drop-scope.rs:26:43 | LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; | ^^^^^^^^^^^ - value is dropped here @@ -47,7 +31,7 @@ | the destructor for this type cannot be evaluated in constants error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:19:24 + --> $DIR/static-drop-scope.rs:13:24 | LL | const fn const_drop<T>(_: T) {} | ^ - value is dropped here @@ -55,7 +39,7 @@ | the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `(T, ())` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:23:5 + --> $DIR/static-drop-scope.rs:17:5 | LL | (x, ()).1 | ^^^^^^^ the destructor for this type cannot be evaluated in constant functions @@ -63,6 +47,6 @@ LL | } | - value is dropped here -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/stats/auxiliary/include.rs b/tests/ui/stats/auxiliary/include.rs new file mode 100644 index 0000000..7fb7c78 --- /dev/null +++ b/tests/ui/stats/auxiliary/include.rs
@@ -0,0 +1,3 @@ +fn zzz(x: u32) -> u32 { + x +}
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index f2598bd..88f91be 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr
@@ -82,10 +82,10 @@ hir-stats - Let 32 (NN.N%) 1 hir-stats - Semi 32 (NN.N%) 1 hir-stats FnDecl 120 (NN.N%) 3 40 -hir-stats Attribute 128 (NN.N%) 4 32 hir-stats FieldDef 128 (NN.N%) 2 64 hir-stats GenericArgs 144 (NN.N%) 3 48 hir-stats Variant 144 (NN.N%) 2 72 +hir-stats Attribute 160 (NN.N%) 4 40 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 hir-stats Block 288 (NN.N%) 6 48 @@ -117,5 +117,5 @@ hir-stats Path 1_040 (NN.N%) 26 40 hir-stats PathSegment 1_776 (NN.N%) 37 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_644 172 +hir-stats Total 8_676 172 hir-stats
diff --git a/tests/ui/stats/macro-stats.rs b/tests/ui/stats/macro-stats.rs new file mode 100644 index 0000000..ee265d6 --- /dev/null +++ b/tests/ui/stats/macro-stats.rs
@@ -0,0 +1,130 @@ +//@ check-pass +//@ compile-flags: -Zmacro-stats + +#[test] +fn test_foo() { + let what = "this"; + let how = "completely"; + let when = "immediately"; + println!("{what} disappears {how} and {when}"); +} + +#[rustfmt::skip] // non-macro attr, ignored by `-Zmacro-stats` +fn rustfmt_skip() { + // Nothing to see here. +} + +#[derive(Default, Clone, Copy, Hash)] +enum E1 { + #[default] // non-macro attr, ignored by `-Zmacro-stats` + A, + B, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct E2 { + a: u32, + b: String, + c: Vec<bool>, +} + +#[derive(Clone)] struct S0; +#[derive(Clone)] struct S1(u32); +#[derive(Clone)] struct S2(u32, u32); +#[derive(Clone)] struct S3(u32, u32, u32); +#[derive(Clone)] struct S4(u32, u32, u32, u32); +#[derive(Clone)] struct S5(u32, u32, u32, u32, u32); + +macro_rules! u32 { + () => { u32 } +} + +macro_rules! none { + () => { None } +} +fn opt(x: Option<u32>) { + match x { + Some(_) => {} + none!() => {} // AstFragmentKind::Pat + } +} + +macro_rules! this_is_a_really_really_long_macro_name { + ($t:ty) => { + fn f(_: $t) {} + } +} +this_is_a_really_really_long_macro_name!(u32!()); // AstFragmentKind::{Items,Ty} + +macro_rules! trait_tys { + () => { + type A; + type B; + } +} +trait Tr { + trait_tys!(); // AstFragmentKind::TraitItems +} + +macro_rules! impl_const { () => { const X: u32 = 0; } } +struct U; +impl U { + impl_const!(); // AstFragmentKind::ImplItems +} + +macro_rules! trait_impl_tys { + () => { + type A = u32; + type B = bool; + } +} +struct Tr1; +impl Tr for Tr1 { + trait_impl_tys!(); // AstFragment::TraitImplItems +} + +macro_rules! foreign_item { + () => { fn fc(a: u32) -> u32; } +} +extern "C" { + foreign_item!(); // AstFragment::ForeignItems +} + +// Include macros are ignored by `-Zmacro-stats`. +mod includes { + mod z1 { + include!("auxiliary/include.rs"); + } + mod z2 { + std::include!("auxiliary/include.rs"); + } + + const B1: &[u8] = include_bytes!("auxiliary/include.rs"); + const B2: &[u8] = std::include_bytes!("auxiliary/include.rs"); + + const S1: &str = include_str!("auxiliary/include.rs"); + const S2: &str = std::include_str!("auxiliary/include.rs"); +} + +fn main() { + macro_rules! n99 { + () => { 99 } + } + let x = n99!() + n99!(); // AstFragmentKind::Expr + + macro_rules! p { + () => { + // blah + let x = 1; + let y = x; + let _ = y; + } + } + p!(); // AstFragmentKind::Stmts + + macro_rules! q { + () => {}; + ($($x:ident),*) => { $( let $x: u32 = 12345; )* }; + } + q!(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); +}
diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr new file mode 100644 index 0000000..f87e346 --- /dev/null +++ b/tests/ui/stats/macro-stats.stderr
@@ -0,0 +1,26 @@ +macro-stats =================================================================================== +macro-stats MACRO EXPANSION STATS: macro_stats +macro-stats Macro Name Uses Lines Avg Lines Bytes Avg Bytes +macro-stats ----------------------------------------------------------------------------------- +macro-stats #[derive(Clone)] 8 56 7.0 1_660 207.5 +macro-stats #[derive(PartialOrd)] 1 16 16.0 654 654.0 +macro-stats #[derive(Hash)] 2 15 7.5 547 273.5 +macro-stats #[derive(Ord)] 1 14 14.0 489 489.0 +macro-stats q! 1 24 24.0 435 435.0 +macro-stats #[derive(Default)] 2 14 7.0 367 183.5 +macro-stats #[derive(Eq)] 1 10 10.0 312 312.0 +macro-stats #[derive(Debug)] 1 7 7.0 261 261.0 +macro-stats #[derive(PartialEq)] 1 8 8.0 247 247.0 +macro-stats #[derive(Copy)] 1 1 1.0 46 46.0 +macro-stats p! 1 2 2.0 28 28.0 +macro-stats trait_impl_tys! 1 1 1.0 11 11.0 +macro-stats foreign_item! 1 0 0.0 6 6.0 +macro-stats impl_const! 1 0 0.0 4 4.0 +macro-stats trait_tys! 1 1 1.0 3 3.0 +macro-stats u32! 1 0 0.0 -3 -3.0 +macro-stats none! 1 0 0.0 -3 -3.0 +macro-stats n99! 2 0 0.0 -8 -4.0 +macro-stats this_is_a_really_really_long_macro_name! +macro-stats 1 0 0.0 -30 -30.0 +macro-stats #[test] 1 -6 -6.0 -158 -158.0 +macro-stats ===================================================================================
diff --git a/tests/ui/str/str-array-assignment.stderr b/tests/ui/str/str-array-assignment.stderr index 515cb9e..76eb783 100644 --- a/tests/ui/str/str-array-assignment.stderr +++ b/tests/ui/str/str-array-assignment.stderr
@@ -25,7 +25,6 @@ | = help: the trait `Sized` is not implemented for `str` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider borrowing here | LL | let v = &s[..2];
diff --git a/tests/ui/structs-enums/enum-alignment.rs b/tests/ui/structs-enums/enum-alignment.rs index bb779b1..95f14e5 100644 --- a/tests/ui/structs-enums/enum-alignment.rs +++ b/tests/ui/structs-enums/enum-alignment.rs
@@ -11,7 +11,7 @@ fn addr_of<T>(ptr: &T) -> usize { fn is_aligned<T>(ptr: &T) -> bool { unsafe { let addr: usize = mem::transmute(ptr); - (addr % mem::min_align_of::<T>()) == 0 + (addr % mem::align_of::<T>()) == 0 } }
diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs-enums/rec-align-u32.rs index 4487918..b18cd11 100644 --- a/tests/ui/structs-enums/rec-align-u32.rs +++ b/tests/ui/structs-enums/rec-align-u32.rs
@@ -34,12 +34,12 @@ pub fn main() { // Send it through the shape code let y = format!("{:?}", x); - println!("align inner = {:?}", intrinsics::min_align_of::<Inner>()); + println!("align inner = {:?}", intrinsics::align_of::<Inner>()); println!("size outer = {:?}", mem::size_of::<Outer>()); println!("y = {:?}", y); // per clang/gcc the alignment of `inner` is 4 on x86. - assert_eq!(intrinsics::min_align_of::<Inner>(), m::align()); + assert_eq!(intrinsics::align_of::<Inner>(), m::align()); // per clang/gcc the size of `outer` should be 12 // because `inner`s alignment was 4.
diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 0f7bb6b..df21989 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs
@@ -84,12 +84,12 @@ pub fn main() { let y = format!("{:?}", x); - println!("align inner = {:?}", intrinsics::min_align_of::<Inner>()); + println!("align inner = {:?}", intrinsics::align_of::<Inner>()); println!("size outer = {:?}", mem::size_of::<Outer>()); println!("y = {:?}", y); // per clang/gcc the alignment of `Inner` is 4 on x86. - assert_eq!(intrinsics::min_align_of::<Inner>(), m::m::align()); + assert_eq!(intrinsics::align_of::<Inner>(), m::m::align()); // per clang/gcc the size of `Outer` should be 12 // because `Inner`s alignment was 4.
diff --git a/tests/ui/structs-enums/tag-align-dyn-u64.rs b/tests/ui/structs-enums/tag-align-dyn-u64.rs index 5e7d918..5a4f087 100644 --- a/tests/ui/structs-enums/tag-align-dyn-u64.rs +++ b/tests/ui/structs-enums/tag-align-dyn-u64.rs
@@ -19,7 +19,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag<u64>) -> bool { let p: usize = unsafe { mem::transmute(u) }; - let u64_align = std::mem::min_align_of::<u64>(); + let u64_align = std::mem::align_of::<u64>(); return (p & (u64_align - 1)) == 0; }
diff --git a/tests/ui/structs-enums/tag-align-dyn-variants.rs b/tests/ui/structs-enums/tag-align-dyn-variants.rs index c0574f3..019f1a8 100644 --- a/tests/ui/structs-enums/tag-align-dyn-variants.rs +++ b/tests/ui/structs-enums/tag-align-dyn-variants.rs
@@ -34,7 +34,7 @@ fn variant_data_is_aligned<A,B>(amnt: usize, u: &Tag<A,B>) -> bool { } pub fn main() { - let u64_align = std::mem::min_align_of::<u64>(); + let u64_align = std::mem::align_of::<u64>(); let x = mk_rec(22u64, 23u64); assert!(is_aligned(u64_align, &x.tA)); assert!(variant_data_is_aligned(u64_align, &x.tA));
diff --git a/tests/ui/structs-enums/tag-align-u64.rs b/tests/ui/structs-enums/tag-align-u64.rs index 8ab9f24..e274cc0 100644 --- a/tests/ui/structs-enums/tag-align-u64.rs +++ b/tests/ui/structs-enums/tag-align-u64.rs
@@ -19,7 +19,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; - let u64_align = std::mem::min_align_of::<u64>(); + let u64_align = std::mem::align_of::<u64>(); return (p & (u64_align - 1)) == 0; }
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr new file mode 100644 index 0000000..e2b6078 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr
@@ -0,0 +1,7 @@ +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `x86-retpoline` target modifier flag instead + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted +
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr new file mode 100644 index 0000000..2a0f5f0 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr
@@ -0,0 +1,7 @@ +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted +
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr new file mode 100644 index 0000000..f7b6cb1 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr
@@ -0,0 +1,7 @@ +warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted +
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr new file mode 100644 index 0000000..4f2cd1d --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr
@@ -0,0 +1,7 @@ +warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted +
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs new file mode 100644 index 0000000..de3c44c --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs
@@ -0,0 +1,21 @@ +//@ add-core-stubs +//@ revisions: by_flag by_feature1 by_feature2 by_feature3 +//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: x86 +//@ [by_flag]compile-flags: -Zretpoline + +//@ [by_feature1]compile-flags: -Ctarget-feature=+retpoline-external-thunk +//@ [by_feature2]compile-flags: -Ctarget-feature=+retpoline-indirect-branches +//@ [by_feature3]compile-flags: -Ctarget-feature=+retpoline-indirect-calls +//@ [by_flag]build-pass +// For now this is just a warning. +//@ [by_feature1]build-pass +//@ [by_feature2]build-pass +//@ [by_feature3]build-pass +#![feature(no_core)] +#![no_core] +extern crate minicore; + +//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead +//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
diff --git a/tests/ui/tool-attributes/diagnostic_item.rs b/tests/ui/tool-attributes/diagnostic_item.rs index 26a52ce..806b140 100644 --- a/tests/ui/tool-attributes/diagnostic_item.rs +++ b/tests/ui/tool-attributes/diagnostic_item.rs
@@ -1,3 +1,5 @@ -#[rustc_diagnostic_item = "foomp"] //~ ERROR compiler internal support for linting +#[rustc_diagnostic_item = "foomp"] +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes struct Foomp; fn main() {}
diff --git a/tests/ui/tool-attributes/diagnostic_item.stderr b/tests/ui/tool-attributes/diagnostic_item.stderr index c6ae5a3..d370442 100644 --- a/tests/ui/tool-attributes/diagnostic_item.stderr +++ b/tests/ui/tool-attributes/diagnostic_item.stderr
@@ -1,11 +1,11 @@ -error[E0658]: diagnostic items compiler internal support for linting +error[E0658]: use of an internal attribute --> $DIR/diagnostic_item.rs:1:1 | LL | #[rustc_diagnostic_item = "foomp"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes error: aborting due to 1 previous error
diff --git a/tests/ui/traits/associated_type_bound/hrtb-associated.rs b/tests/ui/traits/associated_type_bound/hrtb-associated.rs index 59e5a09..bf9f59c 100644 --- a/tests/ui/traits/associated_type_bound/hrtb-associated.rs +++ b/tests/ui/traits/associated_type_bound/hrtb-associated.rs
@@ -10,7 +10,7 @@ pub trait Provides<'a> { pub trait Selector: for<'a> Provides<'a> { type Namespace: PartialEq + for<'a> PartialEq<<Self as Provides<'a>>::Item>; - fn get_namespace(&self) -> <Self as Provides>::Item; + fn get_namespace(&self) -> <Self as Provides<'_>>::Item; } pub struct MySelector;
diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs index 27e7055..47cc9f5 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs
@@ -1,5 +1,7 @@ #[rustc_must_implement_one_of(eq, neq)] -//~^ ERROR the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization trait Equal { fn eq(&self, other: &Self) -> bool { !self.neq(other)
diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr index 162c3d3..4d44cef 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr
@@ -1,11 +1,12 @@ -error[E0658]: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std +error[E0658]: use of an internal attribute --> $DIR/rustc_must_implement_one_of_gated.rs:1:1 | LL | #[rustc_must_implement_one_of(eq, neq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization error: aborting due to 1 previous error
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs index ea6df93..14f0cbc 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs
@@ -13,9 +13,9 @@ fn main() { } fn weird0() -> impl Sized + !Sized {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Sized` is not satisfied fn weird1() -> impl !Sized + Sized {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Sized` is not satisfied fn weird2() -> impl !Sized {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Sized` is not satisfied //~| ERROR the size for values of type
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr index 41d9e74..3ba3d8d 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr
@@ -7,23 +7,23 @@ = help: the trait `Sized` is not implemented for `impl !Sized` = note: the return type of a function must have a statically known size -error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` +error[E0277]: the trait bound `(): !Sized` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:15:16 | LL | fn weird0() -> impl Sized + !Sized {} - | ^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied -error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` +error[E0277]: the trait bound `(): !Sized` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:17:16 | LL | fn weird1() -> impl !Sized + Sized {} - | ^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied -error[E0271]: type mismatch resolving `impl !Sized == ()` +error[E0277]: the trait bound `(): !Sized` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:19:16 | LL | fn weird2() -> impl !Sized {} - | ^^^^^^^^^^^ types differ + | ^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:12:13 @@ -41,5 +41,4 @@ error: aborting due to 5 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs index ce42bce..3942291 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs
@@ -3,6 +3,6 @@ #![feature(negative_bounds, unboxed_closures)] fn produce() -> impl !Fn<(u32,)> {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Fn(u32)` is not satisfied fn main() {}
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr index e1b84e0..760e5aa6 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr
@@ -1,9 +1,9 @@ -error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()` +error[E0277]: the trait bound `(): !Fn(u32)` is not satisfied --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17 | LL | fn produce() -> impl !Fn<(u32,)> {} - | ^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^ the trait bound `(): !Fn(u32)` is not satisfied error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr index 736c8c1..6d2bbd8 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr
@@ -1,9 +1,16 @@ -error[E0284]: type annotations needed: cannot satisfy `Foo == _` +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 | LL | needs_send::<Foo>(); - | ^^^ cannot satisfy `Foo == _` + | ^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 + | +LL | fn needs_send<T: Send>() {} + | ^^^^ required by this bound in `needs_send` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr index 736c8c1..6d2bbd8 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr
@@ -1,9 +1,16 @@ -error[E0284]: type annotations needed: cannot satisfy `Foo == _` +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 | LL | needs_send::<Foo>(); - | ^^^ cannot satisfy `Foo == _` + | ^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 + | +LL | fn needs_send<T: Send>() {} + | ^^^^ required by this bound in `needs_send` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs index 2a08a3b..fddf892 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs
@@ -14,7 +14,7 @@ fn needs_send<T: Send>() {} #[define_opaque(Foo)] fn test(_: Foo) { needs_send::<Foo>(); - //~^ ERROR type annotations needed: cannot satisfy `Foo == _` + //~^ ERROR type annotations needed } #[define_opaque(Foo)]
diff --git a/tests/ui/traits/object/no-incomplete-inference.current.stderr b/tests/ui/traits/object/no-incomplete-inference.current.stderr new file mode 100644 index 0000000..3c6b811 --- /dev/null +++ b/tests/ui/traits/object/no-incomplete-inference.current.stderr
@@ -0,0 +1,16 @@ +error[E0283]: type annotations needed + --> $DIR/no-incomplete-inference.rs:16:5 + | +LL | impls_equals::<dyn Equals<u32>, _>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals` + | + = note: cannot satisfy `dyn Equals<u32>: Equals<_>` +note: required by a bound in `impls_equals` + --> $DIR/no-incomplete-inference.rs:13:20 + | +LL | fn impls_equals<T: Equals<U> + ?Sized, U: ?Sized>() {} + | ^^^^^^^^^ required by this bound in `impls_equals` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/object/no-incomplete-inference.next.stderr b/tests/ui/traits/object/no-incomplete-inference.next.stderr new file mode 100644 index 0000000..3c6b811 --- /dev/null +++ b/tests/ui/traits/object/no-incomplete-inference.next.stderr
@@ -0,0 +1,16 @@ +error[E0283]: type annotations needed + --> $DIR/no-incomplete-inference.rs:16:5 + | +LL | impls_equals::<dyn Equals<u32>, _>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals` + | + = note: cannot satisfy `dyn Equals<u32>: Equals<_>` +note: required by a bound in `impls_equals` + --> $DIR/no-incomplete-inference.rs:13:20 + | +LL | fn impls_equals<T: Equals<U> + ?Sized, U: ?Sized>() {} + | ^^^^^^^^^ required by this bound in `impls_equals` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/object/no-incomplete-inference.rs b/tests/ui/traits/object/no-incomplete-inference.rs new file mode 100644 index 0000000..9ed8dd6 --- /dev/null +++ b/tests/ui/traits/object/no-incomplete-inference.rs
@@ -0,0 +1,18 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + + +// Make sure that having an applicable user-written +// and builtin impl is ambiguous. + +trait Equals<T: ?Sized> {} + +impl<T: ?Sized> Equals<T> for T {} + +fn impls_equals<T: Equals<U> + ?Sized, U: ?Sized>() {} + +fn main() { + impls_equals::<dyn Equals<u32>, _>(); + //~^ ERROR type annotations needed +}
diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr index 9e83de5..f7e0245 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr
@@ -7,7 +7,7 @@ LL | impl<In, Out> Trait<(), In> for Out { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation -error[E0284]: type annotations needed: cannot satisfy `Bar == _` +error[E0282]: type annotations needed --> $DIR/issue-84660-unsoundness.rs:24:37 | LL | fn convert(_i: In) -> Self::Out { @@ -16,9 +16,9 @@ LL | | LL | | unreachable!(); LL | | } - | |_____^ cannot satisfy `Bar == _` + | |_____^ cannot infer type error: aborting due to 2 previous errors -Some errors have detailed explanations: E0119, E0284. +Some errors have detailed explanations: E0119, E0282. For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs index 7a540d2..a385138 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
@@ -22,7 +22,7 @@ impl<In, Out> Trait<Bar, In> for Out { type Out = Out; #[define_opaque(Bar)] fn convert(_i: In) -> Self::Out { - //[next]~^ ERROR: type annotations needed: cannot satisfy `Bar == _` + //[next]~^ ERROR: type annotations needed //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}` unreachable!(); }
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr index b733739..d212797 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr
@@ -1,9 +1,9 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Foo<FooX> == ()` +error[E0282]: type annotations needed --> $DIR/nested-tait-inference2.rs:20:5 | LL | () - | ^^ cannot satisfy `impl Foo<FooX> == ()` + | ^^ cannot infer type error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs b/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs index 4aeecb9..6063361 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs
@@ -18,7 +18,7 @@ impl Foo<u32> for () {} fn foo() -> impl Foo<FooX> { //[current]~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied () - //[next]~^ ERROR: cannot satisfy `impl Foo<FooX> == ()` + //[next]~^ ERROR: type annotations needed } fn main() {}
diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 9712ba5..cd1a5d0 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout
@@ -190,7 +190,7 @@ (static async || value); (static async move || value); || -> u8 { value }; - 1 + (|| {}); + 1 + || {}; } /// ExprKind::Block
diff --git a/tests/ui/unsized-locals/align.rs b/tests/ui/unsized-locals/align.rs index a3820e3..fdb83a8 100644 --- a/tests/ui/unsized-locals/align.rs +++ b/tests/ui/unsized-locals/align.rs
@@ -1,8 +1,5 @@ // Test that unsized locals uphold alignment requirements. // Regression test for #71416. -//@ run-pass -#![feature(unsized_locals)] -#![allow(incomplete_features)] use std::any::Any; #[repr(align(256))] @@ -23,7 +20,7 @@ fn mk() -> Box<dyn Any> { } fn main() { - let x = *mk(); + let x = *mk(); //~ERROR the size for values of type `dyn Any` cannot be known at compilation time let dwncst = x.downcast_ref::<A>().unwrap(); let addr = dwncst.f(); assert_eq!(addr as usize % 256, 0);
diff --git a/tests/ui/unsized-locals/align.stderr b/tests/ui/unsized-locals/align.stderr new file mode 100644 index 0000000..7a48ad1 --- /dev/null +++ b/tests/ui/unsized-locals/align.stderr
@@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `dyn Any` cannot be known at compilation time + --> $DIR/align.rs:23:9 + | +LL | let x = *mk(); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Any` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *mk(); +LL + let x = mk(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/autoderef.rs b/tests/ui/unsized-locals/autoderef.rs index 31b58ba..24f8a4c 100644 --- a/tests/ui/unsized-locals/autoderef.rs +++ b/tests/ui/unsized-locals/autoderef.rs
@@ -1,7 +1,4 @@ -//@ run-pass - -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![feature(unsized_fn_params)] pub trait Foo { fn foo(self) -> String; @@ -26,7 +23,7 @@ fn foo(mut self) -> String { } fn main() { - let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); + let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); //~ERROR the size for values of type `[char]` cannot be known at compilation time assert_eq!(&x.foo() as &str, "hello"); let x = Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>; @@ -35,13 +32,13 @@ fn main() { let x = "hello".to_owned().into_boxed_str(); assert_eq!(&x.foo() as &str, "hello"); - let x = *("hello".to_owned().into_boxed_str()); + let x = *("hello".to_owned().into_boxed_str()); //~ERROR the size for values of type `str` cannot be known at compilation time assert_eq!(&x.foo() as &str, "hello"); let x = "hello".to_owned().into_boxed_str(); assert_eq!(&x.foo() as &str, "hello"); - let x = *(Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>); + let x = *(Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>); //~ERROR the size for values of type `dyn FnMut() -> String` cannot be known at compilation time assert_eq!(&x.foo() as &str, "hello"); let x = Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>;
diff --git a/tests/ui/unsized-locals/autoderef.stderr b/tests/ui/unsized-locals/autoderef.stderr new file mode 100644 index 0000000..785badc --- /dev/null +++ b/tests/ui/unsized-locals/autoderef.stderr
@@ -0,0 +1,45 @@ +error[E0277]: the size for values of type `[char]` cannot be known at compilation time + --> $DIR/autoderef.rs:26:9 + | +LL | let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[char]` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); +LL + let x = (Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); + | + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/autoderef.rs:35:9 + | +LL | let x = *("hello".to_owned().into_boxed_str()); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *("hello".to_owned().into_boxed_str()); +LL + let x = ("hello".to_owned().into_boxed_str()); + | + +error[E0277]: the size for values of type `dyn FnMut() -> String` cannot be known at compilation time + --> $DIR/autoderef.rs:41:9 + | +LL | let x = *(Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn FnMut() -> String` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *(Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>); +LL + let x = (Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>); + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/auxiliary/ufuncs.rs b/tests/ui/unsized-locals/auxiliary/ufuncs.rs index 5954abf..7853418 100644 --- a/tests/ui/unsized-locals/auxiliary/ufuncs.rs +++ b/tests/ui/unsized-locals/auxiliary/ufuncs.rs
@@ -1,3 +1,3 @@ -#![feature(unsized_locals, unsized_fn_params)] +#![feature(unsized_fn_params)] pub fn udrop<T: ?Sized>(_x: T) {}
diff --git a/tests/ui/unsized-locals/borrow-after-move.rs b/tests/ui/unsized-locals/borrow-after-move.rs index ad73b72..6c51091 100644 --- a/tests/ui/unsized-locals/borrow-after-move.rs +++ b/tests/ui/unsized-locals/borrow-after-move.rs
@@ -1,5 +1,4 @@ -#![feature(unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete +#![feature(unsized_fn_params)] pub trait Foo { fn foo(self) -> String; @@ -16,28 +15,23 @@ fn drop_unsized<T: ?Sized>(_: T) {} fn main() { { let x = "hello".to_owned().into_boxed_str(); - let y = *x; + let y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] drop_unsized(y); println!("{}", &x); - //~^ERROR borrow of moved value println!("{}", &y); - //~^ERROR borrow of moved value } { let x = "hello".to_owned().into_boxed_str(); - let y = *x; + let y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] y.foo(); println!("{}", &x); - //~^ERROR borrow of moved value println!("{}", &y); - //~^ERROR borrow of moved value } { let x = "hello".to_owned().into_boxed_str(); x.foo(); println!("{}", &x); - //~^ERROR borrow of moved value } }
diff --git a/tests/ui/unsized-locals/borrow-after-move.stderr b/tests/ui/unsized-locals/borrow-after-move.stderr index 9e3c345..1a4ce39 100644 --- a/tests/ui/unsized-locals/borrow-after-move.stderr +++ b/tests/ui/unsized-locals/borrow-after-move.stderr
@@ -1,85 +1,31 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/borrow-after-move.rs:1:12 - | -LL | #![feature(unsized_locals, unsized_fn_params)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:21:24 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/borrow-after-move.rs:18:13 | LL | let y = *x; - | -- value moved here -LL | drop_unsized(y); -LL | println!("{}", &x); - | ^^ value borrowed here after move + | ^ doesn't have a size known at compile-time | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let y = *x; +LL + let y = x; + | -error[E0382]: borrow of moved value: `y` - --> $DIR/borrow-after-move.rs:23:24 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/borrow-after-move.rs:26:13 | LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | drop_unsized(y); - | - value moved here -... -LL | println!("{}", &y); - | ^^ value borrowed here after move + | ^ doesn't have a size known at compile-time | -note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary - --> $DIR/borrow-after-move.rs:14:31 + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | -LL | fn drop_unsized<T: ?Sized>(_: T) {} - | ------------ ^ this parameter takes ownership of the value - | | - | in this function +LL - let y = *x; +LL + let y = x; + | -error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:31:24 - | -LL | let y = *x; - | -- value moved here -LL | y.foo(); -LL | println!("{}", &x); - | ^^ value borrowed here after move - | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait +error: aborting due to 2 previous errors -error[E0382]: borrow of moved value: `y` - --> $DIR/borrow-after-move.rs:33:24 - | -LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | y.foo(); - | ----- `y` moved due to this method call -... -LL | println!("{}", &y); - | ^^ value borrowed here after move - | -note: `Foo::foo` takes ownership of the receiver `self`, which moves `y` - --> $DIR/borrow-after-move.rs:5:12 - | -LL | fn foo(self) -> String; - | ^^^^ - -error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:40:24 - | -LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `Box<str>`, which does not implement the `Copy` trait -LL | x.foo(); - | - value moved here -LL | println!("{}", &x); - | ^^ value borrowed here after move - | -help: consider cloning the value if the performance cost is acceptable - | -LL | x.clone().foo(); - | ++++++++ - -error: aborting due to 5 previous errors; 1 warning emitted - -For more information about this error, try `rustc --explain E0382`. +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.rs b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.rs index 7ccea43..26d2bc6 100644 --- a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.rs +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.rs
@@ -1,8 +1,3 @@ -//@ run-pass - -#![allow(incomplete_features)] -#![feature(unsized_locals)] - pub trait Foo { fn foo(self) -> String; } @@ -16,7 +11,7 @@ fn foo(self) -> String { } fn main() { - let x = *(Box::new(A) as Box<dyn Foo>); + let x = *(Box::new(A) as Box<dyn Foo>); //~ERROR the size for values of type `dyn Foo` cannot be known at compilation time assert_eq!(x.foo(), format!("hello")); // I'm not sure whether we want this to work
diff --git a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.stderr b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.stderr new file mode 100644 index 0000000..231cc05 --- /dev/null +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.stderr
@@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `dyn Foo` cannot be known at compilation time + --> $DIR/by-value-trait-dyn-compatibility-rpass.rs:14:9 + | +LL | let x = *(Box::new(A) as Box<dyn Foo>); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Foo` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *(Box::new(A) as Box<dyn Foo>); +LL + let x = (Box::new(A) as Box<dyn Foo>); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.rs b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.rs index 1f9b5f1..554c270 100644 --- a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.rs +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.rs
@@ -1,7 +1,5 @@ -//@ run-pass - -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![allow(internal_features)] +#![feature(unsized_fn_params)] pub trait Foo { fn foo(self) -> String { @@ -14,7 +12,7 @@ fn foo(self) -> String { impl Foo for A {} fn main() { - let x = *(Box::new(A) as Box<dyn Foo>); + let x = *(Box::new(A) as Box<dyn Foo>); //~ERROR the size for values of type `dyn Foo` cannot be known at compilation time assert_eq!(x.foo(), format!("hello")); // I'm not sure whether we want this to work
diff --git a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.stderr b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.stderr new file mode 100644 index 0000000..6d8370f --- /dev/null +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.stderr
@@ -0,0 +1,17 @@ +error[E0277]: the size for values of type `dyn Foo` cannot be known at compilation time + --> $DIR/by-value-trait-dyn-compatibility-with-default.rs:15:9 + | +LL | let x = *(Box::new(A) as Box<dyn Foo>); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Foo` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *(Box::new(A) as Box<dyn Foo>); +LL + let x = (Box::new(A) as Box<dyn Foo>); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.rs b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.rs index d0ba694..d390f18 100644 --- a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.rs +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.rs
@@ -1,6 +1,3 @@ -#![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete - pub trait Foo { fn foo(self) -> String where @@ -16,7 +13,7 @@ fn foo(self) -> String { } fn main() { - let x = *(Box::new(A) as Box<dyn Foo>); + let x = *(Box::new(A) as Box<dyn Foo>); //~ERROR the size for values of type `dyn Foo` cannot be known at compilation time [E0277] x.foo(); //~^ERROR the `foo` method cannot be invoked on a trait object }
diff --git a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.stderr b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.stderr index 223624c..1c681ba 100644 --- a/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.stderr +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.stderr
@@ -1,14 +1,5 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/by-value-trait-dyn-compatibility.rs:1:12 - | -LL | #![feature(unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error: the `foo` method cannot be invoked on a trait object - --> $DIR/by-value-trait-dyn-compatibility.rs:20:7 + --> $DIR/by-value-trait-dyn-compatibility.rs:17:7 | LL | Self: Sized; | ----- this has a `Sized` requirement @@ -16,5 +7,20 @@ LL | x.foo(); | ^^^ -error: aborting due to 1 previous error; 1 warning emitted +error[E0277]: the size for values of type `dyn Foo` cannot be known at compilation time + --> $DIR/by-value-trait-dyn-compatibility.rs:16:9 + | +LL | let x = *(Box::new(A) as Box<dyn Foo>); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Foo` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *(Box::new(A) as Box<dyn Foo>); +LL + let x = (Box::new(A) as Box<dyn Foo>); + | +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/double-move.rs b/tests/ui/unsized-locals/double-move.rs index 9e46ef9..254528ab 100644 --- a/tests/ui/unsized-locals/double-move.rs +++ b/tests/ui/unsized-locals/double-move.rs
@@ -1,5 +1,4 @@ -#![feature(unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete +#![feature(unsized_fn_params)] pub trait Foo { fn foo(self) -> String; @@ -16,39 +15,39 @@ fn drop_unsized<T: ?Sized>(_: T) {} fn main() { { let x = "hello".to_owned().into_boxed_str(); - let y = *x; + let y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] drop_unsized(y); - drop_unsized(y); //~ERROR use of moved value + drop_unsized(y); } { let x = "hello".to_owned().into_boxed_str(); - let _y = *x; - drop_unsized(x); //~ERROR use of moved value + let _y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] + drop_unsized(x); } { let x = "hello".to_owned().into_boxed_str(); drop_unsized(x); - let _y = *x; //~ERROR use of moved value + let _y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] } { let x = "hello".to_owned().into_boxed_str(); - let y = *x; + let y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] y.foo(); - y.foo(); //~ERROR use of moved value + y.foo(); } { let x = "hello".to_owned().into_boxed_str(); - let _y = *x; - x.foo(); //~ERROR use of moved value + let _y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] + x.foo(); } { let x = "hello".to_owned().into_boxed_str(); x.foo(); - let _y = *x; //~ERROR use of moved value + let _y = *x; //~ERROR the size for values of type `str` cannot be known at compilation time [E0277] } }
diff --git a/tests/ui/unsized-locals/double-move.stderr b/tests/ui/unsized-locals/double-move.stderr index 49b906b..8d97b16 100644 --- a/tests/ui/unsized-locals/double-move.stderr +++ b/tests/ui/unsized-locals/double-move.stderr
@@ -1,86 +1,87 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/double-move.rs:1:12 - | -LL | #![feature(unsized_locals, unsized_fn_params)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0382]: use of moved value: `y` - --> $DIR/double-move.rs:21:22 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/double-move.rs:18:13 | LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | drop_unsized(y); - | - value moved here -LL | drop_unsized(y); - | ^ value used here after move + | ^ doesn't have a size known at compile-time | -note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary - --> $DIR/double-move.rs:14:31 + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | -LL | fn drop_unsized<T: ?Sized>(_: T) {} - | ------------ ^ this parameter takes ownership of the value - | | - | in this function +LL - let y = *x; +LL + let y = x; + | -error[E0382]: use of moved value: `x` - --> $DIR/double-move.rs:27:22 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/double-move.rs:25:13 | LL | let _y = *x; - | -- value moved here -LL | drop_unsized(x); - | ^ value used here after move + | ^^ doesn't have a size known at compile-time | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let _y = *x; +LL + let _y = x; + | -error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:33:18 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/double-move.rs:32:13 | -LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `Box<str>`, which does not implement the `Copy` trait -LL | drop_unsized(x); - | - value moved here LL | let _y = *x; - | ^^ value used here after move + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let _y = *x; +LL + let _y = x; + | -error[E0382]: use of moved value: `y` - --> $DIR/double-move.rs:40:9 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/double-move.rs:37:13 | LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | y.foo(); - | ----- `y` moved due to this method call -LL | y.foo(); - | ^ value used here after move + | ^ doesn't have a size known at compile-time | -note: `Foo::foo` takes ownership of the receiver `self`, which moves `y` - --> $DIR/double-move.rs:5:12 + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | -LL | fn foo(self) -> String; - | ^^^^ +LL - let y = *x; +LL + let y = x; + | -error[E0382]: use of moved value: `x` - --> $DIR/double-move.rs:46:9 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/double-move.rs:44:13 | LL | let _y = *x; - | -- value moved here -LL | x.foo(); - | ^ value used here after move + | ^^ doesn't have a size known at compile-time | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let _y = *x; +LL + let _y = x; + | -error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:52:18 +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/double-move.rs:51:13 | -LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `Box<str>`, which does not implement the `Copy` trait -LL | x.foo(); - | - value moved here LL | let _y = *x; - | ^^ value used here after move + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let _y = *x; +LL + let _y = x; + | -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0382`. +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs index ec47567..4b15e19 100644 --- a/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs +++ b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.rs
@@ -1,7 +1,5 @@ // ICE size_and_align_of::<[closure@test.rs:15:5: 17:7]> not supported #88212 // issue: rust-lang/rust#88212 -#![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes trait Example {} struct Foo(); @@ -13,9 +11,8 @@ fn example() -> Box<dyn Example> { } fn main() { - let x: dyn Example = *example(); + let x: dyn Example = *example(); //~ERROR the size for values of type `dyn Example` cannot be known at compilation time (move || { - let _y = x; - //~^ ERROR the size for values of type `dyn Example` cannot be known at compilation time + let _y = x; //~ERROR the size for values of type `dyn Example` cannot be known at compilation time })(); }
diff --git a/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr index a0253ac..ffee985 100644 --- a/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr +++ b/tests/ui/unsized-locals/ice-size_and_align_of-closure-not-supported-88212.stderr
@@ -1,23 +1,25 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ice-size_and_align_of-closure-not-supported-88212.rs:3:12 - | -LL | #![feature(unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `dyn Example` cannot be known at compilation time - --> $DIR/ice-size_and_align_of-closure-not-supported-88212.rs:18:18 + --> $DIR/ice-size_and_align_of-closure-not-supported-88212.rs:14:9 | -LL | (move || { - | -- this closure captures all values by move -LL | let _y = x; - | ^ doesn't have a size known at compile-time +LL | let x: dyn Example = *example(); + | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn Example` - = note: all values captured by value by a closure must have a statically known size + = note: all local variables must have a statically known size +help: consider borrowing here + | +LL | let x: &dyn Example = *example(); + | + -error: aborting due to 1 previous error; 1 warning emitted +error[E0277]: the size for values of type `dyn Example` cannot be known at compilation time + --> $DIR/ice-size_and_align_of-closure-not-supported-88212.rs:16:13 + | +LL | let _y = x; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Example` + = note: all local variables must have a statically known size + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/issue-30276-feature-flagged.rs b/tests/ui/unsized-locals/issue-30276-feature-flagged.rs index 8b5b321..6b67ebb 100644 --- a/tests/ui/unsized-locals/issue-30276-feature-flagged.rs +++ b/tests/ui/unsized-locals/issue-30276-feature-flagged.rs
@@ -1,6 +1,3 @@ -#![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete - struct Test([i32]); fn main() {
diff --git a/tests/ui/unsized-locals/issue-30276-feature-flagged.stderr b/tests/ui/unsized-locals/issue-30276-feature-flagged.stderr index ee8e4f3..a7bf27a 100644 --- a/tests/ui/unsized-locals/issue-30276-feature-flagged.stderr +++ b/tests/ui/unsized-locals/issue-30276-feature-flagged.stderr
@@ -1,14 +1,5 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-30276-feature-flagged.rs:1:12 - | -LL | #![feature(unsized_locals)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `[i32]` cannot be known at compilation time - --> $DIR/issue-30276-feature-flagged.rs:7:29 + --> $DIR/issue-30276-feature-flagged.rs:4:29 | LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time @@ -17,6 +8,6 @@ = note: all function arguments must have a statically known size = help: unsized fn params are gated as an unstable feature -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/issue-50940-with-feature.rs b/tests/ui/unsized-locals/issue-50940-with-feature.rs index 63b0e83..9a1ba7a 100644 --- a/tests/ui/unsized-locals/issue-50940-with-feature.rs +++ b/tests/ui/unsized-locals/issue-50940-with-feature.rs
@@ -1,5 +1,4 @@ -#![feature(unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete +#![feature(unsized_fn_params)] fn main() { struct A<X: ?Sized>(X);
diff --git a/tests/ui/unsized-locals/issue-50940-with-feature.stderr b/tests/ui/unsized-locals/issue-50940-with-feature.stderr index b39eb2e..f3fb3ac 100644 --- a/tests/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/tests/ui/unsized-locals/issue-50940-with-feature.stderr
@@ -1,26 +1,17 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-50940-with-feature.rs:1:12 - | -LL | #![feature(unsized_locals, unsized_fn_params)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/issue-50940-with-feature.rs:6:5 + --> $DIR/issue-50940-with-feature.rs:5:5 | LL | A as fn(str) -> A<str>; | ^ doesn't have a size known at compile-time | = help: within `A<str>`, the trait `Sized` is not implemented for `str` note: required because it appears within the type `A<str>` - --> $DIR/issue-50940-with-feature.rs:5:12 + --> $DIR/issue-50940-with-feature.rs:4:12 | LL | struct A<X: ?Sized>(X); | ^ = note: the return type of a function must have a statically known size -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/reference-unsized-locals.rs b/tests/ui/unsized-locals/reference-unsized-locals.rs index 5b5fca2..757bae4b 100644 --- a/tests/ui/unsized-locals/reference-unsized-locals.rs +++ b/tests/ui/unsized-locals/reference-unsized-locals.rs
@@ -1,10 +1,5 @@ -//@ run-pass - -#![allow(incomplete_features)] -#![feature(unsized_locals)] - fn main() { let foo: Box<[u8]> = Box::new(*b"foo"); - let foo: [u8] = *foo; + let foo: [u8] = *foo; //~ERROR the size for values of type `[u8]` cannot be known at compilation time [E0277] assert_eq!(&foo, b"foo" as &[u8]); }
diff --git a/tests/ui/unsized-locals/reference-unsized-locals.stderr b/tests/ui/unsized-locals/reference-unsized-locals.stderr new file mode 100644 index 0000000..d1cba9b --- /dev/null +++ b/tests/ui/unsized-locals/reference-unsized-locals.stderr
@@ -0,0 +1,16 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/reference-unsized-locals.rs:3:9 + | +LL | let foo: [u8] = *foo; + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size +help: consider borrowing here + | +LL | let foo: &[u8] = *foo; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/simple-unsized-locals.rs b/tests/ui/unsized-locals/simple-unsized-locals.rs index 374031b..e6c8bdc 100644 --- a/tests/ui/unsized-locals/simple-unsized-locals.rs +++ b/tests/ui/unsized-locals/simple-unsized-locals.rs
@@ -1,9 +1,4 @@ -//@ run-pass - -#![allow(incomplete_features)] -#![feature(unsized_locals)] - fn main() { let foo: Box<[u8]> = Box::new(*b"foo"); - let _foo: [u8] = *foo; + let _foo: [u8] = *foo; //~ERROR the size for values of type `[u8]` cannot be known at compilation time [E0277] }
diff --git a/tests/ui/unsized-locals/simple-unsized-locals.stderr b/tests/ui/unsized-locals/simple-unsized-locals.stderr new file mode 100644 index 0000000..83a64bd --- /dev/null +++ b/tests/ui/unsized-locals/simple-unsized-locals.stderr
@@ -0,0 +1,16 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/simple-unsized-locals.rs:3:9 + | +LL | let _foo: [u8] = *foo; + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size +help: consider borrowing here + | +LL | let _foo: &[u8] = *foo; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsized-locals/suggest-borrow.stderr b/tests/ui/unsized-locals/suggest-borrow.stderr index 8741b35..a3b4403 100644 --- a/tests/ui/unsized-locals/suggest-borrow.stderr +++ b/tests/ui/unsized-locals/suggest-borrow.stderr
@@ -6,7 +6,6 @@ | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider borrowing here | LL | let x: &[u8] = vec!(1, 2, 3)[..]; @@ -51,7 +50,6 @@ | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider borrowing here | LL | let x: &[u8] = &vec!(1, 2, 3)[..];
diff --git a/tests/ui/unsized-locals/unsized-exprs-rpass.rs b/tests/ui/unsized-locals/unsized-exprs-rpass.rs index 861583e..54ecd00 100644 --- a/tests/ui/unsized-locals/unsized-exprs-rpass.rs +++ b/tests/ui/unsized-locals/unsized-exprs-rpass.rs
@@ -1,6 +1,6 @@ //@ run-pass -#![allow(incomplete_features, unused_braces, unused_parens)] -#![feature(unsized_locals, unsized_fn_params)] +#![allow(internal_features, unused_braces, unused_parens)] +#![feature(unsized_fn_params)] struct A<X: ?Sized>(#[allow(dead_code)] X);
diff --git a/tests/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr b/tests/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr index ace5a87..fe6780c 100644 --- a/tests/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr +++ b/tests/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr
@@ -6,7 +6,6 @@ | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `[i32]` cannot be known at compilation time --> $DIR/unsized-locals-using-unsized-fn-params.rs:8:12 @@ -16,7 +15,6 @@ | = help: the trait `Sized` is not implemented for `[i32]` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/unsized-locals-using-unsized-fn-params.rs:13:9 @@ -26,7 +24,6 @@ | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider borrowing here | LL | let _foo: &[u8] = *foo;
diff --git a/tests/ui/unsized-locals/yote.rs b/tests/ui/unsized-locals/yote.rs new file mode 100644 index 0000000..aa5b68a --- /dev/null +++ b/tests/ui/unsized-locals/yote.rs
@@ -0,0 +1,4 @@ +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" + +#![feature(unsized_locals)] //~ERROR feature has been removed +#![crate_type = "lib"]
diff --git a/tests/ui/unsized-locals/yote.stderr b/tests/ui/unsized-locals/yote.stderr new file mode 100644 index 0000000..655aad5 --- /dev/null +++ b/tests/ui/unsized-locals/yote.stderr
@@ -0,0 +1,12 @@ +error[E0557]: feature has been removed + --> $DIR/yote.rs:3:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ feature has been removed + | + = note: removed in CURRENT_RUSTC_VERSION (you are using $RUSTC_VERSION) + = note: removed due to implementation concerns; see https://github.com/rust-lang/rust/issues/111942 + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0557`.
diff --git a/tests/ui/unsized/unsized6.stderr b/tests/ui/unsized/unsized6.stderr index de92170..2dcdd3c 100644 --- a/tests/ui/unsized/unsized6.stderr +++ b/tests/ui/unsized/unsized6.stderr
@@ -8,7 +8,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) { @@ -60,7 +59,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f2<X: ?Sized, Y: ?Sized>(x: &X) { @@ -96,7 +94,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { @@ -117,7 +114,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { @@ -139,7 +135,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { @@ -155,7 +150,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { @@ -176,7 +170,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { @@ -198,7 +191,6 @@ | ^ doesn't have a size known at compile-time | = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
diff --git a/triagebot.toml b/triagebot.toml index 52d18d2..e5af77b 100644 --- a/triagebot.toml +++ b/triagebot.toml
@@ -1229,6 +1229,7 @@ "@oli-obk", "@petrochenkov", "@SparrowLii", + "@WaffleLapkin", "@wesleywiser", ] libs = [ @@ -1240,13 +1241,6 @@ "@thomcc", "@ibraheemdev", ] -bootstrap = [ - "@Mark-Simulacrum", - "@albertlarsan68", - "@kobzol", - "@jieyouxu", - "@clubby789", -] infra-ci = [ "@Mark-Simulacrum", "@Kobzol", @@ -1266,6 +1260,7 @@ "@dianqk", "@saethlin", "@workingjubilee", + "@WaffleLapkin", ] query-system = [ "@oli-obk",