diff options
399 files changed, 4389 insertions, 2204 deletions
diff --git a/.gitmodules b/.gitmodules index b5250d49386..926807336d7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,3 +47,7 @@ path = src/tools/rustc-perf url = https://github.com/rust-lang/rustc-perf.git shallow = true +[submodule "src/tools/enzyme"] + path = src/tools/enzyme + url = https://github.com/EnzymeAD/Enzyme.git + shallow = true diff --git a/RELEASES.md b/RELEASES.md index 29c872eb448..b49470c3075 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -34,7 +34,6 @@ Compiler - [Add Tier 3 `std` Xtensa targets:](https://github.com/rust-lang/rust/pull/126380/) `xtensa-esp32-espidf`, `xtensa-esp32s2-espidf`, `xtensa-esp32s3-espidf` - [Add Tier 3 i686 Redox OS target:](https://github.com/rust-lang/rust/pull/126192/) `i686-unknown-redox` - [Promote `arm64ec-pc-windows-msvc` to Tier 2.](https://github.com/rust-lang/rust/pull/126039/) - - [Promote `wasm32-wasip2` to Tier 2.](https://github.com/rust-lang/rust/pull/126967/) - [Promote `loongarch64-unknown-linux-musl` to Tier 2 with host tools.](https://github.com/rust-lang/rust/pull/126298/) - [Enable full tools and profiler for LoongArch Linux targets.](https://github.com/rust-lang/rust/pull/127078/) - [Unconditionally warn on usage of `wasm32-wasi`.](https://github.com/rust-lang/rust/pull/126662/) (see compatibility note below) @@ -100,6 +99,9 @@ Compatibility Notes The reason is that these types have different roles: `std::panic::PanicHookInfo` is the argument to the [panic hook](https://doc.rust-lang.org/stable/std/panic/fn.set_hook.html) in std context (where panics can have an arbitrary payload), while `core::panic::PanicInfo` is the argument to the [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) in no_std context (where panics always carry a formatted *message*). Separating these types allows us to add more useful methods to these types, such as `std::panic::PanicHookInfo::payload_as_str()` and `core::panic::PanicInfo::message()`. * The new sort implementations may panic if a type's implementation of [`Ord`](https://doc.rust-lang.org/std/cmp/trait.Ord.html) (or the given comparison function) does not implement a [total order](https://en.wikipedia.org/wiki/Total_order) as the trait requires. `Ord`'s supertraits (`PartialOrd`, `Eq`, and `PartialEq`) must also be consistent. The previous implementations would not "notice" any problem, but the new implementations have a good chance of detecting inconsistencies, throwing a panic rather than returning knowingly unsorted data. +* [In very rare cases, a change in the internal evaluation order of the trait + solver may result in new fatal overflow errors.](https://github.com/rust-lang/rust/pull/126128) + <a id="1.81.0-Internal-Changes"></a> diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 8a66894a356..7c8af6c4a55 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -752,7 +752,7 @@ fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrToke pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) { let Token { kind, span } = t; match kind { - token::Ident(name, _ /*raw*/) | token::Lifetime(name) => { + token::Ident(name, _is_raw) | token::Lifetime(name, _is_raw) => { let mut ident = Ident::new(*name, *span); vis.visit_ident(&mut ident); *name = ident.name; @@ -762,7 +762,7 @@ pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) { token::NtIdent(ident, _is_raw) => { vis.visit_ident(ident); } - token::NtLifetime(ident) => { + token::NtLifetime(ident, _is_raw) => { vis.visit_ident(ident); } token::Interpolated(nt) => { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f1dddb3acac..a0082a41713 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -331,11 +331,11 @@ pub enum TokenKind { /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to /// treat regular and interpolated lifetime identifiers in the same way. - Lifetime(Symbol), + Lifetime(Symbol, IdentIsRaw), /// This identifier (and its span) is the lifetime passed to the /// declarative macro. The span in the surrounding `Token` is the span of /// the `lifetime` metavariable in the macro's RHS. - NtLifetime(Ident), + NtLifetime(Ident, IdentIsRaw), /// An embedded AST node, as produced by a macro. This only exists for /// historical reasons. We'd like to get rid of it, for multiple reasons. @@ -458,7 +458,7 @@ impl Token { /// if they keep spans or perform edition checks. pub fn uninterpolated_span(&self) -> Span { match self.kind { - NtIdent(ident, _) | NtLifetime(ident) => ident.span, + NtIdent(ident, _) | NtLifetime(ident, _) => ident.span, Interpolated(ref nt) => nt.use_span(), _ => self.span, } @@ -661,7 +661,9 @@ impl Token { pub fn uninterpolate(&self) -> Cow<'_, Token> { match self.kind { NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)), - NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)), + NtLifetime(ident, is_raw) => { + Cow::Owned(Token::new(Lifetime(ident.name, is_raw), ident.span)) + } _ => Cow::Borrowed(self), } } @@ -679,11 +681,11 @@ impl Token { /// Returns a lifetime identifier if this token is a lifetime. #[inline] - pub fn lifetime(&self) -> Option<Ident> { + pub fn lifetime(&self) -> Option<(Ident, IdentIsRaw)> { // We avoid using `Token::uninterpolate` here because it's slow. match self.kind { - Lifetime(name) => Some(Ident::new(name, self.span)), - NtLifetime(ident) => Some(ident), + Lifetime(name, is_raw) => Some((Ident::new(name, self.span), is_raw)), + NtLifetime(ident, is_raw) => Some((ident, is_raw)), _ => None, } } @@ -865,7 +867,7 @@ impl Token { _ => return None, }, SingleQuote => match joint.kind { - Ident(name, IdentIsRaw::No) => Lifetime(Symbol::intern(&format!("'{name}"))), + Ident(name, is_raw) => Lifetime(Symbol::intern(&format!("'{name}")), is_raw), _ => return None, }, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 057b4455dca..fc1dd2caf68 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -482,11 +482,11 @@ impl TokenStream { token::NtIdent(ident, is_raw) => { TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) } - token::NtLifetime(ident) => TokenTree::Delimited( + token::NtLifetime(ident, is_raw) => TokenTree::Delimited( DelimSpan::from_single(token.span), DelimSpacing::new(Spacing::JointHidden, spacing), Delimiter::Invisible, - TokenStream::token_alone(token::Lifetime(ident.name), ident.span), + TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), ), token::Interpolated(ref nt) => TokenTree::Delimited( DelimSpan::from_single(token.span), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c7ff39d23ed..3b1449d9a91 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,7 +11,9 @@ use std::borrow::Cow; use ast::TraitBoundModifiers; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{ + self, BinOpToken, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind, +}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; @@ -947,8 +949,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere token::NtIdent(ident, is_raw) => { IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into() } - token::Lifetime(name) => name.to_string().into(), - token::NtLifetime(ident) => ident.name.to_string().into(), + + token::Lifetime(name, IdentIsRaw::No) + | token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(), + token::Lifetime(name, IdentIsRaw::Yes) + | token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => { + format!("'r#{}", &name.as_str()[1..]).into() + } /* Other */ token::DocComment(comment_kind, attr_style, data) => { diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 91b02a36d00..c720b0928fe 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -662,9 +662,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { // `&dyn Trait` ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box<dyn Trait>` - _ if ty.is_box() && ty.boxed_ty().is_trait() => { + _ if ty.boxed_ty().is_some_and(Ty::is_trait) => { true } + // `dyn Trait` _ if ty.is_trait() => true, // Anything else. diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5ab66963409..878ce6162e0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -345,9 +345,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { variant_index: Option<VariantIdx>, including_tuple_field: IncludingTupleField, ) -> Option<String> { - if ty.is_box() { + if let Some(boxed_ty) = ty.boxed_ty() { // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field) + self.describe_field_from_ty(boxed_ty, field, variant_index, including_tuple_field) } else { match *ty.kind() { ty::Adt(def, _) => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index ffb350b1d1f..d40dcfa5805 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2522,7 +2522,7 @@ mod diags { } pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> { - let mut res = None; + let mut res = self.infcx.tainted_by_errors(); // Buffer any move errors that we collected and de-duplicated. for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 224f8d5c893..3c9a43883ad 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1979,19 +1979,76 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match cast_kind { CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); + let src_sig = op.ty(body, tcx).fn_sig(tcx); + + // HACK: This shouldn't be necessary... We can remove this when we actually + // get binders with where clauses, then elaborate implied bounds into that + // binder, and implement a higher-ranked subtyping algorithm that actually + // respects these implied bounds. + // + // This protects against the case where we are casting from a higher-ranked + // fn item to a non-higher-ranked fn pointer, where the cast throws away + // implied bounds that would've needed to be checked at the call site. This + // only works when we're casting to a non-higher-ranked fn ptr, since + // placeholders in the target signature could have untracked implied + // bounds, resulting in incorrect errors. + // + // We check that this signature is WF before subtyping the signature with + // the target fn sig. + if src_sig.has_bound_regions() + && let ty::FnPtr(target_fn_tys, target_hdr) = *ty.kind() + && let target_sig = target_fn_tys.with(target_hdr) + && let Some(target_sig) = target_sig.no_bound_vars() + { + let src_sig = self.infcx.instantiate_binder_with_fresh_vars( + span, + BoundRegionConversionTime::HigherRankedType, + src_sig, + ); + let src_ty = Ty::new_fn_ptr(self.tcx(), ty::Binder::dummy(src_sig)); + self.prove_predicate( + ty::ClauseKind::WellFormed(src_ty.into()), + location.to_locations(), + ConstraintCategory::Cast { unsize_to: None }, + ); + + let src_ty = self.normalize(src_ty, location); + if let Err(terr) = self.sub_types( + src_ty, + *ty, + location.to_locations(), + ConstraintCategory::Cast { unsize_to: None }, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + target_sig, + src_sig, + terr + ); + }; + } + + let src_ty = Ty::new_fn_ptr(tcx, src_sig); + // HACK: We want to assert that the signature of the source fn is + // well-formed, because we don't enforce that via the WF of FnDef + // types normally. This should be removed when we improve the tracking + // of implied bounds of fn signatures. + self.prove_predicate( + ty::ClauseKind::WellFormed(src_ty.into()), + location.to_locations(), + ConstraintCategory::Cast { unsize_to: None }, + ); // The type that we see in the fcx is like // `foo::<'a, 'b>`, where `foo` is the path to a // function definition. When we extract the // signature, it comes from the `fn_sig` query, // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); - - let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig); - + let src_ty = self.normalize(src_ty, location); if let Err(terr) = self.sub_types( - ty_fn_ptr_from, + src_ty, *ty, location.to_locations(), ConstraintCategory::Cast { unsize_to: None }, @@ -2000,7 +2057,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self, rvalue, "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, + src_ty, ty, terr ); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9eabe817359..164be73f492 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -29,7 +29,8 @@ use rustc_macros::extension; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt, + self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, + TyCtxt, TypeVisitableExt, }; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym}; @@ -688,7 +689,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>> { let tcx = self.infcx.tcx; - match defining_ty { + + let inputs_and_output = match defining_ty { DefiningTy::Closure(def_id, args) => { assert_eq!(self.mir_def.to_def_id(), def_id); let closure_sig = args.as_closure().sig(); @@ -798,6 +800,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // "output" (the type of the constant). assert_eq!(self.mir_def.to_def_id(), def_id); let ty = tcx.type_of(self.mir_def).instantiate_identity(); + let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } @@ -807,7 +810,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = args.as_inline_const().ty(); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } + }; + + // FIXME(#129952): We probably want a more principled approach here. + if let Err(terr) = inputs_and_output.skip_binder().error_reported() { + self.infcx.set_tainted_by_errors(terr); } + + inputs_and_output } } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 92a857c2adc..9d4497d73a8 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -411,26 +411,31 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( // the string "false". Now it is disabled by absence of the attribute. to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false")); } - } else if llvm_util::get_version() >= (19, 0, 0) { - // For non-naked functions, set branch protection attributes on aarch64. - if let Some(BranchProtection { bti, pac_ret }) = - cx.sess().opts.unstable_opts.branch_protection - { - assert!(cx.sess().target.arch == "aarch64"); - if bti { - to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); - } - if let Some(PacRet { leaf, key }) = pac_ret { - to_add.push(llvm::CreateAttrStringValue( - cx.llcx, - "sign-return-address", - if leaf { "all" } else { "non-leaf" }, - )); - to_add.push(llvm::CreateAttrStringValue( - cx.llcx, - "sign-return-address-key", - if key == PAuthKey::A { "a_key" } else { "b_key" }, - )); + } else { + // Do not set sanitizer attributes for naked functions. + to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); + + if llvm_util::get_version() >= (19, 0, 0) { + // For non-naked functions, set branch protection attributes on aarch64. + if let Some(BranchProtection { bti, pac_ret }) = + cx.sess().opts.unstable_opts.branch_protection + { + assert!(cx.sess().target.arch == "aarch64"); + if bti { + to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); + } + if let Some(PacRet { leaf, key }) = pac_ret { + to_add.push(llvm::CreateAttrStringValue( + cx.llcx, + "sign-return-address", + if leaf { "all" } else { "non-leaf" }, + )); + to_add.push(llvm::CreateAttrStringValue( + cx.llcx, + "sign-return-address-key", + if key == PAuthKey::A { "a_key" } else { "b_key" }, + )); + } } } } @@ -485,7 +490,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( if let Some(backchain) = backchain_attr(cx) { to_add.push(backchain); } - to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); // Always annotate functions with the target-cpu they are compiled for. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 17a9630c655..d231b103964 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -456,7 +456,7 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> if def.is_box() && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) => { - build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id) + build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id) } ty::FnDef(..) | ty::FnPtr(..) => build_subroutine_type_di_node(cx, unique_type_id), ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id), diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index a300f5f707a..05fb77a193a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -187,9 +187,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { Some(instance), ) } - sym::likely => { - self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)]) - } + sym::likely => self.expect(args[0].immediate(), true), sym::is_val_statically_known => { let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx); let kind = self.type_kind(intrinsic_type); @@ -210,8 +208,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.const_bool(false) } } - sym::unlikely => self - .call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]), + sym::unlikely => self.expect(args[0].immediate(), false), sym::select_unpredictable => { let cond = args[0].immediate(); assert_eq!(args[1].layout, args[2].layout); @@ -604,11 +601,17 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } fn assume(&mut self, val: Self::Value) { - self.call_intrinsic("llvm.assume", &[val]); + if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { + self.call_intrinsic("llvm.assume", &[val]); + } } fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value { - self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) + if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No { + self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) + } else { + cond + } } fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 618602ed70f..d55220ba5c3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -353,9 +353,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { None } }) - .filter(|feature| { - RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature)) - }) + .filter(|feature| features.contains(&Symbol::intern(feature))) .map(|feature| Symbol::intern(feature)) .collect() } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 9b5a797ad51..0fd9d7fffe8 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -372,27 +372,42 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static Some(file) } -/// Since Xcode 15 Apple's LD requires object files to contain information about what they were -/// built for (LC_BUILD_VERSION): the platform (macOS/watchOS etc), minimum OS version, and SDK -/// version. This returns a `MachOBuildVersion` for the target. +/// Mach-O files contain information about: +/// - The platform/OS they were built for (macOS/watchOS/Mac Catalyst/iOS simulator etc). +/// - The minimum OS version / deployment target. +/// - The version of the SDK they were targetting. +/// +/// In the past, this was accomplished using the LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, +/// LC_VERSION_MIN_TVOS or LC_VERSION_MIN_WATCHOS load commands, which each contain information +/// about the deployment target and SDK version, and implicitly, by their presence, which OS they +/// target. Simulator targets were determined if the architecture was x86_64, but there was e.g. a +/// LC_VERSION_MIN_IPHONEOS present. +/// +/// This is of course brittle and limited, so modern tooling emit the LC_BUILD_VERSION load +/// command (which contains all three pieces of information in one) when the deployment target is +/// high enough, or the target is something that wouldn't be encodable with the old load commands +/// (such as Mac Catalyst, or Aarch64 iOS simulator). +/// +/// Since Xcode 15, Apple's LD apparently requires object files to use this load command, so this +/// returns the `MachOBuildVersion` for the target to do so. fn macho_object_build_version_for_target(target: &Target) -> object::write::MachOBuildVersion { /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz" /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200 - fn pack_version((major, minor): (u32, u32)) -> u32 { - (major << 16) | (minor << 8) + fn pack_version((major, minor, patch): (u16, u8, u8)) -> u32 { + let (major, minor, patch) = (major as u32, minor as u32, patch as u32); + (major << 16) | (minor << 8) | patch } let platform = rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS"); - let min_os = rustc_target::spec::current_apple_deployment_target(target) - .expect("unknown Apple target OS"); - let sdk = + let min_os = rustc_target::spec::current_apple_deployment_target(target); + let (sdk_major, sdk_minor) = rustc_target::spec::current_apple_sdk_version(platform).expect("unknown Apple target OS"); let mut build_version = object::write::MachOBuildVersion::default(); build_version.platform = platform; build_version.minos = pack_version(min_os); - build_version.sdk = pack_version(sdk); + build_version.sdk = pack_version((sdk_major, sdk_minor, 0)); build_version } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d94c6f8ddce..91fd9905f63 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -382,7 +382,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { scalar: abi::Scalar, backend_ty: Bx::Type, ) { - if matches!(self.cx.sess().opts.optimize, OptLevel::No | OptLevel::Less) + if matches!(self.cx.sess().opts.optimize, OptLevel::No) // For now, the critical niches are all over `Int`eger values. // Should floating-point values or pointers ever get more complex // niches, then this code will probably want to handle them too. diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 2ef860fc336..73283cafb49 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,6 +1,5 @@ use rustc_middle::mir::{self, NonDivergingIntrinsic}; use rustc_middle::span_bug; -use rustc_session::config::OptLevel; use tracing::instrument; use super::{FunctionCx, LocalRef}; @@ -68,10 +67,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_coverage(bx, kind, statement.source_info.scope); } mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { - if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) { - let op_val = self.codegen_operand(bx, op); - bx.assume(op_val.immediate()); - } + let op_val = self.codegen_operand(bx, op); + bx.assume(op_val.immediate()); } mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( mir::CopyNonOverlapping { ref count, ref src, ref dst }, diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 82438eb5e78..568a9a3a637 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -189,7 +189,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::Ref(_, ty, _) => *ty, ty::RawPtr(ty, _) => *ty, // We only accept `Box` with the default allocator. - _ if ty.is_box_global(*self.tcx) => ty.boxed_ty(), + _ if ty.is_box_global(*self.tcx) => ty.expect_boxed_ty(), _ => return Ok(None), })) }; diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 0f2c0eee27d..aaa95f6b7f1 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -57,6 +57,7 @@ impl<T> Steal<T> { /// /// This should not be used within rustc as it leaks information not tracked /// by the query system, breaking incremental compilation. + #[cfg_attr(not(bootstrap), rustc_lint_untracked_query_information)] pub fn is_stolen(&self) -> bool { self.value.borrow().is_none() } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index cb2fa6e9d74..e7d0fab3f0d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -862,9 +862,9 @@ fn print_crate_info( use rustc_target::spec::current_apple_deployment_target; if sess.target.is_like_osx { - let (major, minor) = current_apple_deployment_target(&sess.target) - .expect("unknown Apple target OS"); - println_info!("deployment_target={}", format!("{major}.{minor}")) + let (major, minor, patch) = current_apple_deployment_target(&sess.target); + let patch = if patch != 0 { format!(".{patch}") } else { String::new() }; + println_info!("deployment_target={major}.{minor}{patch}") } else { #[allow(rustc::diagnostic_outside_of_impl)] sess.dcx().fatal("only Apple targets currently support deployment version info") diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 9011d02da33..501a2417fcf 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -398,8 +398,10 @@ pub(crate) enum NamedMatch { fn token_name_eq(t1: &Token, t2: &Token) -> bool { if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) { ident1.name == ident2.name && is_raw1 == is_raw2 - } else if let (Some(ident1), Some(ident2)) = (t1.lifetime(), t2.lifetime()) { - ident1.name == ident2.name + } else if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = + (t1.lifetime(), t2.lifetime()) + { + ident1.name == ident2.name && is_raw1 == is_raw2 } else { t1.kind == t2.kind } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index b06910595bb..39489a8df1b 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -283,9 +283,9 @@ pub(super) fn transcribe<'a>( let kind = token::NtIdent(*ident, *is_raw); TokenTree::token_alone(kind, sp) } - MatchedSingle(ParseNtResult::Lifetime(ident)) => { + MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { marker.visit_span(&mut sp); - let kind = token::NtLifetime(*ident); + let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } MatchedSingle(ParseNtResult::Nt(nt)) => { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 4ff5da1a4bd..5798bcedc22 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -229,15 +229,16 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre span: ident.span, })), - Lifetime(name) => { + Lifetime(name, is_raw) => { let ident = symbol::Ident::new(name, span).without_first_quote(); trees.extend([ TokenTree::Punct(Punct { ch: b'\'', joint: true, span }), - TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }), + TokenTree::Ident(Ident { sym: ident.name, is_raw: is_raw.into(), span }), ]); } - NtLifetime(ident) => { - let stream = TokenStream::token_alone(token::Lifetime(ident.name), ident.span); + NtLifetime(ident, is_raw) => { + let stream = + TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span); trees.push(TokenTree::Group(Group { delimiter: pm::Delimiter::None, stream: Some(stream), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e2491922b8d..e86421f2150 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -793,6 +793,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), + // 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 + ), // 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!( diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index bd8b43e28e5..9fce927e2c7 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -93,7 +93,8 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) { + if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer) + { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected self type: {:?}", self_ty); @@ -132,7 +133,7 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) { + if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::InstantiateWithInfer) { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected primitive type: {:?}", ty); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index be6c3f048dc..ba01ea3f512 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -59,6 +59,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); + if let Some(sig) = node.fn_sig() + && let Some(sig_id) = sig.decl.opt_delegation_sig_id() + { + return inherit_generics_for_delegation_item(tcx, def_id, sig_id); + } + let parent_def_id = match node { Node::ImplItem(_) | Node::TraitItem(_) @@ -229,16 +235,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // inherit the generics of the item. Some(parent.to_def_id()) } - ItemKind::Fn(sig, _, _) => { - // For a delegation item inherit generics from callee. - if let Some(sig_id) = sig.decl.opt_delegation_sig_id() - && let Some(generics) = - inherit_generics_for_delegation_item(tcx, def_id, sig_id) - { - return generics; - } - None - } _ => None, }, _ => None, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a47aaf25e95..7243e85ce98 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -138,6 +138,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); + if let Some(sig) = node.fn_sig() + && let Some(sig_id) = sig.decl.opt_delegation_sig_id() + { + return inherit_predicates_for_delegation_item(tcx, def_id, sig_id); + } + let mut is_trait = None; let mut is_default_impl_trait = None; @@ -164,16 +170,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { is_trait = Some(self_bounds); } - - ItemKind::Fn(sig, _, _) => { - // For a delegation item inherit predicates from callee. - if let Some(sig_id) = sig.decl.opt_delegation_sig_id() - && let Some(predicates) = - inherit_predicates_for_delegation_item(tcx, def_id, sig_id) - { - return predicates; - } - } _ => {} } }; diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 20aaa43219f..2c9f20b7840 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -1,3 +1,7 @@ +//! Support inheriting generic parameters and predicates for function delegation. +//! +//! For more information about delegation design, see the tracking issue #118212. + use std::assert_matches::debug_assert_matches; use rustc_data_structures::fx::FxHashMap; @@ -5,7 +9,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::ErrorGuaranteed; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_type_ir::visit::TypeVisitableExt; type RemapTable = FxHashMap<u32, u32>; @@ -76,127 +80,381 @@ fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind { } } +/// Given the current context(caller and callee `FnKind`), it specifies +/// the policy of predicates and generic parameters inheritance. +#[derive(Clone, Copy, Debug, PartialEq)] +enum InheritanceKind { + /// Copying all predicates and parameters, including those of the parent + /// container. + /// + /// Boolean value defines whether the `Self` parameter or `Self: Trait` + /// predicate are copied. It's always equal to `false` except when + /// delegating from a free function to a trait method. + /// + /// FIXME(fn_delegation): This often leads to type inference + /// errors. Support providing generic arguments or restrict use sites. + WithParent(bool), + /// The trait implementation should be compatible with the original trait. + /// Therefore, for trait implementations only the method's own parameters + /// and predicates are copied. + Own, +} + +struct GenericsBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + sig_id: DefId, + parent: Option<DefId>, + inh_kind: InheritanceKind, +} + +impl<'tcx> GenericsBuilder<'tcx> { + fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> { + GenericsBuilder { tcx, sig_id, parent: None, inh_kind: InheritanceKind::WithParent(false) } + } + + fn with_parent(mut self, parent: DefId) -> Self { + self.parent = Some(parent); + self + } + + fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { + self.inh_kind = inh_kind; + self + } + + fn build(self) -> ty::Generics { + let mut own_params = vec![]; + + let sig_generics = self.tcx.generics_of(self.sig_id); + if let InheritanceKind::WithParent(has_self) = self.inh_kind + && let Some(parent_def_id) = sig_generics.parent + { + let sig_parent_generics = self.tcx.generics_of(parent_def_id); + own_params.append(&mut sig_parent_generics.own_params.clone()); + if !has_self { + own_params.remove(0); + } + } + own_params.append(&mut sig_generics.own_params.clone()); + + // Lifetime parameters must be declared before type and const parameters. + // Therefore, When delegating from a free function to a associated function, + // generic parameters need to be reordered: + // + // trait Trait<'a, A> { + // fn foo<'b, B>(...) {...} + // } + // + // reuse Trait::foo; + // desugaring: + // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { + // Trait::foo(...) + // } + own_params.sort_by_key(|key| key.kind.is_ty_or_const()); + + let param_def_id_to_index = + own_params.iter().map(|param| (param.def_id, param.index)).collect(); + + let (parent_count, has_self) = if let Some(def_id) = self.parent { + let parent_generics = self.tcx.generics_of(def_id); + let parent_kind = self.tcx.def_kind(def_id); + (parent_generics.count(), parent_kind == DefKind::Trait) + } else { + (0, false) + }; + + for (idx, param) in own_params.iter_mut().enumerate() { + param.index = (idx + parent_count) as u32; + // FIXME(fn_delegation): Default parameters are not inherited, because they are + // not permitted in functions. Therefore, there are 2 options here: + // + // - We can create non-default generic parameters. + // - We can substitute default parameters into the signature. + // + // At the moment, first option has been selected as the most general. + if let ty::GenericParamDefKind::Type { has_default, .. } + | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind + { + *has_default = false; + } + } + + ty::Generics { + parent: self.parent, + parent_count, + own_params, + param_def_id_to_index, + has_self, + has_late_bound_regions: sig_generics.has_late_bound_regions, + host_effect_index: sig_generics.host_effect_index, + } + } +} + +struct PredicatesBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + sig_id: DefId, + parent: Option<DefId>, + inh_kind: InheritanceKind, + args: ty::GenericArgsRef<'tcx>, +} + +impl<'tcx> PredicatesBuilder<'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + args: ty::GenericArgsRef<'tcx>, + sig_id: DefId, + ) -> PredicatesBuilder<'tcx> { + PredicatesBuilder { + tcx, + sig_id, + parent: None, + inh_kind: InheritanceKind::WithParent(false), + args, + } + } + + fn with_parent(mut self, parent: DefId) -> Self { + self.parent = Some(parent); + self + } + + fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { + self.inh_kind = inh_kind; + self + } + + fn build(self) -> ty::GenericPredicates<'tcx> { + struct PredicatesCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: Vec<(ty::Clause<'tcx>, Span)>, + args: ty::GenericArgsRef<'tcx>, + } + + impl<'tcx> PredicatesCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> { + PredicatesCollector { tcx, preds: vec![], args } + } + + fn with_own_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>, + def_id: DefId, + ) -> Self { + let preds = f(def_id).instantiate_own(self.tcx, self.args); + self.preds.extend(preds); + self + } + + fn with_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy, + def_id: DefId, + ) -> Self { + let preds = f(def_id); + if let Some(parent_def_id) = preds.parent { + self = self.with_own_preds(f, parent_def_id); + } + self.with_own_preds(f, def_id) + } + } + let collector = PredicatesCollector::new(self.tcx, self.args); + + // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate. + // Note: `predicates_of` query can also add inferred outlives predicates, but that + // is not the case here as `sig_id` is either a trait or a function. + let preds = match self.inh_kind { + InheritanceKind::WithParent(false) => { + collector.with_preds(|def_id| self.tcx.explicit_predicates_of(def_id), self.sig_id) + } + InheritanceKind::WithParent(true) => { + collector.with_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) + } + InheritanceKind::Own => { + collector.with_own_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) + } + } + .preds; + + ty::GenericPredicates { + parent: self.parent, + predicates: self.tcx.arena.alloc_from_iter(preds), + // FIXME(fn_delegation): Support effects. + effects_min_tys: ty::List::empty(), + } + } +} + +struct GenericArgsBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + remap_table: RemapTable, + sig_id: DefId, + def_id: LocalDefId, +} + +impl<'tcx> GenericArgsBuilder<'tcx> { + fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> { + GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id } + } + + fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> { + let caller_generics = self.tcx.generics_of(self.def_id); + let callee_generics = self.tcx.generics_of(self.sig_id); + + for caller_param in &caller_generics.own_params { + let callee_index = + callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap(); + self.remap_table.insert(callee_index, caller_param.index); + } + + let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table }; + args.fold_with(&mut folder) + } +} + fn create_generic_args<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, ) -> ty::GenericArgsRef<'tcx> { - let caller_generics = tcx.generics_of(def_id); - let callee_generics = tcx.generics_of(sig_id); + let builder = GenericArgsBuilder::new(tcx, sig_id, def_id); let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. match (caller_kind, callee_kind) { - (FnKind::Free, _) => { - // Lifetime parameters must be declared before type and const parameters. - // Therefore, When delegating from a free function to a associated function, - // generic parameters need to be reordered: - // - // trait Trait<'a, A> { - // fn foo<'b, B>(...) {...} - // } - // - // reuse Trait::foo; - // desugaring: - // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { - // Trait::foo(...) - // } - let mut remap_table = RemapTable::default(); - for caller_param in &caller_generics.own_params { - let callee_index = - callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap(); - remap_table.insert(callee_index, caller_param.index); - } - let mut folder = ParamIndexRemapper { tcx, remap_table }; - ty::GenericArgs::identity_for_item(tcx, sig_id).fold_with(&mut folder) + (FnKind::Free, FnKind::Free) + | (FnKind::Free, FnKind::AssocTrait) + | (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) + | (FnKind::AssocTrait, FnKind::AssocTrait) => { + let args = ty::GenericArgs::identity_for_item(tcx, sig_id); + builder.build_from_args(args) } - // FIXME(fn_delegation): Only `Self` param supported here. - (FnKind::AssocTraitImpl, FnKind::AssocTrait) - | (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { + + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + let callee_generics = tcx.generics_of(sig_id); + let parent = tcx.parent(def_id.into()); + let parent_args = + 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 = builder.build_from_args(method_args); + + tcx.mk_args_from_iter(parent_args.iter().chain(method_args)) + } + + (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { let parent = tcx.parent(def_id.into()); let self_ty = tcx.type_of(parent).instantiate_identity(); let generic_self_ty = ty::GenericArg::from(self_ty); - tcx.mk_args_from_iter(std::iter::once(generic_self_ty)) + + let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); + let trait_args = builder.build_from_args(trait_args); + + let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1)); + tcx.mk_args_from_iter(args) } - _ => ty::GenericArgs::identity_for_item(tcx, sig_id), + + // For trait impl's `sig_id` is always equal to the corresponding trait method. + (FnKind::AssocTraitImpl, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), } } +// FIXME(fn_delegation): Move generics inheritance to the AST->HIR lowering. +// For now, generic parameters are not propagated to the generated call, +// which leads to inference errors: +// +// fn foo<T>(x: i32) {} +// +// reuse foo as bar; +// desugaring: +// fn bar<T>() { +// foo::<_>() // ERROR: type annotations needed +// } pub(crate) fn inherit_generics_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, -) -> Option<ty::Generics> { - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. - if fn_kind(tcx, def_id.into()) != FnKind::Free { - return None; - } +) -> ty::Generics { + let builder = GenericsBuilder::new(tcx, sig_id); - let mut own_params = vec![]; - - let callee_generics = tcx.generics_of(sig_id); - if let Some(parent_sig_id) = callee_generics.parent { - let parent_sig_generics = tcx.generics_of(parent_sig_id); - own_params.append(&mut parent_sig_generics.own_params.clone()); - } - own_params.append(&mut callee_generics.own_params.clone()); + let caller_kind = fn_kind(tcx, def_id.into()); + let callee_kind = fn_kind(tcx, sig_id); + match (caller_kind, callee_kind) { + (FnKind::Free, FnKind::Free) + | (FnKind::Free, FnKind::AssocTrait) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(), + + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .with_inheritance_kind(InheritanceKind::Own) + .build() + } - // Lifetimes go first. - own_params.sort_by_key(|key| key.kind.is_ty_or_const()); + (FnKind::AssocInherentImpl, FnKind::AssocTrait) + | (FnKind::AssocTrait, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() + } - for (idx, param) in own_params.iter_mut().enumerate() { - param.index = idx as u32; - // Default parameters are not inherited: they are not allowed - // in fn's. - if let ty::GenericParamDefKind::Type { has_default, .. } - | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind - { - *has_default = false; + (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() } - } - let param_def_id_to_index = - own_params.iter().map(|param| (param.def_id, param.index)).collect(); - - Some(ty::Generics { - parent: None, - parent_count: 0, - own_params, - param_def_id_to_index, - has_self: false, - has_late_bound_regions: callee_generics.has_late_bound_regions, - host_effect_index: callee_generics.host_effect_index, - }) + // For trait impl's `sig_id` is always equal to the corresponding trait method. + (FnKind::AssocTraitImpl, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), + } } pub(crate) fn inherit_predicates_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, -) -> Option<ty::GenericPredicates<'tcx>> { - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. - if fn_kind(tcx, def_id.into()) != FnKind::Free { - return None; - } - - let callee_predicates = tcx.predicates_of(sig_id); +) -> ty::GenericPredicates<'tcx> { let args = create_generic_args(tcx, def_id, sig_id); + let builder = PredicatesBuilder::new(tcx, args, sig_id); - let mut preds = vec![]; - if let Some(parent_id) = callee_predicates.parent { - preds.extend(tcx.predicates_of(parent_id).instantiate_own(tcx, args)); - } - preds.extend(callee_predicates.instantiate_own(tcx, args)); + let caller_kind = fn_kind(tcx, def_id.into()); + let callee_kind = fn_kind(tcx, sig_id); + match (caller_kind, callee_kind) { + (FnKind::Free, FnKind::Free) + | (FnKind::Free, FnKind::AssocTrait) => { + builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build() + } + + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .with_inheritance_kind(InheritanceKind::Own) + .build() + } + + (FnKind::AssocInherentImpl, FnKind::AssocTrait) + | (FnKind::AssocTrait, FnKind::AssocTrait) + | (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() + } - Some(ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter(preds), - effects_min_tys: ty::List::empty(), - }) + // For trait impl's `sig_id` is always equal to the corresponding trait method. + (FnKind::AssocTraitImpl, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), + } } fn check_constraints<'tcx>( @@ -224,19 +482,6 @@ fn check_constraints<'tcx>( emit("recursive delegation is not supported yet"); } - if fn_kind(tcx, def_id.into()) != FnKind::Free { - let sig_generics = tcx.generics_of(sig_id); - let parent = tcx.parent(def_id.into()); - let parent_generics = tcx.generics_of(parent); - - let parent_has_self = parent_generics.has_self as usize; - let sig_has_self = sig_generics.has_self as usize; - - if sig_generics.count() > sig_has_self || parent_generics.count() > parent_has_self { - emit("early bound generics are not supported for associated delegation items"); - } - } - ret } diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 0790c6f9a59..ac5e1040803 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -63,8 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Instead, the problem is that the array-into_iter hack will no longer // apply in Rust 2021. (ARRAY_INTO_ITER, "2021") - } else if self_ty.is_box() - && self_ty.boxed_ty().is_slice() + } else if self_ty.boxed_ty().is_some_and(Ty::is_slice) && !span.at_least_rust_2024() { // In this case, it wasn't really a prelude addition that was the problem. diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 2fdba8446bd..3ba3429cbb3 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -715,7 +715,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) { - let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else { + let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer) else { bug!("unexpected incoherent type: {:?}", self_ty) }; for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter().flatten() { @@ -1485,8 +1485,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Some trait methods are excluded for boxed slices before 2024. // (`boxed_slice.into_iter()` wants a slice iterator for compatibility.) - if self_ty.is_box() - && self_ty.boxed_ty().is_slice() + if self_ty.boxed_ty().is_some_and(Ty::is_slice) && !method_name.span.at_least_rust_2024() { let trait_def = self.tcx.trait_def(poly_trait_ref.def_id()); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9ea57e4aa61..14ad5830111 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2235,8 +2235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let target_ty = self .autoderef(sugg_span, rcvr_ty) .find(|(rcvr_ty, _)| { - DeepRejectCtxt::new(self.tcx, TreatParams::ForLookup) - .types_may_unify(*rcvr_ty, impl_ty) + DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty) }) .map_or(impl_ty, |(ty, _)| ty) .peel_refs(); @@ -2498,7 +2497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .any(|info| self.associated_value(info.def_id, item_name).is_some()); let found_assoc = |ty: Ty<'tcx>| { - simplify_type(tcx, ty, TreatParams::AsCandidateKey) + simplify_type(tcx, ty, TreatParams::InstantiateWithInfer) .and_then(|simp| { tcx.incoherent_impls(simp) .into_iter() @@ -3963,7 +3962,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // cases where a positive bound implies a negative impl. (candidates, Vec::new()) } else if let Some(simp_rcvr_ty) = - simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup) + simplify_type(self.tcx, rcvr_ty, TreatParams::AsRigid) { let mut potential_candidates = Vec::new(); let mut explicitly_negative = Vec::new(); @@ -3981,7 +3980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .any(|header| { let imp = header.trait_ref.instantiate_identity(); let imp_simp = - simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup); + simplify_type(self.tcx, imp.self_ty(), TreatParams::AsRigid); imp_simp.is_some_and(|s| s == simp_rcvr_ty) }) { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 5789e60ebbe..7688a63a30a 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -39,7 +39,6 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; -use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind}; use rustc_middle::mir::FakeReadCause; use rustc_middle::traits::ObligationCauseCode; @@ -425,7 +424,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, upvar_ty, capture, - if needs_ref { Some(closure_env_region) } else { child_capture.region }, + if needs_ref { + closure_env_region + } else { + self.tcx.lifetimes.re_erased + }, ); }, ), @@ -587,7 +590,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability); - apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region) + apply_capture_kind_on_capture_ty( + self.tcx, + upvar_ty, + capture, + self.tcx.lifetimes.re_erased, + ) }) .collect() } @@ -775,13 +783,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(min_cap_list) = root_var_min_capture_list.get_mut(&var_hir_id) else { let mutability = self.determine_capture_mutability(&typeck_results, &place); - let min_cap_list = vec![ty::CapturedPlace { - var_ident, - place, - info: capture_info, - mutability, - region: None, - }]; + let min_cap_list = + vec![ty::CapturedPlace { var_ident, place, info: capture_info, mutability }]; root_var_min_capture_list.insert(var_hir_id, min_cap_list); continue; }; @@ -874,34 +877,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only need to insert when we don't have an ancestor in the existing min capture list if !ancestor_found { let mutability = self.determine_capture_mutability(&typeck_results, &place); - let captured_place = ty::CapturedPlace { - var_ident, - place, - info: updated_capture_info, - mutability, - region: None, - }; + let captured_place = + ty::CapturedPlace { var_ident, place, info: updated_capture_info, mutability }; min_cap_list.push(captured_place); } } - // For each capture that is determined to be captured by ref, add region info. - for (_, captures) in &mut root_var_min_capture_list { - for capture in captures { - match capture.info.capture_kind { - ty::UpvarCapture::ByRef(_) => { - let PlaceBase::Upvar(upvar_id) = capture.place.base else { - bug!("expected upvar") - }; - let origin = UpvarRegion(upvar_id, closure_span); - let upvar_region = self.next_region_var(origin); - capture.region = Some(upvar_region); - } - _ => (), - } - } - } - debug!( "For closure={:?}, min_captures before sorting={:?}", closure_def_id, root_var_min_capture_list @@ -1195,7 +1176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, ty, max_capture_info.capture_kind, - Some(self.tcx.lifetimes.re_erased), + self.tcx.lifetimes.re_erased, ) } }; @@ -1217,7 +1198,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, capture.place.ty(), capture.info.capture_kind, - Some(self.tcx.lifetimes.re_erased), + self.tcx.lifetimes.re_erased, ); // Checks if a capture implements any of the auto traits @@ -1935,13 +1916,11 @@ fn apply_capture_kind_on_capture_ty<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, capture_kind: UpvarCapture, - region: Option<ty::Region<'tcx>>, + region: ty::Region<'tcx>, ) -> Ty<'tcx> { match capture_kind { ty::UpvarCapture::ByValue => ty, - ty::UpvarCapture::ByRef(kind) => { - Ty::new_ref(tcx, region.unwrap(), ty, kind.to_mutbl_lossy()) - } + ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()), } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 42fed98df01..50422df8ee6 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -808,7 +808,7 @@ fn test_unstable_options_tracking_hash() { tracked!(mir_opt_level, Some(4)); tracked!(move_size_limit, Some(4096)); tracked!(mutable_noalias, false); - tracked!(next_solver, Some(NextSolverConfig { coherence: true, globally: false })); + tracked!(next_solver, NextSolverConfig { coherence: true, globally: true }); tracked!(no_generate_arange_section, true); tracked!(no_jump_tables, true); tracked!(no_link, true); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 31fdd2d7cec..60aab668cba 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -91,6 +91,15 @@ pub enum TokenKind { /// tokens. UnknownPrefix, + /// An unknown prefix in a lifetime, like `'foo#`. + /// + /// Note that like above, only the `'` and prefix are included in the token + /// and not the separator. + UnknownPrefixLifetime, + + /// `'r#lt`, which in edition < 2021 is split into several tokens: `'r # lt`. + RawLifetime, + /// Similar to the above, but *always* an error on every edition. This is used /// for emoji identifier recovery, as those are not meant to be ever accepted. InvalidPrefix, @@ -677,9 +686,17 @@ impl Cursor<'_> { return Literal { kind, suffix_start }; } + if self.first() == 'r' && self.second() == '#' && is_id_start(self.third()) { + // Eat "r" and `#`, and identifier start characters. + self.bump(); + self.bump(); + self.bump(); + self.eat_while(is_id_continue); + return RawLifetime; + } + // Either a lifetime or a character literal with // length greater than 1. - let starts_with_number = self.first().is_ascii_digit(); // Skip the literal contents. @@ -688,15 +705,17 @@ impl Cursor<'_> { self.bump(); self.eat_while(is_id_continue); - // Check if after skipping literal contents we've met a closing - // single quote (which means that user attempted to create a - // string with single quotes). - if self.first() == '\'' { - self.bump(); - let kind = Char { terminated: true }; - Literal { kind, suffix_start: self.pos_within_token() } - } else { - Lifetime { starts_with_number } + match self.first() { + // Check if after skipping literal contents we've met a closing + // single quote (which means that user attempted to create a + // string with single quotes). + '\'' => { + self.bump(); + let kind = Char { terminated: true }; + Literal { kind, suffix_start: self.pos_within_token() } + } + '#' if !starts_with_number => UnknownPrefixLifetime, + _ => Lifetime { starts_with_number }, } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 35334595833..7d4dee45c26 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -255,6 +255,7 @@ lint_duplicate_matcher_binding = duplicate matcher binding lint_elided_named_lifetime = elided lifetime has a name .label_elided = this elided lifetime gets resolved as `{$name}` .label_named = lifetime `{$name}` declared here + .suggestion = consider specifying it explicitly lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type @@ -699,11 +700,18 @@ lint_ptr_null_checks_ref = references are not nullable, so checking them for nul lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale +lint_query_untracked = `{$method}` accesses information that is not tracked by the query system + .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale + lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}` lint_range_use_inclusive_range = use an inclusive range instead +lint_raw_prefix = prefix `'r` is reserved + .label = reserved prefix + .suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + lint_reason_must_be_string_literal = reason must be a string literal lint_reason_must_come_last = reason in lint attribute must come last diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d8482567bbe..824a1868c55 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1851,9 +1851,16 @@ impl KeywordIdents { TokenTree::Token(token, _) => { if let Some((ident, token::IdentIsRaw::No)) = token.ident() { if !prev_dollar { - self.check_ident_token(cx, UnderMacro(true), ident); + self.check_ident_token(cx, UnderMacro(true), ident, ""); } - } else if *token == TokenKind::Dollar { + } else if let Some((ident, token::IdentIsRaw::No)) = token.lifetime() { + self.check_ident_token( + cx, + UnderMacro(true), + ident.without_first_quote(), + "'", + ); + } else if token.kind == TokenKind::Dollar { prev_dollar = true; continue; } @@ -1869,6 +1876,7 @@ impl KeywordIdents { cx: &EarlyContext<'_>, UnderMacro(under_macro): UnderMacro, ident: Ident, + prefix: &'static str, ) { let (lint, edition) = match ident.name { kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018), @@ -1902,7 +1910,7 @@ impl KeywordIdents { cx.emit_span_lint( lint, ident.span, - BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span }, + BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span, prefix }, ); } } @@ -1915,7 +1923,11 @@ impl EarlyLintPass for KeywordIdents { self.check_tokens(cx, &mac.args.tokens); } fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { - self.check_ident_token(cx, UnderMacro(false), ident); + if ident.name.as_str().starts_with('\'') { + self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'"); + } else { + self.check_ident_token(cx, UnderMacro(false), ident, ""); + } } } diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index fd43afa1743..fd13c418c09 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -8,13 +8,13 @@ use rustc_errors::{ elided_lifetime_in_path_suggestion, Applicability, Diag, DiagArgValue, LintDiagnostic, }; use rustc_middle::middle::stability; -use rustc_session::lint::BuiltinLintDiag; +use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution}; use rustc_session::Session; use rustc_span::symbol::kw; use rustc_span::BytePos; use tracing::debug; -use crate::lints; +use crate::lints::{self, ElidedNamedLifetime}; mod check_cfg; @@ -172,6 +172,10 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & } .decorate_lint(diag); } + BuiltinLintDiag::RawPrefix(label_span) => { + lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() } + .decorate_lint(diag); + } BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => { lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag); } @@ -442,15 +446,14 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => { lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag) } - BuiltinLintDiag::ElidedIsStatic { elided } => { - lints::ElidedNamedLifetime { elided, name: kw::StaticLifetime, named_declaration: None } - .decorate_lint(diag) - } - BuiltinLintDiag::ElidedIsParam { elided, param: (param_name, param_span) } => { - lints::ElidedNamedLifetime { - elided, - name: param_name, - named_declaration: Some(param_span), + BuiltinLintDiag::ElidedNamedLifetimes { elided: (span, kind), resolution } => { + match resolution { + ElidedLifetimeResolution::Static => { + ElidedNamedLifetime { span, kind, name: kw::StaticLifetime, declaration: None } + } + ElidedLifetimeResolution::Param(name, declaration) => { + ElidedNamedLifetime { span, kind, name, declaration: Some(declaration) } + } } .decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 2e8116b8ba8..9d637c1eb7f 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -17,8 +17,8 @@ use tracing::debug; use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword, - NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, - TykindKind, TypeIrInherentUsage, UntranslatableDiag, + NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag, TyQualified, + TykindDiag, TykindKind, TypeIrInherentUsage, UntranslatableDiag, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -88,7 +88,18 @@ declare_tool_lint! { report_in_external_macro: true } -declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]); +declare_tool_lint! { + /// The `untracked_query_information` lint detects use of methods which leak information not + /// tracked by the query system, such as whether a `Steal<T>` value has already been stolen. In + /// order not to break incremental compilation, such methods must be used very carefully or not + /// at all. + pub rustc::UNTRACKED_QUERY_INFORMATION, + Allow, + "require explicit opt-in when accessing information not tracked by the query system", + report_in_external_macro: true +} + +declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]); impl LateLintPass<'_> for QueryStability { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { @@ -102,6 +113,13 @@ impl LateLintPass<'_> for QueryStability { QueryInstability { query: cx.tcx.item_name(def_id) }, ); } + if cx.tcx.has_attr(def_id, sym::rustc_lint_untracked_query_information) { + cx.emit_span_lint( + UNTRACKED_QUERY_INFORMATION, + span, + QueryUntracked { method: cx.tcx.item_name(def_id) }, + ); + } } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index bb7de4739fb..a9627e9b789 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -610,6 +610,7 @@ fn register_internals(store: &mut LintStore) { vec![ LintId::of(DEFAULT_HASH_TYPES), LintId::of(POTENTIAL_QUERY_INSTABILITY), + LintId::of(UNTRACKED_QUERY_INFORMATION), LintId::of(USAGE_OF_TY_TYKIND), LintId::of(PASS_BY_VALUE), LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7ca282b7c85..e49b102cb39 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -9,7 +9,7 @@ use rustc_errors::{ }; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir}; +use rustc_hir::{self as hir, MissingLifetimeKind}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; @@ -363,8 +363,9 @@ pub(crate) enum BuiltinEllipsisInclusiveRangePatternsLint { pub(crate) struct BuiltinKeywordIdents { pub kw: Ident, pub next: Edition, - #[suggestion(code = "r#{kw}", applicability = "machine-applicable")] + #[suggestion(code = "{prefix}r#{kw}", applicability = "machine-applicable")] pub suggestion: Span, + pub prefix: &'static str, } #[derive(LintDiagnostic)] @@ -895,6 +896,13 @@ pub(crate) struct QueryInstability { } #[derive(LintDiagnostic)] +#[diag(lint_query_untracked)] +#[note] +pub(crate) struct QueryUntracked { + pub method: Symbol, +} + +#[derive(LintDiagnostic)] #[diag(lint_span_use_eq_ctxt)] pub(crate) struct SpanUseEqCtxtDiag; @@ -2616,14 +2624,56 @@ pub(crate) struct ElidedLifetimesInPaths { pub subdiag: ElidedLifetimeInPathSubdiag, } -#[derive(LintDiagnostic)] -#[diag(lint_elided_named_lifetime)] pub(crate) struct ElidedNamedLifetime { - #[label(lint_label_elided)] - pub elided: Span, + pub span: Span, + pub kind: MissingLifetimeKind, pub name: Symbol, - #[label(lint_label_named)] - pub named_declaration: Option<Span>, + pub declaration: Option<Span>, +} + +impl<G: EmissionGuarantee> LintDiagnostic<'_, G> for ElidedNamedLifetime { + fn decorate_lint(self, diag: &mut rustc_errors::Diag<'_, G>) { + let Self { span, kind, name, declaration } = self; + diag.primary_message(fluent::lint_elided_named_lifetime); + diag.arg("name", name); + diag.span_label(span, fluent::lint_label_elided); + if let Some(declaration) = declaration { + diag.span_label(declaration, fluent::lint_label_named); + } + // FIXME(GrigorenkoPV): this `if` and `return` should be removed, + // but currently this lint's suggestions can conflict with those of `clippy::needless_lifetimes`: + // https://github.com/rust-lang/rust/pull/129840#issuecomment-2323349119 + // HACK: `'static` suggestions will never sonflict, emit only those for now. + if name != rustc_span::symbol::kw::StaticLifetime { + return; + } + match kind { + MissingLifetimeKind::Underscore => diag.span_suggestion_verbose( + span, + fluent::lint_suggestion, + format!("{name}"), + Applicability::MachineApplicable, + ), + MissingLifetimeKind::Ampersand => diag.span_suggestion_verbose( + span.shrink_to_hi(), + fluent::lint_suggestion, + format!("{name} "), + Applicability::MachineApplicable, + ), + MissingLifetimeKind::Comma => diag.span_suggestion_verbose( + span.shrink_to_hi(), + fluent::lint_suggestion, + format!("{name}, "), + Applicability::MachineApplicable, + ), + MissingLifetimeKind::Brackets => diag.span_suggestion_verbose( + span.shrink_to_hi(), + fluent::lint_suggestion, + format!("<{name}>"), + Applicability::MachineApplicable, + ), + }; + } } #[derive(LintDiagnostic)] @@ -2766,6 +2816,15 @@ pub(crate) struct ReservedPrefix { } #[derive(LintDiagnostic)] +#[diag(lint_raw_prefix)] +pub(crate) struct RawPrefix { + #[label] + pub label: Span, + #[suggestion(code = " ", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] #[diag(lint_unused_builtin_attribute)] pub(crate) struct UnusedBuiltinAttribute { #[note] diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index bb9c7d85c2e..bb122509d0a 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -94,12 +94,9 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { fn is_ref_to_array(ty: Ty<'_>) -> bool { if let ty::Ref(_, pointee_ty, _) = *ty.kind() { pointee_ty.is_array() } else { false } } - fn is_boxed_slice(ty: Ty<'_>) -> bool { - ty.is_box() && ty.boxed_ty().is_slice() - } fn is_ref_to_boxed_slice(ty: Ty<'_>) -> bool { if let ty::Ref(_, pointee_ty, _) = *ty.kind() { - is_boxed_slice(pointee_ty) + pointee_ty.boxed_ty().is_some_and(Ty::is_slice) } else { false } @@ -119,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { .iter() .copied() .take_while(|ty| !is_ref_to_boxed_slice(*ty)) - .position(|ty| is_boxed_slice(ty)) + .position(|ty| ty.boxed_ty().is_some_and(Ty::is_slice)) { (BOXED_SLICE_INTO_ITER, "Box<[T]>", "2024", idx == 0) } else { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f2f7c0eaa4d..b5e501b92f0 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1304,8 +1304,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match *ty.kind() { ty::Adt(def, args) => { - if def.is_box() && matches!(self.mode, CItemKind::Definition) { - if ty.boxed_ty().is_sized(tcx, self.cx.param_env) { + if let Some(boxed) = ty.boxed_ty() + && matches!(self.mode, CItemKind::Definition) + { + if boxed.is_sized(tcx, self.cx.param_env) { return FfiSafe; } else { return FfiUnsafe { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 761d30bac71..b7f7b782c77 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -283,9 +283,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } match *ty.kind() { - ty::Adt(..) if ty.is_box() => { - let boxed_ty = ty.boxed_ty(); - is_ty_must_use(cx, boxed_ty, expr, span) + ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => { + is_ty_must_use(cx, boxed, expr, span) .map(|inner| MustUsePath::Boxed(Box::new(inner))) } ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6ee33041623..5c4b7e5664d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -10,7 +10,7 @@ use rustc_data_structures::stable_hasher::{ }; use rustc_error_messages::{DiagMessage, MultiSpan}; use rustc_hir::def::Namespace; -use rustc_hir::{HashStableContext, HirId}; +use rustc_hir::{HashStableContext, HirId, MissingLifetimeKind}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; @@ -556,6 +556,12 @@ pub enum DeprecatedSinceKind { InVersion(String), } +#[derive(Debug)] +pub enum ElidedLifetimeResolution { + Static, + Param(Symbol, Span), +} + // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). #[derive(Debug)] @@ -568,12 +574,9 @@ pub enum BuiltinLintDiag { }, MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), ElidedLifetimesInPaths(usize, Span, bool, Span), - ElidedIsStatic { - elided: Span, - }, - ElidedIsParam { - elided: Span, - param: (Symbol, Span), + ElidedNamedLifetimes { + elided: (Span, MissingLifetimeKind), + resolution: ElidedLifetimeResolution, }, UnknownCrateTypes { span: Span, @@ -609,6 +612,8 @@ pub enum BuiltinLintDiag { LegacyDeriveHelpers(Span), OrPatternsBackCompat(Span, String), ReservedPrefix(Span, String), + /// `'r#` in edition < 2021. + RawPrefix(Span), TrailingMacro(bool, Ident), BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c55583b39a6..83bad59825c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2033,7 +2033,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let simplified_self_ty = fast_reject::simplify_type( self.tcx, trait_ref.self_ty(), - TreatParams::AsCandidateKey, + TreatParams::InstantiateWithInfer, ); trait_impls .entry(trait_ref.def_id) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 748ca047754..22a4b688c51 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1307,6 +1307,9 @@ pub enum Rvalue<'tcx> { /// If the type of the place is an array, this is the array length. For slices (`[T]`, not /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is /// ill-formed for places of other types. + /// + /// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only + /// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing. Len(Place<'tcx>), /// Performs essentially all of the casts that can be performed via `as`. diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 8eb3c015679..809801c33e1 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -88,9 +88,6 @@ pub struct CapturedPlace<'tcx> { /// Represents if `place` can be mutated or not. pub mutability: hir::Mutability, - - /// Region of the resulting reference if the upvar is captured by ref. - pub region: Option<ty::Region<'tcx>>, } impl<'tcx> CapturedPlace<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 20828067c46..2a3008897c6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -426,7 +426,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { let simp = ty::fast_reject::simplify_type( tcx, self_ty, - ty::fast_reject::TreatParams::ForLookup, + ty::fast_reject::TreatParams::AsRigid, ) .unwrap(); consider_impls_for_simplified_type(simp); @@ -3128,11 +3128,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn next_trait_solver_globally(self) -> bool { - self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally) + self.sess.opts.unstable_opts.next_solver.globally } pub fn next_trait_solver_in_coherence(self) -> bool { - self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.coherence) + self.sess.opts.unstable_opts.next_solver.coherence } pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 91344c4e39c..2945a0be424 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -3,6 +3,14 @@ pub use rustc_type_ir::fast_reject::*; use super::TyCtxt; -pub type DeepRejectCtxt<'tcx> = rustc_type_ir::fast_reject::DeepRejectCtxt<TyCtxt<'tcx>>; +pub type DeepRejectCtxt< + 'tcx, + const INSTANTIATE_LHS_WITH_INFER: bool, + const INSTANTIATE_RHS_WITH_INFER: bool, +> = rustc_type_ir::fast_reject::DeepRejectCtxt< + TyCtxt<'tcx>, + INSTANTIATE_LHS_WITH_INFER, + INSTANTIATE_RHS_WITH_INFER, +>; pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType<DefId>; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d0a9039441d..8cec8eac189 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1075,11 +1075,13 @@ where // the raw pointer, so size and align are set to the boxed type, but `pointee.safe` // will still be `None`. if let Some(ref mut pointee) = result { - if offset.bytes() == 0 && this.ty.is_box() { + if offset.bytes() == 0 + && let Some(boxed_ty) = this.ty.boxed_ty() + { debug_assert!(pointee.safe.is_none()); let optimize = tcx.sess.opts.optimize != OptLevel::No; pointee.safe = Some(PointerKind::Box { - unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()), + unpin: optimize && boxed_ty.is_unpin(tcx, cx.param_env()), global: this.ty.is_box_global(tcx), }); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 89ef30fa768..1f4f2c62d70 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1170,14 +1170,19 @@ impl<'tcx> Ty<'tcx> { } } - /// Panics if called on any type other than `Box<T>`. - pub fn boxed_ty(self) -> Ty<'tcx> { + pub fn boxed_ty(self) -> Option<Ty<'tcx>> { match self.kind() { - Adt(def, args) if def.is_box() => args.type_at(0), - _ => bug!("`boxed_ty` is called on non-box type {:?}", self), + Adt(def, args) if def.is_box() => Some(args.type_at(0)), + _ => None, } } + /// Panics if called on any type other than `Box<T>`. + pub fn expect_boxed_ty(self) -> Ty<'tcx> { + self.boxed_ty() + .unwrap_or_else(|| bug!("`expect_boxed_ty` is called on non-box type {:?}", self)) + } + /// A scalar type is one that denotes an atomic datum, with no sub-components. /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) @@ -1323,7 +1328,7 @@ impl<'tcx> Ty<'tcx> { /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(self, explicit: bool) -> Option<Ty<'tcx>> { match *self.kind() { - Adt(def, _) if def.is_box() => Some(self.boxed_ty()), + _ if let Some(boxed) = self.boxed_ty() => Some(boxed), Ref(_, ty, _) => Some(ty), RawPtr(ty, _) if explicit => Some(ty), _ => None, diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index dfb137f738f..82690f70e5f 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -168,9 +168,9 @@ impl<'tcx> TyCtxt<'tcx> { // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on. - // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using - // `TreatParams::AsCandidateKey` while actually adding them. - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup) { + // Note that we're using `TreatParams::AsRigid` to query `non_blanket_impls` while using + // `TreatParams::InstantiateWithInfer` while actually adding them. + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsRigid) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { f(impl_def_id); @@ -190,7 +190,9 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, ) -> impl Iterator<Item = DefId> + 'tcx { let impls = self.trait_impls_of(trait_def_id); - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) { + if let Some(simp) = + fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer) + { if let Some(impls) = impls.non_blanket_impls.get(&simp) { return impls.iter().copied(); } @@ -239,7 +241,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); if let Some(simplified_self_ty) = - fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey) + fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::InstantiateWithInfer) { impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); } else { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index efbccca77c1..d70ff8258d0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1628,7 +1628,7 @@ impl<'tcx> ExplicitSelf<'tcx> { _ if is_self_ty(self_arg_ty) => ByValue, ty::Ref(region, ty, mutbl) if is_self_ty(ty) => ByReference(region, mutbl), ty::RawPtr(ty, mutbl) if is_self_ty(ty) => ByRawPointer(mutbl), - ty::Adt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox, + _ if self_arg_ty.boxed_ty().is_some_and(is_self_ty) => ByBox, _ => Other, } } diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index cf39c136b01..9e35dfed0ee 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -88,6 +88,11 @@ pub fn coroutine_by_move_body_def_id<'tcx>( ) -> DefId { let body = tcx.mir_built(coroutine_def_id).borrow(); + // If the typeck results are tainted, no need to make a by-ref body. + if body.tainted_by_errors.is_some() { + return coroutine_def_id.to_def_id(); + } + let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) = tcx.coroutine_kind(coroutine_def_id) else { @@ -98,7 +103,9 @@ pub fn coroutine_by_move_body_def_id<'tcx>( // the MIR body will be constructed well. let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; - let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; + let ty::Coroutine(_, args) = *coroutine_ty.kind() else { + bug!("tried to create by-move body of non-coroutine receiver"); + }; let args = args.as_coroutine(); let coroutine_kind = args.kind_ty().to_opt_closure_kind().unwrap(); @@ -107,7 +114,7 @@ pub fn coroutine_by_move_body_def_id<'tcx>( let ty::CoroutineClosure(_, parent_args) = *tcx.type_of(parent_def_id).instantiate_identity().kind() else { - bug!(); + bug!("coroutine's parent was not a coroutine-closure"); }; if parent_args.references_error() { return coroutine_def_id.to_def_id(); diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index fcc774503f4..b904b0d2599 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -3,7 +3,7 @@ use std::collections::VecDeque; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; -use rustc_span::Span; +use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::{debug, debug_span, instrument}; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; @@ -25,7 +25,7 @@ pub(super) fn extract_refined_covspans( // First, perform the passes that need macro information. covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); - remove_unwanted_macro_spans(&mut covspans); + remove_unwanted_expansion_spans(&mut covspans); split_visible_macro_spans(&mut covspans); // We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`. @@ -76,18 +76,24 @@ pub(super) fn extract_refined_covspans( /// invocation, which is unhelpful. Keeping only the first such span seems to /// give better mappings, so remove the others. /// +/// Similarly, `await` expands to a branch on the discriminant of `Poll`, which +/// leads to incorrect coverage if the `Future` is immediately ready (#98712). +/// /// (The input spans should be sorted in BCB dominator order, so that the /// retained "first" span is likely to dominate the others.) -fn remove_unwanted_macro_spans(covspans: &mut Vec<SpanFromMir>) { - let mut seen_macro_spans = FxHashSet::default(); +fn remove_unwanted_expansion_spans(covspans: &mut Vec<SpanFromMir>) { + let mut deduplicated_spans = FxHashSet::default(); + covspans.retain(|covspan| { - // Ignore (retain) non-macro-expansion spans. - if covspan.visible_macro.is_none() { - return true; + match covspan.expn_kind { + // Retain only the first await-related or macro-expanded covspan with this span. + Some(ExpnKind::Desugaring(kind)) if kind == DesugaringKind::Await => { + deduplicated_spans.insert(covspan.span) + } + Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span), + // Ignore (retain) other spans. + _ => true, } - - // Retain only the first macro-expanded covspan with this span. - seen_macro_spans.insert(covspan.span) }); } @@ -99,7 +105,9 @@ fn split_visible_macro_spans(covspans: &mut Vec<SpanFromMir>) { let mut extra_spans = vec![]; covspans.retain(|covspan| { - let Some(visible_macro) = covspan.visible_macro else { return true }; + let Some(ExpnKind::Macro(MacroKind::Bang, visible_macro)) = covspan.expn_kind else { + return true; + }; let split_len = visible_macro.as_str().len() as u32 + 1; let (before, after) = covspan.span.split_at(split_len); @@ -111,8 +119,8 @@ fn split_visible_macro_spans(covspans: &mut Vec<SpanFromMir>) { return true; } - extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); - extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); + extra_spans.push(SpanFromMir::new(before, covspan.expn_kind.clone(), covspan.bcb)); + extra_spans.push(SpanFromMir::new(after, covspan.expn_kind.clone(), covspan.bcb)); false // Discard the original covspan that we just split. }); diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 32bd25bf4b9..7f5765c9462 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -3,13 +3,13 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::{Span, Symbol}; +use rustc_span::{ExpnKind, Span}; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; use crate::coverage::spans::Covspan; -use crate::coverage::unexpand::unexpand_into_body_span_with_visible_macro; +use crate::coverage::unexpand::unexpand_into_body_span_with_expn_kind; use crate::coverage::ExtractedHirInfo; pub(crate) struct ExtractedCovspans { @@ -60,7 +60,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let data = &mir_body[bb]; let unexpand = move |expn_span| { - unexpand_into_body_span_with_visible_macro(expn_span, body_span) + unexpand_into_body_span_with_expn_kind(expn_span, body_span) // Discard any spans that fill the entire body, because they tend // to represent compiler-inserted code, e.g. implicitly returning `()`. .filter(|(span, _)| !span.source_equal(body_span)) @@ -68,9 +68,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let mut extract_statement_span = |statement| { let expn_span = filtered_statement_span(statement)?; - let (span, visible_macro) = unexpand(expn_span)?; + let (span, expn_kind) = unexpand(expn_span)?; - initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); Some(()) }; for statement in data.statements.iter() { @@ -79,9 +79,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let mut extract_terminator_span = |terminator| { let expn_span = filtered_terminator_span(terminator)?; - let (span, visible_macro) = unexpand(expn_span)?; + let (span, expn_kind) = unexpand(expn_span)?; - initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); Some(()) }; extract_terminator_span(data.terminator()); @@ -214,7 +214,7 @@ pub(crate) struct SpanFromMir { /// With the exception of `fn_sig_span`, this should always be contained /// within `body_span`. pub(crate) span: Span, - pub(crate) visible_macro: Option<Symbol>, + pub(crate) expn_kind: Option<ExpnKind>, pub(crate) bcb: BasicCoverageBlock, } @@ -223,12 +223,12 @@ impl SpanFromMir { Self::new(fn_sig_span, None, START_BCB) } - pub(crate) fn new(span: Span, visible_macro: Option<Symbol>, bcb: BasicCoverageBlock) -> Self { - Self { span, visible_macro, bcb } + pub(crate) fn new(span: Span, expn_kind: Option<ExpnKind>, bcb: BasicCoverageBlock) -> Self { + Self { span, expn_kind, bcb } } pub(crate) fn into_covspan(self) -> Covspan { - let Self { span, visible_macro: _, bcb } = self; + let Self { span, expn_kind: _, bcb } = self; Covspan { span, bcb } } } diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs index 8cde291b907..cb861544736 100644 --- a/compiler/rustc_mir_transform/src/coverage/unexpand.rs +++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs @@ -1,4 +1,4 @@ -use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; +use rustc_span::{ExpnKind, Span}; /// Walks through the expansion ancestors of `original_span` to find a span that /// is contained in `body_span` and has the same [syntax context] as `body_span`. @@ -13,20 +13,15 @@ pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> O /// /// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`), /// the returned symbol will be the name of that macro (e.g. `foo`). -pub(crate) fn unexpand_into_body_span_with_visible_macro( +pub(crate) fn unexpand_into_body_span_with_expn_kind( original_span: Span, body_span: Span, -) -> Option<(Span, Option<Symbol>)> { +) -> Option<(Span, Option<ExpnKind>)> { let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; - let visible_macro = prev - .map(|prev| match prev.ctxt().outer_expn_data().kind { - ExpnKind::Macro(MacroKind::Bang, name) => Some(name), - _ => None, - }) - .flatten(); + let expn_kind = prev.map(|prev| prev.ctxt().outer_expn_data().kind); - Some((span, visible_macro)) + Some((span, expn_kind)) } /// Walks through the expansion ancestors of `original_span` to find a span that diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index 5dd82f40163..66e49d556e2 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -62,11 +62,13 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { let base_ty = self.local_decls[place.local].ty; // Derefer ensures that derefs are always the first projection - if place.projection.first() == Some(&PlaceElem::Deref) && base_ty.is_box() { + if let Some(PlaceElem::Deref) = place.projection.first() + && let Some(boxed_ty) = base_ty.boxed_ty() + { let source_info = self.local_decls[place.local].source_info; let (unique_ty, nonnull_ty, ptr_ty) = - build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did); + build_ptr_tys(tcx, boxed_ty, self.unique_did, self.nonnull_did); let ptr_local = self.patch.new_temp(ptr_ty, source_info.span); @@ -120,13 +122,15 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs { for (base, elem) in place.iter_projections() { let base_ty = base.ty(&body.local_decls, tcx).ty; - if elem == PlaceElem::Deref && base_ty.is_box() { + if let PlaceElem::Deref = elem + && let Some(boxed_ty) = base_ty.boxed_ty() + { // Clone the projections before us, since now we need to mutate them. let new_projections = new_projections.get_or_insert_with(|| base.projection.to_vec()); let (unique_ty, nonnull_ty, ptr_ty) = - build_ptr_tys(tcx, base_ty.boxed_ty(), unique_did, nonnull_did); + build_ptr_tys(tcx, boxed_ty, unique_did, nonnull_did); new_projections.extend_from_slice(&build_projection( unique_ty, nonnull_ty, ptr_ty, diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 69e2592e82c..e515dfc5ea5 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1,6 +1,7 @@ //! Validates the MIR to ensure that invariants are upheld. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir as hir; use rustc_hir::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; @@ -714,7 +715,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // since we may be in the process of computing this MIR in the // first place. let layout = if def_id == self.caller_body.source.def_id() { - // FIXME: This is not right for async closures. + self.caller_body.coroutine_layout_raw() + } else if let Some(hir::CoroutineKind::Desugared( + _, + hir::CoroutineSource::Closure, + )) = self.tcx.coroutine_kind(def_id) + && let ty::ClosureKind::FnOnce = + args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() + && self.caller_body.source.def_id() + == self.tcx.coroutine_by_move_body_def_id(def_id) + { + // Same if this is the by-move body of a coroutine-closure. self.caller_body.coroutine_layout_raw() } else { self.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8515ab45de2..093697a290c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1041,8 +1041,11 @@ fn find_vtable_types_for_unsizing<'tcx>( match (source_ty.kind(), target_ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b), - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) + (_, _) + if let Some(source_boxed) = source_ty.boxed_ty() + && let Some(target_boxed) = target_ty.boxed_ty() => + { + ptr_vtable(source_boxed, target_boxed) } // T as dyn* Trait diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b22e8e30465..91101ddd590 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,7 @@ // tidy-alphabetical-start #![feature(array_windows)] +#![feature(if_let_guard)] +#![feature(let_chains)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c7a9846cd97..17b6ec7e2bb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -3,7 +3,7 @@ mod inherent; mod opaque_types; mod weak_types; -use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _}; @@ -106,6 +106,12 @@ where if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { let cx = ecx.cx(); + if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.alias.args, + projection_pred.skip_binder().projection_term.args, + ) { + return Err(NoSolution); + } ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -144,7 +150,7 @@ where let goal_trait_ref = goal.predicate.alias.trait_ref(cx); let impl_trait_ref = cx.impl_trait_ref(impl_def_id); - if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup).args_may_unify( + if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()).args_may_unify( goal.predicate.alias.trait_ref(cx).args, impl_trait_ref.skip_binder().args, ) { diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 67b001d0cce..683d8dab3b2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -2,7 +2,7 @@ use rustc_ast_ir::Movability; use rustc_type_ir::data_structures::IndexSet; -use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; @@ -47,7 +47,7 @@ where let cx = ecx.cx(); let impl_trait_ref = cx.impl_trait_ref(impl_def_id); - if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup) + if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()) .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) { return Err(NoSolution); @@ -124,6 +124,13 @@ where if trait_clause.def_id() == goal.predicate.def_id() && trait_clause.polarity() == goal.predicate.polarity { + if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + trait_clause.skip_binder().trait_ref.args, + ) { + return Err(NoSolution); + } + ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); ecx.eq( diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 8e8d91ce4d0..ec9a676ea31 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -381,6 +381,7 @@ parse_invalid_char_in_escape_msg = invalid character in {$is_hex -> *[false] unicode } escape + parse_invalid_comparison_operator = invalid comparison operator `{$invalid}` .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` @@ -581,6 +582,11 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl .suggestion_add_trait = add a trait here .suggestion_remove_for = for an inherent impl, drop this `for` +parse_misspelled_kw = {$is_incorrect_case -> + [true] write keyword `{$similar_kw}` in lowercase + *[false] there is a keyword `{$similar_kw}` with a similar name +} + parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds .suggestion = remove the `{$modifier}` diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f30939093c2..b7232ff21ca 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -13,7 +13,6 @@ use rustc_session::lint::builtin::{ }; use rustc_session::lint::BuiltinLintDiag; use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use tracing::debug; @@ -188,9 +187,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { preceded_by_whitespace = true; continue; } - rustc_lexer::TokenKind::Ident => { - self.ident(start) - } + rustc_lexer::TokenKind::Ident => self.ident(start), rustc_lexer::TokenKind::RawIdent => { let sym = nfc_normalize(self.str_from(start + BytePos(2))); let span = self.mk_sp(start, self.pos); @@ -205,20 +202,31 @@ impl<'psess, 'src> StringReader<'psess, 'src> { self.report_unknown_prefix(start); self.ident(start) } - rustc_lexer::TokenKind::InvalidIdent - | rustc_lexer::TokenKind::InvalidPrefix + rustc_lexer::TokenKind::UnknownPrefixLifetime => { + self.report_unknown_prefix(start); + // Include the leading `'` in the real identifier, for macro + // expansion purposes. See #12512 for the gory details of why + // this is necessary. + let lifetime_name = self.str_from(start); + self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); + let ident = Symbol::intern(lifetime_name); + token::Lifetime(ident, IdentIsRaw::No) + } + rustc_lexer::TokenKind::InvalidIdent | rustc_lexer::TokenKind::InvalidPrefix // Do not recover an identifier with emoji if the codepoint is a confusable // with a recoverable substitution token, like `➖`. - if !UNICODE_ARRAY - .iter() - .any(|&(c, _, _)| { - let sym = self.str_from(start); - sym.chars().count() == 1 && c == sym.chars().next().unwrap() - }) => + if !UNICODE_ARRAY.iter().any(|&(c, _, _)| { + let sym = self.str_from(start); + sym.chars().count() == 1 && c == sym.chars().next().unwrap() + }) => { let sym = nfc_normalize(self.str_from(start)); let span = self.mk_sp(start, self.pos); - self.psess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default() + self.psess + .bad_unicode_identifiers + .borrow_mut() + .entry(sym) + .or_default() .push(span); token::Ident(sym, IdentIsRaw::No) } @@ -249,9 +257,9 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let suffix = if suffix_start < self.pos { let string = self.str_from(suffix_start); if string == "_" { - self - .dcx() - .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) }); + self.dcx().emit_err(errors::UnderscoreLiteralSuffix { + span: self.mk_sp(suffix_start, self.pos), + }); None } else { Some(Symbol::intern(string)) @@ -269,12 +277,47 @@ impl<'psess, 'src> StringReader<'psess, 'src> { self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); if starts_with_number { let span = self.mk_sp(start, self.pos); - self.dcx().struct_err("lifetimes cannot start with a number") + self.dcx() + .struct_err("lifetimes cannot start with a number") .with_span(span) .stash(span, StashKey::LifetimeIsChar); } let ident = Symbol::intern(lifetime_name); - token::Lifetime(ident) + token::Lifetime(ident, IdentIsRaw::No) + } + rustc_lexer::TokenKind::RawLifetime => { + self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); + + let ident_start = start + BytePos(3); + let prefix_span = self.mk_sp(start, ident_start); + + if prefix_span.at_least_rust_2021() { + let lifetime_name_without_tick = self.str_from(ident_start); + // Put the `'` back onto the lifetime name. + let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1); + lifetime_name.push('\''); + lifetime_name += lifetime_name_without_tick; + let sym = Symbol::intern(&lifetime_name); + + token::Lifetime(sym, IdentIsRaw::Yes) + } else { + // Otherwise, this should be parsed like `'r`. Warn about it though. + self.psess.buffer_lint( + RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, + prefix_span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::RawPrefix(prefix_span), + ); + + // Reset the state so we just lex the `'r`. + let lt_start = start + BytePos(2); + self.pos = lt_start; + self.cursor = Cursor::new(&str_before[2 as usize..]); + + let lifetime_name = self.str_from(start); + let ident = Symbol::intern(lifetime_name); + token::Lifetime(ident, IdentIsRaw::No) + } } rustc_lexer::TokenKind::Semi => token::Semi, rustc_lexer::TokenKind::Comma => token::Comma, @@ -331,16 +374,19 @@ impl<'psess, 'src> StringReader<'psess, 'src> { // first remove compound tokens like `<<` from `rustc_lexer`, and then add // fancier error recovery to it, as there will be less overall work to do this // way. - let (token, sugg) = unicode_chars::check_for_substitution(self, start, c, repeats+1); + let (token, sugg) = + unicode_chars::check_for_substitution(self, start, c, repeats + 1); self.dcx().emit_err(errors::UnknownTokenStart { span: self.mk_sp(start, self.pos + Pos::from_usize(repeats * c.len_utf8())), escaped: escaped_char(c), sugg, - null: if c == '\x00' {Some(errors::UnknownTokenNull)} else {None}, + null: if c == '\x00' { Some(errors::UnknownTokenNull) } else { None }, repeat: if repeats > 0 { swallow_next_invalid = repeats; Some(errors::UnknownTokenRepeat { repeats }) - } else {None} + } else { + None + }, }); if let Some(token) = token { @@ -699,7 +745,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let expn_data = prefix_span.ctxt().outer_expn_data(); - if expn_data.edition >= Edition::Edition2021 { + if expn_data.edition.at_least_rust_2021() { // In Rust 2021, this is a hard error. let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index fcdc10c0837..f6f66821df7 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -19,8 +19,9 @@ use rustc_errors::{ Subdiagnostic, }; use rustc_session::errors::ExprParenthesesNeeded; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{kw, sym, AllKeywords, Ident}; use rustc_span::{BytePos, Span, SpanSnippetError, Symbol, DUMMY_SP}; use thin_vec::{thin_vec, ThinVec}; use tracing::{debug, trace}; @@ -203,6 +204,37 @@ impl std::fmt::Display for UnaryFixity { } } +#[derive(Debug, rustc_macros::Subdiagnostic)] +#[suggestion( + parse_misspelled_kw, + applicability = "machine-applicable", + code = "{similar_kw}", + style = "verbose" +)] +struct MisspelledKw { + similar_kw: String, + #[primary_span] + span: Span, + is_incorrect_case: bool, +} + +/// Checks if the given `lookup` identifier is similar to any keyword symbol in `candidates`. +fn find_similar_kw(lookup: Ident, candidates: &[Symbol]) -> Option<MisspelledKw> { + let lowercase = lookup.name.as_str().to_lowercase(); + let lowercase_sym = Symbol::intern(&lowercase); + if candidates.contains(&lowercase_sym) { + Some(MisspelledKw { similar_kw: lowercase, span: lookup.span, is_incorrect_case: true }) + } else if let Some(similar_sym) = find_best_match_for_name(candidates, lookup.name, None) { + Some(MisspelledKw { + similar_kw: similar_sym.to_string(), + span: lookup.span, + is_incorrect_case: false, + }) + } else { + None + } +} + struct MultiSugg { msg: String, patches: Vec<(Span, String)>, @@ -638,9 +670,9 @@ impl<'a> Parser<'a> { let concat = Symbol::intern(&format!("{prev}{cur}")); let ident = Ident::new(concat, DUMMY_SP); if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { - let span = self.prev_token.span.to(self.token.span); + let concat_span = self.prev_token.span.to(self.token.span); err.span_suggestion_verbose( - span, + concat_span, format!("consider removing the space to spell keyword `{concat}`"), concat, Applicability::MachineApplicable, @@ -741,9 +773,55 @@ impl<'a> Parser<'a> { err.span_label(sp, label_exp); err.span_label(self.token.span, "unexpected token"); } + + // Check for misspelled keywords if there are no suggestions added to the diagnostic. + if err.suggestions.as_ref().is_ok_and(|code_suggestions| code_suggestions.is_empty()) { + self.check_for_misspelled_kw(&mut err, &expected); + } Err(err) } + /// Checks if the current token or the previous token are misspelled keywords + /// and adds a helpful suggestion. + fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) { + let Some((curr_ident, _)) = self.token.ident() else { + return; + }; + let expected_tokens: &[TokenType] = + expected.len().checked_sub(10).map_or(&expected, |index| &expected[index..]); + let expected_keywords: Vec<Symbol> = expected_tokens + .iter() + .filter_map(|token| if let TokenType::Keyword(kw) = token { Some(*kw) } else { None }) + .collect(); + + // When there are a few keywords in the last ten elements of `self.expected_tokens` and the current + // token is an identifier, it's probably a misspelled keyword. + // This handles code like `async Move {}`, misspelled `if` in match guard, misspelled `else` in `if`-`else` + // and mispelled `where` in a where clause. + if !expected_keywords.is_empty() + && !curr_ident.is_used_keyword() + && let Some(misspelled_kw) = find_similar_kw(curr_ident, &expected_keywords) + { + err.subdiagnostic(misspelled_kw); + } else if let Some((prev_ident, _)) = self.prev_token.ident() + && !prev_ident.is_used_keyword() + { + // We generate a list of all keywords at runtime rather than at compile time + // so that it gets generated only when the diagnostic needs it. + // Also, it is unlikely that this list is generated multiple times because the + // parser halts after execution hits this path. + let all_keywords = AllKeywords::new().collect_used(|| prev_ident.span.edition()); + + // Otherwise, check the previous token with all the keywords as possible candidates. + // This handles code like `Struct Human;` and `While a < b {}`. + // We check the previous token only when the current token is an identifier to avoid false + // positives like suggesting keyword `for` for `extern crate foo {}`. + if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) { + err.subdiagnostic(misspelled_kw); + } + } + } + /// The user has written `#[attr] expr` which is unsupported. (#106020) pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed { // Missing semicolon typo error. @@ -846,6 +924,7 @@ impl<'a> Parser<'a> { ); } } + err.emit() } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 84684e808d9..ecc4cd96faf 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2050,7 +2050,7 @@ impl<'a> Parser<'a> { }; // On an error path, eagerly consider a lifetime to be an unclosed character lit, if that // makes sense. - if let Some(ident) = self.token.lifetime() + if let Some((ident, IdentIsRaw::No)) = self.token.lifetime() && could_be_unclosed_char_literal(ident) { let lt = self.expect_lifetime(); @@ -2925,9 +2925,9 @@ impl<'a> Parser<'a> { } pub(crate) fn eat_label(&mut self) -> Option<Label> { - if let Some(ident) = self.token.lifetime() { + if let Some((ident, is_raw)) = self.token.lifetime() { // Disallow `'fn`, but with a better error message than `expect_lifetime`. - if ident.without_first_quote().is_reserved() { + if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved() { self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 61e3fa2e6c5..b90c41d9163 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1666,7 +1666,7 @@ enum FlatToken { pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), - Lifetime(Ident), + Lifetime(Ident, IdentIsRaw), /// This case will eventually be removed, along with `Token::Interpolate`. Nt(Lrc<Nonterminal>), diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index e66d0df012b..44b169c881e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -88,7 +88,7 @@ impl<'a> Parser<'a> { }, NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind), NonterminalKind::Lifetime => match &token.kind { - token::Lifetime(_) | token::NtLifetime(..) => true, + token::Lifetime(..) | token::NtLifetime(..) => true, _ => false, }, NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => { @@ -171,9 +171,9 @@ impl<'a> Parser<'a> { NonterminalKind::Lifetime => { // We want to keep `'keyword` parsing, just like `keyword` is still // an ident for nonterminal purposes. - return if let Some(ident) = self.token.lifetime() { + return if let Some((ident, is_raw)) = self.token.lifetime() { self.bump(); - Ok(ParseNtResult::Lifetime(ident)) + Ok(ParseNtResult::Lifetime(ident, is_raw)) } else { Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime { span: self.token.span, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index f87b5649654..cbd35ffdfa9 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,6 +1,6 @@ use rustc_ast::mut_visit::{walk_pat, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, Delimiter, Token}; +use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token}; use rustc_ast::{ self as ast, AttrVec, BindingMode, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, @@ -548,7 +548,7 @@ impl<'a> Parser<'a> { None => PatKind::Path(qself, path), } } - } else if let Some(lt) = self.token.lifetime() + } else if let Some((lt, IdentIsRaw::No)) = self.token.lifetime() // In pattern position, we're totally fine with using "next token isn't colon" // as a heuristic. We could probably just always try to recover if it's a lifetime, // because we never have `'a: label {}` in a pattern position anyways, but it does @@ -689,7 +689,7 @@ impl<'a> Parser<'a> { /// Parse `&pat` / `&mut pat`. fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> { self.expect_and()?; - if let Some(lifetime) = self.token.lifetime() { + if let Some((lifetime, _)) = self.token.lifetime() { self.bump(); // `'a` self.dcx().emit_err(UnexpectedLifetimeInPattern { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 52f0b1c1b04..dd1cc75c7ff 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,5 +1,5 @@ use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, @@ -1285,8 +1285,9 @@ impl<'a> Parser<'a> { /// Parses a single lifetime `'a` or panics. pub(super) fn expect_lifetime(&mut self) -> Lifetime { - if let Some(ident) = self.token.lifetime() { - if ident.without_first_quote().is_reserved() + if let Some((ident, is_raw)) = self.token.lifetime() { + if matches!(is_raw, IdentIsRaw::No) + && ident.without_first_quote().is_reserved() && ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name) { self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 21478a44b0e..e41f89a3c9d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -125,7 +125,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), [sym::coverage, ..] => self.check_coverage(attr, span, target), [sym::optimize, ..] => self.check_optimize(hir_id, attr, target), - [sym::no_sanitize, ..] => self.check_no_sanitize(hir_id, attr, span, target), + [sym::no_sanitize, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target), [sym::marker, ..] => self.check_marker(hir_id, attr, span, target), [sym::target_feature, ..] => { @@ -166,10 +168,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) } [sym::rustc_lint_query_instability, ..] => { - self.check_rustc_lint_query_instability(hir_id, attr, span, target) + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_lint_untracked_query_information, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) } [sym::rustc_lint_diagnostics, ..] => { - self.check_rustc_lint_diagnostics(hir_id, attr, span, target) + self.check_applied_to_fn_or_method(hir_id, attr, span, target) } [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target), [sym::rustc_lint_opt_deny_field_access, ..] => { @@ -452,11 +457,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks that `#[no_sanitize(..)]` is applied to a function or method. - fn check_no_sanitize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - fn check_generic_attr( &self, hir_id: HirId, @@ -1635,30 +1635,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks that the `#[rustc_lint_query_instability]` attribute is only applied to a function - /// or method. - fn check_rustc_lint_query_instability( - &self, - hir_id: HirId, - attr: &Attribute, - span: Span, - target: Target, - ) { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - - /// Checks that the `#[rustc_lint_diagnostics]` attribute is only applied to a function or - /// method. - fn check_rustc_lint_diagnostics( - &self, - hir_id: HirId, - attr: &Attribute, - span: Span, - target: Target, - ) { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct. fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) { match target { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 79c42456cf8..917cb81aa51 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2062,7 +2062,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { lint::builtin::ELIDED_NAMED_LIFETIMES, missing.id_for_lint, missing.span, - BuiltinLintDiag::ElidedIsStatic { elided: missing.span }, + BuiltinLintDiag::ElidedNamedLifetimes { + elided: (missing.span, missing.kind), + resolution: lint::ElidedLifetimeResolution::Static, + }, ); } } @@ -2072,9 +2075,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { lint::builtin::ELIDED_NAMED_LIFETIMES, missing.id_for_lint, missing.span, - BuiltinLintDiag::ElidedIsParam { - elided: missing.span, - param: (tcx.item_name(param.into()), tcx.source_span(param)), + BuiltinLintDiag::ElidedNamedLifetimes { + elided: (missing.span, missing.kind), + resolution: lint::ElidedLifetimeResolution::Param( + tcx.item_name(param.into()), + tcx.source_span(param), + ), }, ); } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 908d50a041e..f3e3b36111c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -842,6 +842,11 @@ pub struct NextSolverConfig { /// This is only `true` if `coherence` is also enabled. pub globally: bool, } +impl Default for NextSolverConfig { + fn default() -> Self { + NextSolverConfig { coherence: true, globally: false } + } +} #[derive(Clone)] pub enum Input { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 45339c23ea3..a57dc80b316 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -403,7 +403,7 @@ mod desc { pub(crate) const parse_unpretty: &str = "`string` or `string=string`"; pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; pub(crate) const parse_next_solver_config: &str = - "a comma separated list of solver configurations: `globally` (default), and `coherence`"; + "either `globally` (when used without an argument), `coherence` (default) or `no`"; pub(crate) const parse_lto: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted"; pub(crate) const parse_linker_plugin_lto: &str = @@ -1105,27 +1105,16 @@ mod parse { } } - pub(crate) fn parse_next_solver_config( - slot: &mut Option<NextSolverConfig>, - v: Option<&str>, - ) -> bool { + pub(crate) fn parse_next_solver_config(slot: &mut NextSolverConfig, v: Option<&str>) -> bool { if let Some(config) = v { - let mut coherence = false; - let mut globally = true; - for c in config.split(',') { - match c { - "globally" => globally = true, - "coherence" => { - globally = false; - coherence = true; - } - _ => return false, - } - } - - *slot = Some(NextSolverConfig { coherence: coherence || globally, globally }); + *slot = match config { + "no" => NextSolverConfig { coherence: false, globally: false }, + "coherence" => NextSolverConfig { coherence: true, globally: false }, + "globally" => NextSolverConfig { coherence: true, globally: true }, + _ => return false, + }; } else { - *slot = Some(NextSolverConfig { coherence: true, globally: true }); + *slot = NextSolverConfig { coherence: true, globally: true }; } true @@ -1878,7 +1867,7 @@ options! { "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes)"), - next_solver: Option<NextSolverConfig> = (None, parse_next_solver_config, [TRACKED], + next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED], "enable and configure the next generation trait solver used by rustc"), nll_facts: bool = (false, parse_bool, [UNTRACKED], "dump facts from NLL analysis into side files (default: no)"), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 36b31d10c4d..7572d57309c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -20,7 +20,8 @@ mod tests; // The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`. symbols! { - // If you modify this list, adjust `is_special` and `is_used_keyword`/`is_unused_keyword`. + // If you modify this list, adjust `is_special`, `is_used_keyword`/`is_unused_keyword` + // and `AllKeywords`. // But this should rarely be necessary if the keywords are kept in alphabetic order. Keywords { // Special reserved identifiers used internally for elided lifetimes, @@ -1654,6 +1655,7 @@ symbols! { rustc_lint_opt_deny_field_access, rustc_lint_opt_ty, rustc_lint_query_instability, + rustc_lint_untracked_query_information, rustc_macro_transparency, rustc_main, rustc_mir, @@ -2578,3 +2580,42 @@ impl Ident { self.name.can_be_raw() && self.is_reserved() } } + +/// An iterator over all the keywords in Rust. +#[derive(Copy, Clone)] +pub struct AllKeywords { + curr_idx: u32, + end_idx: u32, +} + +impl AllKeywords { + /// Initialize a new iterator over all the keywords. + /// + /// *Note:* Please update this if a new keyword is added beyond the current + /// range. + pub fn new() -> Self { + AllKeywords { curr_idx: kw::Empty.as_u32(), end_idx: kw::Yeet.as_u32() } + } + + /// Collect all the keywords in a given edition into a vector. + pub fn collect_used(&self, edition: impl Copy + FnOnce() -> Edition) -> Vec<Symbol> { + self.filter(|&keyword| { + keyword.is_used_keyword_always() || keyword.is_used_keyword_conditional(edition) + }) + .collect() + } +} + +impl Iterator for AllKeywords { + type Item = Symbol; + + fn next(&mut self) -> Option<Self::Item> { + if self.curr_idx <= self.end_idx { + let keyword = Symbol::new(self.curr_idx); + self.curr_idx += 1; + Some(keyword) + } else { + None + } + } +} diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index b752a344395..b1fe49f76ca 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::env; +use std::num::ParseIntError; use crate::spec::{ add_link_args, add_link_args_iter, cvs, Cc, DebuginfoKind, FramePointer, LinkArgs, @@ -39,6 +40,25 @@ impl Arch { } } + /// The architecture name to forward to the linker. + fn ld_arch(self) -> &'static str { + // Supported architecture names can be found in the source: + // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 + match self { + Armv7k => "armv7k", + Armv7s => "armv7s", + Arm64 => "arm64", + Arm64e => "arm64e", + Arm64_32 => "arm64_32", + // ld64 doesn't understand i686, so fall back to i386 instead + // + // Same story when linking with cc, since that ends up invoking ld64. + I386 | I686 => "i386", + X86_64 => "x86_64", + X86_64h => "x86_64h", + } + } + pub(crate) fn target_arch(self) -> Cow<'static, str> { Cow::Borrowed(match self { Armv7k | Armv7s => "arm", @@ -97,53 +117,85 @@ impl TargetAbi { } fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { + // From the man page for ld64 (`man ld`): + // > The linker accepts universal (multiple-architecture) input files, + // > but always creates a "thin" (single-architecture), standard Mach-O + // > output file. The architecture for the output file is specified using + // > the -arch option. + // + // The linker has heuristics to determine the desired architecture, but to + // be safe, and to avoid a warning, we set the architecture explicitly. + let mut args = + TargetOptions::link_args(LinkerFlavor::Darwin(Cc::No, Lld::No), &["-arch", arch.ld_arch()]); + + // From the man page for ld64 (`man ld`): + // > This is set to indicate the platform, oldest supported version of + // > that platform that output is to be used on, and the SDK that the + // > output was built against. platform [...] may be one of the following + // > strings: + // > - macos + // > - ios + // > - tvos + // > - watchos + // > - bridgeos + // > - visionos + // > - xros + // > - mac-catalyst + // > - ios-simulator + // > - tvos-simulator + // > - watchos-simulator + // > - visionos-simulator + // > - xros-simulator + // > - driverkit + // + // Like with `-arch`, the linker can figure out the platform versions + // itself from the binaries being linked, but to be safe, we specify the + // desired versions here explicitly. let platform_name: StaticCow<str> = match abi { TargetAbi::Normal => os.into(), TargetAbi::Simulator => format!("{os}-simulator").into(), TargetAbi::MacCatalyst => "mac-catalyst".into(), }; - let min_version: StaticCow<str> = { - let (major, minor) = match os { - "ios" => ios_deployment_target(arch, abi.target_abi()), - "tvos" => tvos_deployment_target(), - "watchos" => watchos_deployment_target(), - "visionos" => visionos_deployment_target(), - "macos" => macos_deployment_target(arch), - _ => unreachable!(), - }; - format!("{major}.{minor}").into() + let (major, minor, patch) = deployment_target(os, arch, abi); + format!("{major}.{minor}.{patch}").into() }; + // Lie about the SDK version, we don't know it here let sdk_version = min_version.clone(); - - let mut args = TargetOptions::link_args( - LinkerFlavor::Darwin(Cc::No, Lld::No), - &["-arch", arch.target_name(), "-platform_version"], - ); add_link_args_iter( &mut args, LinkerFlavor::Darwin(Cc::No, Lld::No), - [platform_name, min_version, sdk_version].into_iter(), + ["-platform_version".into(), platform_name, min_version, sdk_version].into_iter(), ); + if abi != TargetAbi::MacCatalyst { + // CC forwards the `-arch` to the linker, so we use the same value + // here intentionally. add_link_args( &mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), - &["-arch", arch.target_name()], + &["-arch", arch.ld_arch()], ); } else { add_link_args_iter( &mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), - ["-target".into(), mac_catalyst_llvm_target(arch).into()].into_iter(), + ["-target".into(), llvm_target(os, arch, abi)].into_iter(), ); } args } -pub(crate) fn opts(os: &'static str, arch: Arch, abi: TargetAbi) -> TargetOptions { - TargetOptions { +/// Get the base target options, LLVM target and `target_arch` from the three +/// things that uniquely identify Rust's Apple targets: The OS, the +/// architecture, and the ABI. +pub(crate) fn base( + os: &'static str, + arch: Arch, + abi: TargetAbi, +) -> (TargetOptions, StaticCow<str>, StaticCow<str>) { + let opts = TargetOptions { abi: abi.target_abi().into(), os: os.into(), cpu: arch.target_cpu(abi).into(), @@ -193,10 +245,11 @@ pub(crate) fn opts(os: &'static str, arch: Arch, abi: TargetAbi) -> TargetOption link_env: Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"), Cow::Borrowed("1"))]), ..Default::default() - } + }; + (opts, llvm_target(os, arch, abi), arch.target_arch()) } -pub fn sdk_version(platform: u32) -> Option<(u32, u32)> { +pub fn sdk_version(platform: u32) -> Option<(u16, u8)> { // NOTE: These values are from an arbitrary point in time but shouldn't make it into the final // binary since the final link command will have the current SDK version passed to it. match platform { @@ -230,58 +283,108 @@ pub fn platform(target: &Target) -> Option<u32> { }) } -pub fn deployment_target(target: &Target) -> Option<(u32, u32)> { - let (major, minor) = match &*target.os { - "macos" => { - // This does not need to be specific. It just needs to handle x86 vs M1. - let arch = match target.arch.as_ref() { - "x86" | "x86_64" => X86_64, - "arm64e" => Arm64e, - _ => Arm64, - }; - macos_deployment_target(arch) - } - "ios" => { - let arch = match target.arch.as_ref() { - "arm64e" => Arm64e, - _ => Arm64, - }; - ios_deployment_target(arch, &target.abi) - } - "watchos" => watchos_deployment_target(), - "tvos" => tvos_deployment_target(), - "visionos" => visionos_deployment_target(), - _ => return None, +/// Hack for calling `deployment_target` outside of this module. +pub fn deployment_target_for_target(target: &Target) -> (u16, u8, u8) { + let arch = if target.llvm_target.starts_with("arm64e") { + Arch::Arm64e + } else if target.arch == "aarch64" { + Arch::Arm64 + } else { + // Dummy architecture, only used by `deployment_target` anyhow + Arch::X86_64 }; - - Some((major, minor)) + let abi = match &*target.abi { + "macabi" => TargetAbi::MacCatalyst, + "sim" => TargetAbi::Simulator, + "" => TargetAbi::Normal, + abi => unreachable!("invalid abi '{abi}' for Apple target"), + }; + deployment_target(&target.os, arch, abi) } -fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> { - let deployment_target = env::var(var_name).ok()?; - let (unparsed_major, unparsed_minor) = deployment_target.split_once('.')?; - let (major, minor) = (unparsed_major.parse().ok()?, unparsed_minor.parse().ok()?); +/// Get the deployment target based on the standard environment variables, or +/// fall back to a sane default. +fn deployment_target(os: &str, arch: Arch, abi: TargetAbi) -> (u16, u8, u8) { + // When bumping a version in here, remember to update the platform-support + // docs too. + // + // NOTE: If you are looking for the default deployment target, prefer + // `rustc --print deployment-target`, as the default here may change in + // future `rustc` versions. + + // Minimum operating system versions currently supported by `rustc`. + let os_min = match os { + "macos" => (10, 12, 0), + "ios" => (10, 0, 0), + "tvos" => (10, 0, 0), + "watchos" => (5, 0, 0), + "visionos" => (1, 0, 0), + _ => unreachable!("tried to get deployment target for non-Apple platform"), + }; - Some((major, minor)) -} + // On certain targets it makes sense to raise the minimum OS version. + let min = match (os, arch, abi) { + // Use 11.0 on Aarch64 as that's the earliest version with M1 support. + ("macos", Arch::Arm64 | Arch::Arm64e, _) => (11, 0, 0), + ("ios", Arch::Arm64e, _) => (14, 0, 0), + // Mac Catalyst defaults to 13.1 in Clang. + ("ios", _, TargetAbi::MacCatalyst) => (13, 1, 0), + _ => os_min, + }; -fn macos_default_deployment_target(arch: Arch) -> (u32, u32) { - match arch { - Arm64 | Arm64e => (11, 0), - _ => (10, 12), - } -} + // The environment variable used to fetch the deployment target. + let env_var = match os { + "macos" => "MACOSX_DEPLOYMENT_TARGET", + "ios" => "IPHONEOS_DEPLOYMENT_TARGET", + "watchos" => "WATCHOS_DEPLOYMENT_TARGET", + "tvos" => "TVOS_DEPLOYMENT_TARGET", + "visionos" => "XROS_DEPLOYMENT_TARGET", + _ => unreachable!("tried to get deployment target env var for non-Apple platform"), + }; -fn macos_deployment_target(arch: Arch) -> (u32, u32) { - // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. - // Note: If bumping this version, remember to update it in the rustc/platform-support docs. - from_set_deployment_target("MACOSX_DEPLOYMENT_TARGET") - .unwrap_or_else(|| macos_default_deployment_target(arch)) + if let Ok(deployment_target) = env::var(env_var) { + match parse_version(&deployment_target) { + // It is common that the deployment target is set too low, e.g. on + // macOS Aarch64 to also target older x86_64, the user may set a + // lower deployment target than supported. + // + // To avoid such issues, we silently raise the deployment target + // here. + // FIXME: We want to show a warning when `version < os_min`. + Ok(version) => version.max(min), + // FIXME: Report erroneous environment variable to user. + Err(_) => min, + } + } else { + min + } } -pub(crate) fn macos_llvm_target(arch: Arch) -> String { - let (major, minor) = macos_deployment_target(arch); - format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor) +/// Generate the target triple that we need to pass to LLVM and/or Clang. +fn llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<str> { + // The target triple depends on the deployment target, and is required to + // enable features such as cross-language LTO, and for picking the right + // Mach-O commands. + // + // Certain optimizations also depend on the deployment target. + let (major, minor, patch) = deployment_target(os, arch, abi); + let arch = arch.target_name(); + // Convert to the "canonical" OS name used by LLVM: + // https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L236-L282 + let os = match os { + "macos" => "macosx", + "ios" => "ios", + "watchos" => "watchos", + "tvos" => "tvos", + "visionos" => "xros", + _ => unreachable!("tried to get LLVM target OS for non-Apple platform"), + }; + let environment = match abi { + TargetAbi::Normal => "", + TargetAbi::MacCatalyst => "-macabi", + TargetAbi::Simulator => "-simulator", + }; + format!("{arch}-apple-{os}{major}.{minor}.{patch}{environment}").into() } fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> { @@ -321,83 +424,19 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> { } } -fn ios_deployment_target(arch: Arch, abi: &str) -> (u32, u32) { - // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. - // Note: If bumping this version, remember to update it in the rustc/platform-support docs. - let (major, minor) = match (arch, abi) { - (Arm64e, _) => (14, 0), - // Mac Catalyst defaults to 13.1 in Clang. - (_, "macabi") => (13, 1), - _ => (10, 0), - }; - from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((major, minor)) -} - -pub(crate) fn ios_llvm_target(arch: Arch) -> String { - // Modern iOS tooling extracts information about deployment target - // from LC_BUILD_VERSION. This load command will only be emitted when - // we build with a version specific `llvm_target`, with the version - // set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode - // to pick it up (since std and core are still built with the fallback - // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION). - let (major, minor) = ios_deployment_target(arch, ""); - format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor) -} - -pub(crate) fn mac_catalyst_llvm_target(arch: Arch) -> String { - let (major, minor) = ios_deployment_target(arch, "macabi"); - format!("{}-apple-ios{}.{}.0-macabi", arch.target_name(), major, minor) -} - -pub(crate) fn ios_sim_llvm_target(arch: Arch) -> String { - let (major, minor) = ios_deployment_target(arch, "sim"); - format!("{}-apple-ios{}.{}.0-simulator", arch.target_name(), major, minor) -} - -fn tvos_deployment_target() -> (u32, u32) { - // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. - // Note: If bumping this version, remember to update it in the rustc platform-support docs. - from_set_deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((10, 0)) -} - -pub(crate) fn tvos_llvm_target(arch: Arch) -> String { - let (major, minor) = tvos_deployment_target(); - format!("{}-apple-tvos{}.{}.0", arch.target_name(), major, minor) -} - -pub(crate) fn tvos_sim_llvm_target(arch: Arch) -> String { - let (major, minor) = tvos_deployment_target(); - format!("{}-apple-tvos{}.{}.0-simulator", arch.target_name(), major, minor) -} - -fn watchos_deployment_target() -> (u32, u32) { - // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. - // Note: If bumping this version, remember to update it in the rustc platform-support docs. - from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) -} - -pub(crate) fn watchos_llvm_target(arch: Arch) -> String { - let (major, minor) = watchos_deployment_target(); - format!("{}-apple-watchos{}.{}.0", arch.target_name(), major, minor) -} - -pub(crate) fn watchos_sim_llvm_target(arch: Arch) -> String { - let (major, minor) = watchos_deployment_target(); - format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor) -} - -fn visionos_deployment_target() -> (u32, u32) { - // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. - // Note: If bumping this version, remember to update it in the rustc platform-support docs. - from_set_deployment_target("XROS_DEPLOYMENT_TARGET").unwrap_or((1, 0)) -} - -pub(crate) fn visionos_llvm_target(arch: Arch) -> String { - let (major, minor) = visionos_deployment_target(); - format!("{}-apple-visionos{}.{}.0", arch.target_name(), major, minor) -} - -pub(crate) fn visionos_sim_llvm_target(arch: Arch) -> String { - let (major, minor) = visionos_deployment_target(); - format!("{}-apple-visionos{}.{}.0-simulator", arch.target_name(), major, minor) +/// Parse an OS version triple (SDK version or deployment target). +/// +/// The size of the returned numbers here are limited by Mach-O's +/// `LC_BUILD_VERSION`. +fn parse_version(version: &str) -> Result<(u16, u8, u8), ParseIntError> { + if let Some((major, minor)) = version.split_once('.') { + let major = major.parse()?; + if let Some((minor, patch)) = minor.split_once('.') { + Ok((major, minor.parse()?, patch.parse()?)) + } else { + Ok((major, minor.parse()?, 0)) + } + } else { + Ok((version.parse()?, 0, 0)) + } } diff --git a/compiler/rustc_target/src/spec/base/apple/tests.rs b/compiler/rustc_target/src/spec/base/apple/tests.rs index 7a985ad4dc0..d55b44e3c9e 100644 --- a/compiler/rustc_target/src/spec/base/apple/tests.rs +++ b/compiler/rustc_target/src/spec/base/apple/tests.rs @@ -1,3 +1,4 @@ +use super::parse_version; use crate::spec::targets::{ aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_visionos_sim, aarch64_apple_watchos_sim, i686_apple_darwin, x86_64_apple_darwin, x86_64_apple_ios, @@ -42,3 +43,11 @@ fn macos_link_environment_unmodified() { ); } } + +#[test] +fn test_parse_version() { + assert_eq!(parse_version("10"), Ok((10, 0, 0))); + assert_eq!(parse_version("10.12"), Ok((10, 12, 0))); + assert_eq!(parse_version("10.12.6"), Ok((10, 12, 6))); + assert_eq!(parse_version("9999.99.99"), Ok((9999, 99, 99))); +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6abd8a0d6b7..58d47c201f0 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -60,8 +60,8 @@ pub mod crt_objects; mod base; pub use base::apple::{ - deployment_target as current_apple_deployment_target, platform as current_apple_platform, - sdk_version as current_apple_sdk_version, + deployment_target_for_target as current_apple_deployment_target, + platform as current_apple_platform, sdk_version as current_apple_sdk_version, }; pub use base::avr_gnu::ef_avr_arch; diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index 912392c9fef..1061633be17 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -1,20 +1,10 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; - let mut base = opts("macos", arch, TargetAbi::Normal); - base.cpu = "apple-m1".into(); - base.max_atomic_width = Some(128); - - // FIXME: The leak sanitizer currently fails the tests, see #88132. - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetAbi::Normal); Target { - // Clang automatically chooses a more specific target based on - // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work - // correctly, we do too. - llvm_target: macos_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 macOS (11.0+, Big Sur+)".into()), tier: Some(1), @@ -23,11 +13,15 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { mcount: "\u{1}mcount".into(), frame_pointer: FramePointer::NonLeaf, - ..base + cpu: "apple-m1".into(), + max_atomic_width: Some(128), + // FIXME: The leak sanitizer currently fails the tests, see #88132. + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index 7f3a86f3256..caeb9a121e4 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -1,17 +1,10 @@ -use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; - let mut base = opts("ios", arch, TargetAbi::Normal); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Normal); Target { - // Clang automatically chooses a more specific target based on - // IPHONEOS_DEPLOYMENT_TARGET. - // This is required for the target to pick the right - // MACH-O commands, so we do too. - llvm_target: ios_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 iOS".into()), tier: Some(2), @@ -20,12 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..base + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index e60eeda4295..eee9eca3bcb 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -1,13 +1,10 @@ -use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; - let mut base = opts("ios", arch, TargetAbi::MacCatalyst); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::MacCatalyst); Target { - llvm_target: mac_catalyst_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("Apple Catalyst on ARM64".into()), tier: Some(2), @@ -16,12 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..base + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index d605e22701a..ee58038301d 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -1,17 +1,10 @@ -use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; - let mut base = opts("ios", arch, TargetAbi::Simulator); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Simulator); Target { - // Clang automatically chooses a more specific target based on - // IPHONEOS_DEPLOYMENT_TARGET. - // This is required for the simulator target to pick the right - // MACH-O commands, so we do too. - llvm_target: ios_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("Apple iOS Simulator on ARM64".into()), tier: Some(2), @@ -20,12 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..base + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index fc774ab94c8..baca863d442 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{opts, tvos_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Normal); Target { - llvm_target: tvos_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 tvOS".into()), tier: Some(3), @@ -13,12 +13,12 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..opts("tvos", arch, TargetAbi::Normal) + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index 8e8bb1efc9d..1a48f8c5acf 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Simulator); Target { - llvm_target: tvos_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 tvOS Simulator".into()), tier: Some(3), @@ -13,12 +13,12 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..opts("tvos", arch, TargetAbi::Simulator) + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs index 16c7d72daed..1424126134d 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs @@ -1,13 +1,10 @@ -use crate::spec::base::apple::{opts, visionos_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; - let mut base = opts("visionos", arch, TargetAbi::Normal); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Normal); Target { - llvm_target: visionos_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 Apple visionOS".into()), tier: Some(3), @@ -16,12 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..base + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs index 42973e0268e..d7226e02ecb 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs @@ -1,13 +1,10 @@ -use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; - let mut base = opts("visionos", arch, TargetAbi::Simulator); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Simulator); Target { - llvm_target: visionos_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 Apple visionOS simulator".into()), tier: Some(3), @@ -16,12 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..base + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs index 03fc2518d1d..1940a568b39 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub(crate) fn target() -> Target { - let base = opts("watchos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Normal); Target { - llvm_target: "aarch64-apple-watchos".into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 Apple WatchOS".into()), tier: Some(3), @@ -13,13 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: "aarch64".into(), + arch, options: TargetOptions { features: "+v8a,+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), dynamic_linking: false, position_independent_executables: true, - ..base + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index 13e2b961794..6beef11c504 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -1,14 +1,10 @@ -use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64; + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Simulator); Target { - // Clang automatically chooses a more specific target based on - // WATCHOS_DEPLOYMENT_TARGET. - // This is required for the simulator target to pick the right - // MACH-O commands, so we do too. - llvm_target: watchos_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64 Apple WatchOS Simulator".into()), tier: Some(3), @@ -17,12 +13,12 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..opts("watchos", arch, TargetAbi::Simulator) + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs index f292ee7f563..e9f4d9330d5 100644 --- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs @@ -1,11 +1,10 @@ -use crate::spec::base::apple::{opts, watchos_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64_32; - let base = opts("watchos", arch, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64_32, TargetAbi::Normal); Target { - llvm_target: watchos_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("Arm Apple WatchOS 64-bit with 32-bit pointers".into()), tier: Some(3), @@ -14,13 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, data_layout: "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: "aarch64".into(), + arch, options: TargetOptions { features: "+v8a,+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), dynamic_linking: false, position_independent_executables: true, - ..base + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index e86b8358a9c..4f7c945b9fe 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -1,20 +1,10 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64e; - let mut base = opts("macos", arch, TargetAbi::Normal); - base.cpu = "apple-m1".into(); - base.max_atomic_width = Some(128); - - // FIXME: The leak sanitizer currently fails the tests, see #88132. - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetAbi::Normal); Target { - // Clang automatically chooses a more specific target based on - // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work - // correctly, we do too. - llvm_target: macos_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64e Apple Darwin".into()), tier: Some(3), @@ -23,11 +13,15 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { mcount: "\u{1}mcount".into(), frame_pointer: FramePointer::NonLeaf, - ..base + cpu: "apple-m1".into(), + max_atomic_width: Some(128), + // FIXME: The leak sanitizer currently fails the tests, see #88132. + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index fcb850f44bc..8f192fe2886 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -1,17 +1,10 @@ -use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Arm64e; - let mut base = opts("ios", arch, TargetAbi::Normal); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetAbi::Normal); Target { - // Clang automatically chooses a more specific target based on - // IPHONEOS_DEPLOYMENT_TARGET. - // This is required for the target to pick the right - // MACH-O commands, so we do too. - llvm_target: ios_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("ARM64e Apple iOS".into()), tier: Some(3), @@ -20,12 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12,+v8.3a,+pauth".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..base + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs index 35de6b35eaf..8fe27f60e0a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Armv7k; + let (opts, llvm_target, arch) = base("watchos", Arch::Armv7k, TargetAbi::Normal); Target { - llvm_target: "armv7k-apple-watchos".into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("Armv7-A Apple WatchOS".into()), tier: Some(3), @@ -13,13 +13,13 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, data_layout: "e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+v7,+vfp4,+neon".into(), max_atomic_width: Some(64), dynamic_linking: false, position_independent_executables: true, - ..opts("watchos", arch, TargetAbi::Normal) + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs index 41eaa79d3eb..deee6985f1a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::Armv7s; + let (opts, llvm_target, arch) = base("ios", Arch::Armv7s, TargetAbi::Normal); Target { - llvm_target: ios_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("Armv7-A Apple-A6 Apple iOS".into()), tier: Some(3), @@ -13,11 +13,11 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(), - arch: arch.target_arch(), + arch, options: TargetOptions { features: "+v7,+vfp4,+neon".into(), max_atomic_width: Some(64), - ..opts("ios", arch, TargetAbi::Normal) + ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index 263393fd536..dc14cb3ec76 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -1,17 +1,12 @@ -use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::I386; // i386-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let abi = TargetAbi::Simulator; + let (opts, llvm_target, arch) = base("ios", Arch::I386, TargetAbi::Simulator); Target { - // Clang automatically chooses a more specific target based on - // IPHONEOS_DEPLOYMENT_TARGET. - // This is required for the target to pick the right - // MACH-O commands, so we do too. - llvm_target: ios_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("32-bit x86 iOS".into()), tier: Some(3), @@ -22,7 +17,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i128:128-f64:32:64-f80:128-n8:16:32-S128" .into(), - arch: arch.target_arch(), - options: TargetOptions { max_atomic_width: Some(64), ..opts("ios", arch, abi) }, + arch, + options: TargetOptions { max_atomic_width: Some(64), ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index f173e8b7e4a..67afe35bee4 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -1,21 +1,12 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions}; pub(crate) fn target() -> Target { - // ld64 only understands i386 and not i686 - let arch = Arch::I386; - let mut base = opts("macos", arch, TargetAbi::Normal); - base.max_atomic_width = Some(64); - base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]); - base.frame_pointer = FramePointer::Always; + let (mut opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal); + opts.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]); Target { - // Clang automatically chooses a more specific target based on - // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work - // correctly, we do too. - // - // While ld64 doesn't understand i686, LLVM does. - llvm_target: macos_llvm_target(Arch::I686).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("32-bit macOS (10.12+, Sierra+)".into()), tier: Some(3), @@ -26,7 +17,12 @@ pub(crate) fn target() -> Target { data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i128:128-f64:32:64-f80:128-n8:16:32-S128" .into(), - arch: arch.target_arch(), - options: TargetOptions { mcount: "\u{1}mcount".into(), ..base }, + arch, + options: TargetOptions { + mcount: "\u{1}mcount".into(), + max_atomic_width: Some(64), + frame_pointer: FramePointer::Always, + ..opts + }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 7bf18026735..e7f14aa9209 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -1,20 +1,11 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::X86_64; - let mut base = opts("macos", arch, TargetAbi::Normal); - base.max_atomic_width = Some(128); // penryn+ supports cmpxchg16b - base.frame_pointer = FramePointer::Always; - base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); - base.supported_sanitizers = - SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; - + let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal); + opts.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); Target { - // Clang automatically chooses a more specific target based on - // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work - // correctly, we do too. - llvm_target: macos_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("64-bit macOS (10.12+, Sierra+)".into()), tier: Some(1), @@ -24,7 +15,16 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), - arch: arch.target_arch(), - options: TargetOptions { mcount: "\u{1}mcount".into(), ..base }, + arch, + options: TargetOptions { + mcount: "\u{1}mcount".into(), + max_atomic_width: Some(128), // penryn+ supports cmpxchg16b + frame_pointer: FramePointer::Always, + supported_sanitizers: SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::LEAK + | SanitizerSet::THREAD, + ..opts + }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index 76a0bb1d91e..847c4f011f9 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -1,15 +1,12 @@ -use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::X86_64; // x86_64-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let mut base = opts("ios", arch, TargetAbi::Simulator); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::Simulator); Target { - llvm_target: ios_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("64-bit x86 iOS".into()), tier: Some(2), @@ -19,7 +16,11 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), - arch: arch.target_arch(), - options: TargetOptions { max_atomic_width: Some(128), ..base }, + arch, + options: TargetOptions { + max_atomic_width: Some(128), + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, + ..opts + }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index f66efbbf709..042079f800b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -1,13 +1,10 @@ -use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::X86_64; - let mut base = opts("ios", arch, TargetAbi::MacCatalyst); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; - + let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::MacCatalyst); Target { - llvm_target: mac_catalyst_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("Apple Catalyst on x86_64".into()), tier: Some(2), @@ -17,7 +14,11 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), - arch: arch.target_arch(), - options: TargetOptions { max_atomic_width: Some(128), ..base }, + arch, + options: TargetOptions { + max_atomic_width: Some(128), + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD, + ..opts + }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index f9d5f6e77d9..94708609790 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -1,13 +1,12 @@ -use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::X86_64; // x86_64-apple-tvos is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let abi = TargetAbi::Simulator; + let (opts, llvm_target, arch) = base("tvos", Arch::X86_64, TargetAbi::Simulator); Target { - llvm_target: tvos_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("x86 64-bit tvOS".into()), tier: Some(3), @@ -17,7 +16,7 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), - arch: arch.target_arch(), - options: TargetOptions { max_atomic_width: Some(128), ..opts("tvos", arch, abi) }, + arch, + options: TargetOptions { max_atomic_width: Some(128), ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index 1fced10c895..1dab9598860 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::X86_64; + let (opts, llvm_target, arch) = base("watchos", Arch::X86_64, TargetAbi::Simulator); Target { - llvm_target: watchos_sim_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("x86 64-bit Apple WatchOS simulator".into()), tier: Some(3), @@ -14,10 +14,7 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), - arch: arch.target_arch(), - options: TargetOptions { - max_atomic_width: Some(128), - ..opts("watchos", arch, TargetAbi::Simulator) - }, + arch, + options: TargetOptions { max_atomic_width: Some(128), ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index 9b9ffe4e536..f44bc660a62 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -1,13 +1,12 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; +use crate::spec::base::apple::{base, Arch, TargetAbi}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let arch = Arch::X86_64h; - let mut base = opts("macos", arch, TargetAbi::Normal); - base.max_atomic_width = Some(128); - base.frame_pointer = FramePointer::Always; - base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); - base.supported_sanitizers = + let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetAbi::Normal); + opts.max_atomic_width = Some(128); + opts.frame_pointer = FramePointer::Always; + opts.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); + opts.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; // x86_64h is core2-avx without a few of the features which would otherwise @@ -20,19 +19,16 @@ pub(crate) fn target() -> Target { // It would be nice if this were not the case, but fixing it seems tricky // (and given that the main use-case for this target is for use in universal // binaries, probably not that important). - base.features = "-rdrnd,-aes,-pclmul,-rtm,-fsgsbase".into(); + opts.features = "-rdrnd,-aes,-pclmul,-rtm,-fsgsbase".into(); // Double-check that the `cpu` is what we expect (if it's not the list above // may need updating). assert_eq!( - base.cpu, "core-avx2", + opts.cpu, "core-avx2", "you need to adjust the feature list in x86_64h-apple-darwin if you change this", ); Target { - // Clang automatically chooses a more specific target based on - // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work - // correctly, we do too. - llvm_target: macos_llvm_target(arch).into(), + llvm_target, metadata: crate::spec::TargetMetadata { description: Some("macOS with late-gen Intel (at least Haswell)".into()), tier: Some(3), @@ -42,7 +38,7 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), - arch: arch.target_arch(), - options: TargetOptions { mcount: "\u{1}mcount".into(), ..base }, + arch, + options: TargetOptions { mcount: "\u{1}mcount".into(), ..opts }, } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index bff2a184b19..65d21518491 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -348,8 +348,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } if let Some(ty::error::ExpectedFound { found, .. }) = exp_found - && ty.is_box() - && ty.boxed_ty() == found + && ty.boxed_ty() == Some(found) && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { err.span_suggestion( diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index a93b633ce1a..cf9891f15ad 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -1296,6 +1296,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) && self.tecx.tcx.trait_of_item(def_id).is_some() && !has_impl_trait(def_id) + // FIXME(fn_delegation): In delegation item argument spans are equal to last path + // segment. This leads to ICE's when emitting `multipart_suggestion`. + && tcx.hir().opt_delegation_sig_id(expr.hir_id.owner.def_id).is_none() { let successor = method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index db71331d07f..7bfc6471dc8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::print::{FmtPrinter, Printer}; use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; use rustc_span::def_id::DefId; @@ -317,7 +317,7 @@ impl<T> Trait<T> for X { { let mut has_matching_impl = false; tcx.for_each_relevant_impl(def_id, values.found, |did| { - if DeepRejectCtxt::new(tcx, TreatParams::ForLookup) + if DeepRejectCtxt::relate_rigid_infer(tcx) .types_may_unify(values.found, tcx.type_of(did).skip_binder()) { has_matching_impl = true; @@ -338,7 +338,7 @@ impl<T> Trait<T> for X { { let mut has_matching_impl = false; tcx.for_each_relevant_impl(def_id, values.expected, |did| { - if DeepRejectCtxt::new(tcx, TreatParams::ForLookup) + if DeepRejectCtxt::relate_rigid_infer(tcx) .types_may_unify(values.expected, tcx.type_of(did).skip_binder()) { has_matching_impl = true; @@ -358,7 +358,7 @@ impl<T> Trait<T> for X { { let mut has_matching_impl = false; tcx.for_each_relevant_impl(def_id, values.found, |did| { - if DeepRejectCtxt::new(tcx, TreatParams::ForLookup) + if DeepRejectCtxt::relate_rigid_infer(tcx) .types_may_unify(values.found, tcx.type_of(did).skip_binder()) { has_matching_impl = true; diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8b55f84bccc..bafe1ffae44 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -15,7 +15,7 @@ use rustc_middle::bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; pub use rustc_next_trait_solver::coherence::*; @@ -96,7 +96,7 @@ pub fn overlapping_impls( // Before doing expensive operations like entering an inference context, do // a quick check via fast_reject to tell if the impl headers could possibly // unify. - let drcx = DeepRejectCtxt::new(tcx, TreatParams::AsCandidateKey); + let drcx = DeepRejectCtxt::relate_infer_infer(tcx); let impl1_ref = tcx.impl_trait_ref(impl1_def_id); let impl2_ref = tcx.impl_trait_ref(impl2_def_id); let may_overlap = match (impl1_ref, impl2_ref) { diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index de1d4ef15ac..c8811bc37b3 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -35,10 +35,8 @@ where if infcx.next_trait_solver() { Box::new(NextFulfillmentCtxt::new(infcx)) } else { - let new_solver_globally = - infcx.tcx.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally); assert!( - !new_solver_globally, + !infcx.tcx.next_trait_solver_globally(), "using old solver even though new solver is enabled globally" ); Box::new(FulfillmentContext::new(infcx)) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 4702fd866c1..630acc91fbe 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -13,6 +13,7 @@ use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::select::OverflowError; pub use rustc_middle::traits::Reveal; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData}; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast}; @@ -886,6 +887,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( potentially_unnormalized_candidates: bool, ) { let infcx = selcx.infcx; + let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); for predicate in env_predicates { let bound_predicate = predicate.kind(); if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() { @@ -894,6 +896,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( continue; } + if !drcx + .args_may_unify(obligation.predicate.args, data.skip_binder().projection_term.args) + { + continue; + } + let is_match = infcx.probe(|_| { selcx.match_projection_projections( obligation, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 96faa5236b1..77efc2fc2db 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -13,7 +13,7 @@ use hir::LangItem; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation, SelectionError}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -248,11 +248,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .filter(|p| p.def_id() == stack.obligation.predicate.def_id()) .filter(|p| p.polarity() == stack.obligation.predicate.polarity()); + let drcx = DeepRejectCtxt::relate_rigid_rigid(self.tcx()); + let obligation_args = stack.obligation.predicate.skip_binder().trait_ref.args; // Keep only those bounds which may apply, and propagate overflow if it occurs. for bound in bounds { + let bound_trait_ref = bound.map_bound(|t| t.trait_ref); + if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) { + continue; + } // FIXME(oli-obk): it is suspicious that we are dropping the constness and // polarity here. - let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?; + let wc = self.where_clause_may_apply(stack, bound_trait_ref)?; if wc.may_apply() { candidates.vec.push(ParamCandidate(bound)); } @@ -581,7 +587,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - let drcx = DeepRejectCtxt::new(self.tcx(), TreatParams::ForLookup); + let drcx = DeepRejectCtxt::relate_rigid_infer(self.tcx()); let obligation_args = obligation.predicate.skip_binder().trait_ref.args; self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 0fdaf40b136..13620f4b8d9 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -41,7 +41,7 @@ impl<'tcx> Children { fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); if let Some(st) = - fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey) + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer) { debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); self.non_blanket_impls.entry(st).or_default().push(impl_def_id) @@ -58,7 +58,7 @@ impl<'tcx> Children { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); let vec: &mut Vec<DefId>; if let Some(st) = - fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey) + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer) { debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); vec = self.non_blanket_impls.get_mut(&st).unwrap(); @@ -279,7 +279,7 @@ impl<'tcx> Graph { let mut parent = trait_def_id; let mut last_lint = None; let simplified = - fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey); + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer); // Descend the specialization tree, where `parent` is the current parent node. loop { diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index fab4a099117..2c8e47bcbca 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -74,13 +74,13 @@ impl<HCX: Clone, DefId: HashStable<HCX>> ToStableHashKey<HCX> for SimplifiedType pub enum TreatParams { /// Treat parameters as infer vars. This is the correct mode for caching /// an impl's type for lookup. - AsCandidateKey, + InstantiateWithInfer, /// Treat parameters as placeholders in the given environment. This is the /// correct mode for *lookup*, as during candidate selection. /// /// This also treats projections with inference variables as infer vars /// since they could be further normalized. - ForLookup, + AsRigid, } /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. @@ -140,18 +140,16 @@ pub fn simplify_type<I: Interner>( } ty::Placeholder(..) => Some(SimplifiedType::Placeholder), ty::Param(_) => match treat_params { - TreatParams::ForLookup => Some(SimplifiedType::Placeholder), - TreatParams::AsCandidateKey => None, + TreatParams::AsRigid => Some(SimplifiedType::Placeholder), + TreatParams::InstantiateWithInfer => None, }, ty::Alias(..) => match treat_params { // When treating `ty::Param` as a placeholder, projections also // don't unify with anything else as long as they are fully normalized. // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder` // when the new solver is enabled by default. - TreatParams::ForLookup if !ty.has_non_region_infer() => { - Some(SimplifiedType::Placeholder) - } - TreatParams::ForLookup | TreatParams::AsCandidateKey => None, + TreatParams::AsRigid if !ty.has_non_region_infer() => Some(SimplifiedType::Placeholder), + TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None, }, ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), ty::Error(_) => Some(SimplifiedType::Error), @@ -173,29 +171,49 @@ impl<DefId> SimplifiedType<DefId> { } } -/// Given generic arguments from an obligation and an impl, -/// could these two be unified after replacing parameters in the -/// the impl with inference variables. +/// Given generic arguments, could they be unified after +/// replacing parameters with inference variables or placeholders. +/// This behavior is toggled using the const generics. /// -/// For obligations, parameters won't be replaced by inference -/// variables and only unify with themselves. We treat them -/// the same way we treat placeholders. +/// We use this to quickly reject impl/wc candidates without needing +/// to instantiate generic arguments/having to enter a probe. /// /// We also use this function during coherence. For coherence the /// impls only have to overlap for some value, so we treat parameters -/// on both sides like inference variables. This behavior is toggled -/// using the `treat_obligation_params` field. +/// on both sides like inference variables. #[derive(Debug, Clone, Copy)] -pub struct DeepRejectCtxt<I: Interner> { - treat_obligation_params: TreatParams, +pub struct DeepRejectCtxt< + I: Interner, + const INSTANTIATE_LHS_WITH_INFER: bool, + const INSTANTIATE_RHS_WITH_INFER: bool, +> { _interner: PhantomData<I>, } -impl<I: Interner> DeepRejectCtxt<I> { - pub fn new(_interner: I, treat_obligation_params: TreatParams) -> Self { - DeepRejectCtxt { treat_obligation_params, _interner: PhantomData } +impl<I: Interner> DeepRejectCtxt<I, false, false> { + /// Treat parameters in both the lhs and the rhs as rigid. + pub fn relate_rigid_rigid(_interner: I) -> DeepRejectCtxt<I, false, false> { + DeepRejectCtxt { _interner: PhantomData } + } +} + +impl<I: Interner> DeepRejectCtxt<I, true, true> { + /// Treat parameters in both the lhs and the rhs as infer vars. + pub fn relate_infer_infer(_interner: I) -> DeepRejectCtxt<I, true, true> { + DeepRejectCtxt { _interner: PhantomData } } +} +impl<I: Interner> DeepRejectCtxt<I, false, true> { + /// Treat parameters in the lhs as rigid, and in rhs as infer vars. + pub fn relate_rigid_infer(_interner: I) -> DeepRejectCtxt<I, false, true> { + DeepRejectCtxt { _interner: PhantomData } + } +} + +impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_WITH_INFER: bool> + DeepRejectCtxt<I, INSTANTIATE_LHS_WITH_INFER, INSTANTIATE_RHS_WITH_INFER> +{ pub fn args_may_unify( self, obligation_args: I::GenericArgs, @@ -216,11 +234,18 @@ impl<I: Interner> DeepRejectCtxt<I> { }) } - pub fn types_may_unify(self, obligation_ty: I::Ty, impl_ty: I::Ty) -> bool { - match impl_ty.kind() { - // Start by checking whether the type in the impl may unify with + pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool { + match rhs.kind() { + // Start by checking whether the `rhs` type may unify with // pretty much everything. Just return `true` in that case. - ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true, + ty::Param(_) => { + if INSTANTIATE_RHS_WITH_INFER { + return true; + } + } + ty::Error(_) | ty::Alias(..) | ty::Bound(..) => return true, + ty::Infer(var) => return self.var_and_ty_may_unify(var, lhs), + // These types only unify with inference variables or their own // variant. ty::Bool @@ -238,159 +263,217 @@ impl<I: Interner> DeepRejectCtxt<I> { | ty::Ref(..) | ty::Never | ty::Tuple(..) + | ty::FnDef(..) | ty::FnPtr(..) - | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()), - ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(_) => panic!("unexpected impl_ty: {impl_ty:?}"), - } + | ty::Foreign(_) + | ty::Placeholder(_) => {} + }; - let k = impl_ty.kind(); - match obligation_ty.kind() { - // Purely rigid types, use structural equivalence. - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Never - | ty::Foreign(_) => obligation_ty == impl_ty, - ty::Ref(_, obl_ty, obl_mutbl) => match k { - ty::Ref(_, impl_ty, impl_mutbl) => { - obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty) + // For purely rigid types, use structural equivalence. + match lhs.kind() { + ty::Ref(_, lhs_ty, lhs_mutbl) => match rhs.kind() { + ty::Ref(_, rhs_ty, rhs_mutbl) => { + lhs_mutbl == rhs_mutbl && self.types_may_unify(lhs_ty, rhs_ty) } _ => false, }, - ty::Adt(obl_def, obl_args) => match k { - ty::Adt(impl_def, impl_args) => { - obl_def == impl_def && self.args_may_unify(obl_args, impl_args) + + ty::Adt(lhs_def, lhs_args) => match rhs.kind() { + ty::Adt(rhs_def, rhs_args) => { + lhs_def == rhs_def && self.args_may_unify(lhs_args, rhs_args) } _ => false, }, - ty::Pat(obl_ty, _) => { - // FIXME(pattern_types): take pattern into account - matches!(k, ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty)) + + // Depending on the value of const generics, we either treat generic parameters + // like placeholders or like inference variables. + ty::Param(lhs) => { + INSTANTIATE_LHS_WITH_INFER + || match rhs.kind() { + ty::Param(rhs) => lhs == rhs, + _ => false, + } } - ty::Slice(obl_ty) => { - matches!(k, ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) + + // Placeholder types don't unify with anything on their own. + ty::Placeholder(lhs) => { + matches!(rhs.kind(), ty::Placeholder(rhs) if lhs == rhs) } - ty::Array(obl_ty, obl_len) => match k { - ty::Array(impl_ty, impl_len) => { - self.types_may_unify(obl_ty, impl_ty) - && self.consts_may_unify(obl_len, impl_len) + + ty::Infer(var) => self.var_and_ty_may_unify(var, rhs), + + // As we're walking the whole type, it may encounter projections + // inside of binders and what not, so we're just going to assume that + // projections can unify with other stuff. + // + // Looking forward to lazy normalization this is the safer strategy anyways. + ty::Alias(..) => true, + + ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Bool + | ty::Char + | ty::Never + | ty::Foreign(_) => lhs == rhs, + + ty::Tuple(lhs) => match rhs.kind() { + ty::Tuple(rhs) => { + lhs.len() == rhs.len() + && iter::zip(lhs.iter(), rhs.iter()) + .all(|(lhs, rhs)| self.types_may_unify(lhs, rhs)) } _ => false, }, - ty::Tuple(obl) => match k { - ty::Tuple(imp) => { - obl.len() == imp.len() - && iter::zip(obl.iter(), imp.iter()) - .all(|(obl, imp)| self.types_may_unify(obl, imp)) + + ty::Array(lhs_ty, lhs_len) => match rhs.kind() { + ty::Array(rhs_ty, rhs_len) => { + self.types_may_unify(lhs_ty, rhs_ty) && self.consts_may_unify(lhs_len, rhs_len) } _ => false, }, - ty::RawPtr(obl_ty, obl_mutbl) => match k { - ty::RawPtr(imp_ty, imp_mutbl) => { - obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty) + + ty::RawPtr(lhs_ty, lhs_mutbl) => match rhs.kind() { + ty::RawPtr(rhs_ty, rhs_mutbl) => { + lhs_mutbl == rhs_mutbl && self.types_may_unify(lhs_ty, rhs_ty) } _ => false, }, - ty::Dynamic(obl_preds, ..) => { + + ty::Slice(lhs_ty) => { + matches!(rhs.kind(), ty::Slice(rhs_ty) if self.types_may_unify(lhs_ty, rhs_ty)) + } + + ty::Dynamic(lhs_preds, ..) => { // Ideally we would walk the existential predicates here or at least // compare their length. But considering that the relevant `Relate` impl // actually sorts and deduplicates these, that doesn't work. - matches!(k, ty::Dynamic(impl_preds, ..) if - obl_preds.principal_def_id() == impl_preds.principal_def_id() + matches!(rhs.kind(), ty::Dynamic(rhs_preds, ..) if + lhs_preds.principal_def_id() == rhs_preds.principal_def_id() ) } - ty::FnPtr(obl_sig_tys, obl_hdr) => match k { - ty::FnPtr(impl_sig_tys, impl_hdr) => { - let obl_sig_tys = obl_sig_tys.skip_binder().inputs_and_output; - let impl_sig_tys = impl_sig_tys.skip_binder().inputs_and_output; - - obl_hdr == impl_hdr - && obl_sig_tys.len() == impl_sig_tys.len() - && iter::zip(obl_sig_tys.iter(), impl_sig_tys.iter()) - .all(|(obl, imp)| self.types_may_unify(obl, imp)) + + ty::FnPtr(lhs_sig_tys, lhs_hdr) => match rhs.kind() { + ty::FnPtr(rhs_sig_tys, rhs_hdr) => { + let lhs_sig_tys = lhs_sig_tys.skip_binder().inputs_and_output; + let rhs_sig_tys = rhs_sig_tys.skip_binder().inputs_and_output; + + lhs_hdr == rhs_hdr + && lhs_sig_tys.len() == rhs_sig_tys.len() + && iter::zip(lhs_sig_tys.iter(), rhs_sig_tys.iter()) + .all(|(lhs, rhs)| self.types_may_unify(lhs, rhs)) } _ => false, }, - // Impls cannot contain these types as these cannot be named directly. - ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false, - - // Placeholder types don't unify with anything on their own - ty::Placeholder(..) | ty::Bound(..) => false, + ty::Bound(..) => true, - // Depending on the value of `treat_obligation_params`, we either - // treat generic parameters like placeholders or like inference variables. - ty::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, - TreatParams::AsCandidateKey => true, + ty::FnDef(lhs_def_id, lhs_args) => match rhs.kind() { + ty::FnDef(rhs_def_id, rhs_args) => { + lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args) + } + _ => false, }, - ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(), - - ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(), + ty::Closure(lhs_def_id, lhs_args) => match rhs.kind() { + ty::Closure(rhs_def_id, rhs_args) => { + lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args) + } + _ => false, + }, - ty::Infer(_) => true, + ty::CoroutineClosure(lhs_def_id, lhs_args) => match rhs.kind() { + ty::CoroutineClosure(rhs_def_id, rhs_args) => { + lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args) + } + _ => false, + }, - // As we're walking the whole type, it may encounter projections - // inside of binders and what not, so we're just going to assume that - // projections can unify with other stuff. - // - // Looking forward to lazy normalization this is the safer strategy anyways. - ty::Alias(..) => true, + ty::Coroutine(lhs_def_id, lhs_args) => match rhs.kind() { + ty::Coroutine(rhs_def_id, rhs_args) => { + lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args) + } + _ => false, + }, - ty::Error(_) => true, + ty::CoroutineWitness(lhs_def_id, lhs_args) => match rhs.kind() { + ty::CoroutineWitness(rhs_def_id, rhs_args) => { + lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args) + } + _ => false, + }, - ty::CoroutineWitness(..) => { - panic!("unexpected obligation type: {:?}", obligation_ty) + ty::Pat(lhs_ty, _) => { + // FIXME(pattern_types): take pattern into account + matches!(rhs.kind(), ty::Pat(rhs_ty, _) if self.types_may_unify(lhs_ty, rhs_ty)) } + + ty::Error(..) => true, } } - pub fn consts_may_unify(self, obligation_ct: I::Const, impl_ct: I::Const) -> bool { - let impl_val = match impl_ct.kind() { + pub fn consts_may_unify(self, lhs: I::Const, rhs: I::Const) -> bool { + match rhs.kind() { + ty::ConstKind::Param(_) => { + if INSTANTIATE_RHS_WITH_INFER { + return true; + } + } + ty::ConstKind::Expr(_) - | ty::ConstKind::Param(_) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Error(_) => { + | ty::ConstKind::Error(_) + | ty::ConstKind::Infer(_) + | ty::ConstKind::Bound(..) => { return true; } - ty::ConstKind::Value(_, impl_val) => impl_val, - ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { - panic!("unexpected impl arg: {:?}", impl_ct) - } + + ty::ConstKind::Value(..) | ty::ConstKind::Placeholder(_) => {} }; - match obligation_ct.kind() { - ty::ConstKind::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, - TreatParams::AsCandidateKey => true, + match lhs.kind() { + ty::ConstKind::Value(_, lhs_val) => match rhs.kind() { + ty::ConstKind::Value(_, rhs_val) => lhs_val == rhs_val, + _ => false, }, + ty::ConstKind::Param(lhs) => { + INSTANTIATE_LHS_WITH_INFER + || match rhs.kind() { + ty::ConstKind::Param(rhs) => lhs == rhs, + _ => false, + } + } + // Placeholder consts don't unify with anything on their own - ty::ConstKind::Placeholder(_) => false, + ty::ConstKind::Placeholder(lhs) => { + matches!(rhs.kind(), ty::ConstKind::Placeholder(rhs) if lhs == rhs) + } // As we don't necessarily eagerly evaluate constants, // they might unify with any value. ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { true } - ty::ConstKind::Value(_, obl_val) => obl_val == impl_val, - ty::ConstKind::Infer(_) => true, + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => true, + } + } - ty::ConstKind::Bound(..) => { - panic!("unexpected obl const: {:?}", obligation_ct) - } + fn var_and_ty_may_unify(self, var: ty::InferTy, ty: I::Ty) -> bool { + if !ty.is_known_rigid() { + return true; + } + + match var { + ty::IntVar(_) => ty.is_integral(), + ty::FloatVar(_) => ty.is_floating_point(), + _ => true, } } } diff --git a/config.example.toml b/config.example.toml index 13f76933b16..e9433c9c9bd 100644 --- a/config.example.toml +++ b/config.example.toml @@ -78,6 +78,9 @@ # Indicates whether the LLVM plugin is enabled or not #plugins = false +# Wheter to build Enzyme as AutoDiff backend. +#enzyme = false + # Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in # PATH, or set an absolute path to use a specific version. #ccache = false diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e60bcf3aa5d..81b21f02159 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -122,7 +122,6 @@ #![feature(const_cell_into_inner)] #![feature(const_eval_select)] #![feature(const_exact_div)] -#![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] #![feature(const_hash)] @@ -166,6 +165,8 @@ #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(duration_consts_float)] +#![feature(f128_const)] +#![feature(f16_const)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index d4236e47bfe..1959628bd8f 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -914,7 +914,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. @@ -963,7 +963,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. @@ -990,7 +990,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() @@ -1016,7 +1016,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() @@ -1053,7 +1053,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() @@ -1081,7 +1081,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -1108,7 +1108,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -1145,7 +1145,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f128_const", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 1e2f841aca7..9252e8c6015 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -925,7 +925,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. @@ -973,7 +973,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. @@ -999,7 +999,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() @@ -1024,7 +1024,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() @@ -1062,7 +1062,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() @@ -1086,7 +1086,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -1109,7 +1109,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -1143,7 +1143,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_unstable(feature = "f16_const", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index c1adcc753f2..2bc89722497 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1115,7 +1115,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_bits(self) -> u32 { // SAFETY: `u32` is a plain old datatype so we can always transmute to it. @@ -1159,7 +1159,7 @@ impl f32 { /// assert_eq!(v, 12.5); /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_bits(v: u32) -> Self { @@ -1183,7 +1183,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_be_bytes(self) -> [u8; 4] { self.to_bits().to_be_bytes() @@ -1204,7 +1204,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_le_bytes(self) -> [u8; 4] { self.to_bits().to_le_bytes() @@ -1238,7 +1238,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_ne_bytes(self) -> [u8; 4] { self.to_bits().to_ne_bytes() @@ -1256,7 +1256,7 @@ impl f32 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; 4]) -> Self { @@ -1275,7 +1275,7 @@ impl f32 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; 4]) -> Self { @@ -1305,7 +1305,7 @@ impl f32 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_ne_bytes(bytes: [u8; 4]) -> Self { diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index e6406771ad3..b3f5be9fc8a 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1111,7 +1111,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_bits(self) -> u64 { // SAFETY: `u64` is a plain old datatype so we can always transmute to it. @@ -1155,7 +1155,7 @@ impl f64 { /// assert_eq!(v, 12.5); /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_bits(v: u64) -> Self { @@ -1179,7 +1179,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_be_bytes(self) -> [u8; 8] { self.to_bits().to_be_bytes() @@ -1200,7 +1200,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_le_bytes(self) -> [u8; 8] { self.to_bits().to_le_bytes() @@ -1234,7 +1234,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_ne_bytes(self) -> [u8; 8] { self.to_bits().to_ne_bytes() @@ -1252,7 +1252,7 @@ impl f64 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; 8]) -> Self { @@ -1271,7 +1271,7 @@ impl f64 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; 8]) -> Self { @@ -1301,7 +1301,7 @@ impl f64 { /// assert_eq!(value, 12.5); /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[rustc_const_stable(feature = "const_float_bits_conv", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_ne_bytes(bytes: [u8; 8]) -> Self { diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index d7ed4edcc00..08d06cad55d 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2277,6 +2277,14 @@ impl<F: FnPtr> fmt::Debug for F { /// `addr_of!(expr)` is equivalent to `&raw const expr`. The macro is *soft-deprecated*; /// use `&raw const` instead. /// +/// It is still an open question under which conditions writing through an `addr_of!`-created +/// pointer is permitted. If the place `expr` evaluates to is based on a raw pointer, then the +/// result of `addr_of!` inherits all permissions from that raw pointer. However, if the place is +/// based on a reference, local variable, or `static`, then until all details are decided, the same +/// rules as for shared references apply: it is UB to write through a pointer created with this +/// operation, except for bytes located inside an `UnsafeCell`. Use `&raw mut` (or [`addr_of_mut`]) +/// to create a raw pointer that definitely permits mutation. +/// /// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned /// and points to initialized data. For cases where those requirements do not hold, /// raw pointers should be used instead. However, `&expr as *const _` creates a reference diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 0390bb59a89..c19eeedb354 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -250,7 +250,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::from_millis(2569); + /// let duration = Duration::from_millis(2_569); /// /// assert_eq!(2, duration.as_secs()); /// assert_eq!(569_000_000, duration.subsec_nanos()); @@ -279,7 +279,7 @@ impl Duration { /// let duration = Duration::from_micros(1_000_002); /// /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(2000, duration.subsec_nanos()); + /// assert_eq!(2_000, duration.subsec_nanos()); /// ``` #[stable(feature = "duration_from_micros", since = "1.27.0")] #[must_use] @@ -472,7 +472,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); + /// let duration = Duration::new(5, 730_023_852); /// assert_eq!(duration.as_secs(), 5); /// ``` /// @@ -501,7 +501,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::from_millis(5432); + /// let duration = Duration::from_millis(5_432); /// assert_eq!(duration.as_secs(), 5); /// assert_eq!(duration.subsec_millis(), 432); /// ``` @@ -547,7 +547,7 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::from_millis(5010); + /// let duration = Duration::from_millis(5_010); /// assert_eq!(duration.as_secs(), 5); /// assert_eq!(duration.subsec_nanos(), 10_000_000); /// ``` @@ -566,8 +566,8 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_millis(), 5730); + /// let duration = Duration::new(5, 730_023_852); + /// assert_eq!(duration.as_millis(), 5_730); /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] @@ -584,8 +584,8 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_micros(), 5730023); + /// let duration = Duration::new(5, 730_023_852); + /// assert_eq!(duration.as_micros(), 5_730_023); /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] @@ -602,8 +602,8 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_nanos(), 5730023852); + /// let duration = Duration::new(5, 730_023_852); + /// assert_eq!(duration.as_nanos(), 5_730_023_852); /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] @@ -879,7 +879,7 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 345_678_000); - /// assert_eq!(dur.as_millis_f64(), 2345.678); + /// assert_eq!(dur.as_millis_f64(), 2_345.678); /// ``` #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] @@ -900,7 +900,7 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 345_678_000); - /// assert_eq!(dur.as_millis_f32(), 2345.678); + /// assert_eq!(dur.as_millis_f32(), 2_345.678); /// ``` #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] @@ -1017,7 +1017,7 @@ impl Duration { /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_641)); - /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0)); + /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 918eec2d0d8..99bea676e12 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -852,7 +852,7 @@ impl OsStr { /// Converts an `OsStr` to a <code>[Cow]<[str]></code>. /// - /// Any non-Unicode sequences are replaced with + /// Any non-UTF-8 sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9eaa0e01c2c..506ad445b6b 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2200,7 +2200,7 @@ impl Path { /// Converts a `Path` to a [`Cow<str>`]. /// - /// Any non-Unicode sequences are replaced with + /// Any non-UTF-8 sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 08d46f356d9..e41cbc1a65c 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -195,8 +195,11 @@ impl Condvar { if poisoned { Err(PoisonError::new(guard)) } else { Ok(guard) } } - /// Blocks the current thread until this condition variable receives a - /// notification and the provided condition is false. + /// Blocks the current thread until the provided condition becomes false. + /// + /// `condition` is checked immediately; if not met (returns `true`), this + /// will [`wait`] for the next notification then check again. This repeats + /// until `condition` returns `false`, in which case this function returns. /// /// This function will atomically unlock the mutex specified (represented by /// `guard`) and block the current thread. This means that any calls @@ -210,6 +213,7 @@ impl Condvar { /// poisoned when this thread re-acquires the lock. For more information, /// see information about [poisoning] on the [`Mutex`] type. /// + /// [`wait`]: Self::wait /// [`notify_one`]: Self::notify_one /// [`notify_all`]: Self::notify_all /// [poisoning]: super::Mutex#poisoning diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 71f69e03a9f..666df49012c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -106,22 +106,29 @@ def _download(path, url, probably_big, verbose, exception): try: if (probably_big or verbose) and "GITHUB_ACTIONS" not in os.environ: - option = "-#" + option = "--progress-bar" else: - option = "-s" + option = "--silent" # If curl is not present on Win32, we should not sys.exit # but raise `CalledProcessError` or `OSError` instead require(["curl", "--version"], exception=platform_is_win32()) extra_flags = [] if curl_version() > (7, 70): extra_flags = [ "--retry-all-errors" ] + # options should be kept in sync with + # src/bootstrap/src/core/download.rs + # for consistency. + # they are also more compreprensivly explained in that file. run(["curl", option] + extra_flags + [ - "-L", # Follow redirect. - "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds - "--connect-timeout", "30", # timeout if cannot connect within 30 seconds - "-o", path, + # Follow redirect. + "--location", + # timeout if speed is < 10 bytes/sec for > 30 seconds + "--speed-time", "30", "--speed-limit", "10", + # timeout if cannot connect within 30 seconds + "--connect-timeout", "30", + "--output", path, "--continue-at", "-", - "--retry", "3", "-SRf", url], + "--retry", "3", "--show-error", "--remote-time", "--fail", url], verbose=verbose, exception=True, # Will raise RuntimeError on failure ) diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 768aac912ce..49d564642bd 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -71,6 +71,7 @@ v("llvm-libunwind", "rust.llvm-libunwind", "use LLVM libunwind") # channel, etc. o("optimize-llvm", "llvm.optimize", "build optimized LLVM") o("llvm-assertions", "llvm.assertions", "build LLVM with assertions") +o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme") o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface") o("debug-assertions", "rust.debug-assertions", "build with debugging assertions") o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions") diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 7f7faf077d0..ba12e64c4a2 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -228,7 +228,7 @@ impl Step for Rustc { self.override_build_kind.unwrap_or(builder.kind), ); - rustc_cargo(builder, &mut cargo, target, &compiler); + rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); // For ./x.py clippy, don't run with --all-targets because // linting tests and benchmarks can produce very noisy results diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index a2bb03cd5ac..a0992350722 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -197,7 +197,7 @@ impl Step for Rustc { Kind::Clippy, ); - rustc_cargo(builder, &mut cargo, target, &compiler); + rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); // Explicitly pass -p for all compiler crates -- this will force cargo // to also lint the tests/benches/examples for these crates, rather diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index eef548033f1..1936c91ef83 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -931,7 +931,12 @@ impl Step for Rustc { // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler, // so its artifacts can't be reused. if builder.download_rustc() && compiler.stage != 0 { - builder.ensure(Sysroot { compiler, force_recompile: false }); + let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); + cp_rustc_component_to_ci_sysroot( + builder, + &sysroot, + builder.config.ci_rustc_dev_contents(), + ); return compiler.stage; } @@ -983,7 +988,7 @@ impl Step for Rustc { Kind::Build, ); - rustc_cargo(builder, &mut cargo, target, &compiler); + rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be // consistently applied by check/doc/test modes too. @@ -1042,10 +1047,11 @@ pub fn rustc_cargo( cargo: &mut Cargo, target: TargetSelection, compiler: &Compiler, + crates: &[String], ) { cargo .arg("--features") - .arg(builder.rustc_features(builder.kind, target)) + .arg(builder.rustc_features(builder.kind, target, crates)) .arg("--manifest-path") .arg(builder.src.join("compiler/rustc/Cargo.toml")); @@ -1189,6 +1195,10 @@ pub fn rustc_cargo_env( cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); } + if builder.config.llvm_enzyme { + cargo.rustflag("--cfg=llvm_enzyme"); + } + // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've // detected that LLVM is already built and good to go which helps prevent @@ -1784,6 +1794,24 @@ impl Step for Assemble { // use that to bootstrap this compiler forward. let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); + // Build enzyme + let enzyme_install = if builder.config.llvm_enzyme { + Some(builder.ensure(llvm::Enzyme { target: build_compiler.host })) + } else { + None + }; + + if let Some(enzyme_install) = enzyme_install { + let lib_ext = std::env::consts::DLL_EXTENSION; + let src_lib = enzyme_install.join("build/Enzyme/libEnzyme-19").with_extension(lib_ext); + let libdir = builder.sysroot_libdir(build_compiler, build_compiler.host); + let target_libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); + let dst_lib = libdir.join("libEnzyme-19").with_extension(lib_ext); + let target_dst_lib = target_libdir.join("libEnzyme-19").with_extension(lib_ext); + builder.copy_link(&src_lib, &dst_lib); + builder.copy_link(&src_lib, &target_dst_lib); + } + // Build the libraries for this compiler to link to (i.e., the libraries // it uses at runtime). NOTE: Crates the target compiler compiles don't // link to these. (FIXME: Is that correct? It seems to be correct most diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index ffb617c642b..73d9e3f6793 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -826,7 +826,7 @@ impl Step for Rustc { // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 // cargo.rustdocflag("--generate-link-to-definition"); - compile::rustc_cargo(builder, &mut cargo, target, &compiler); + compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. @@ -1186,6 +1186,9 @@ impl Step for RustcBook { cmd.arg("--rustc"); cmd.arg(&rustc); cmd.arg("--rustc-target").arg(self.target.rustc_target_arg()); + if let Some(target_linker) = builder.linker(self.target) { + cmd.arg("--rustc-linker").arg(target_linker); + } if builder.is_verbose() { cmd.arg("--verbose"); } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index e1eea31b3bb..442638d3203 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -529,6 +529,7 @@ impl Step for Llvm { } }; + // FIXME(ZuseZ4): Do we need that for Enzyme too? // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned // libLLVM.dylib will be built. However, llvm-config will still look // for a versioned path like libLLVM-14.dylib. Manually create a symbolic @@ -849,6 +850,100 @@ fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> { .or_else(|| env::var_os(var_base)) } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Enzyme { + pub target: TargetSelection, +} + +impl Step for Enzyme { + type Output = PathBuf; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/enzyme/enzyme") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Enzyme { target: run.target }); + } + + /// Compile Enzyme for `target`. + fn run(self, builder: &Builder<'_>) -> PathBuf { + builder.require_submodule( + "src/tools/enzyme", + Some("The Enzyme sources are required for autodiff."), + ); + if builder.config.dry_run() { + let out_dir = builder.enzyme_out(self.target); + return out_dir; + } + let target = self.target; + + let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: self.target }); + + static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); + let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { + generate_smart_stamp_hash( + builder, + &builder.config.src.join("src/tools/enzyme"), + builder.enzyme_info.sha().unwrap_or_default(), + ) + }); + + let out_dir = builder.enzyme_out(target); + let stamp = out_dir.join("enzyme-finished-building"); + let stamp = HashStamp::new(stamp, Some(smart_stamp_hash)); + + if stamp.is_done() { + if stamp.hash.is_none() { + builder.info( + "Could not determine the Enzyme submodule commit hash. \ + Assuming that an Enzyme rebuild is not necessary.", + ); + builder.info(&format!( + "To force Enzyme to rebuild, remove the file `{}`", + stamp.path.display() + )); + } + return out_dir; + } + + builder.info(&format!("Building Enzyme for {}", target)); + t!(stamp.remove()); + let _time = helpers::timeit(builder); + t!(fs::create_dir_all(&out_dir)); + + builder + .config + .update_submodule(Path::new("src").join("tools").join("enzyme").to_str().unwrap()); + let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/")); + // FIXME(ZuseZ4): Find a nicer way to use Enzyme Debug builds + //cfg.profile("Debug"); + //cfg.define("CMAKE_BUILD_TYPE", "Debug"); + configure_cmake(builder, target, &mut cfg, true, LdFlags::default(), &[]); + + // Re-use the same flags as llvm to control the level of debug information + // generated for lld. + let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { + (false, _) => "Debug", + (true, false) => "Release", + (true, true) => "RelWithDebInfo", + }; + + cfg.out_dir(&out_dir) + .profile(profile) + .env("LLVM_CONFIG_REAL", &llvm_config) + .define("LLVM_ENABLE_ASSERTIONS", "ON") + .define("ENZYME_EXTERNAL_SHARED_LIB", "ON") + .define("LLVM_DIR", builder.llvm_out(target)); + + cfg.build(); + + t!(stamp.write()); + out_dir + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Lld { pub target: TargetSelection, diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a8e12540473..83f65615c8d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2690,7 +2690,7 @@ impl Step for Crate { } } Mode::Rustc => { - compile::rustc_cargo(builder, &mut cargo, target, &compiler); + compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); } _ => panic!("can only test libraries"), }; @@ -3529,11 +3529,13 @@ impl Step for TestFloatParse { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.build; - let compiler = builder.compiler(0, bootstrap_host); + let compiler = builder.compiler(builder.top_stage, bootstrap_host); let path = self.path.to_str().unwrap(); let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap(); - builder.ensure(compile::Std::new(compiler, self.host)); + if !builder.download_rustc() { + builder.ensure(compile::Std::new(compiler, self.host)); + } // Run any unit tests in the crate let cargo_test = tool::prepare_tool_cargo( diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 304fe8da2bf..8f7ade79403 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -798,6 +798,7 @@ impl<'a> Builder<'a> { tool::Miri, tool::CargoMiri, llvm::Lld, + llvm::Enzyme, llvm::CrtBeginEnd, tool::RustdocGUITest, tool::OptimizedDist, @@ -1588,6 +1589,12 @@ impl<'a> Builder<'a> { rustflags.arg(sysroot_str); } + // https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/.E2.9C.94.20link.20new.20library.20into.20stage1.2Frustc + if self.config.llvm_enzyme { + rustflags.arg("-l"); + rustflags.arg("Enzyme-19"); + } + let use_new_symbol_mangling = match self.config.rust_new_symbol_mangling { Some(setting) => { // If an explicit setting is given, use that @@ -2456,7 +2463,15 @@ impl Cargo { cmd_kind: Kind, ) -> Cargo { let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind); - cargo.configure_linker(builder); + + match cmd_kind { + // No need to configure the target linker for these command types. + Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {} + _ => { + cargo.configure_linker(builder); + } + } + cargo } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f7cc9ee7219..52c1c462788 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -221,6 +221,7 @@ pub struct Config { // llvm codegen options pub llvm_assertions: bool, pub llvm_tests: bool, + pub llvm_enzyme: bool, pub llvm_plugins: bool, pub llvm_optimize: bool, pub llvm_thin_lto: bool, @@ -898,6 +899,7 @@ define_config! { release_debuginfo: Option<bool> = "release-debuginfo", assertions: Option<bool> = "assertions", tests: Option<bool> = "tests", + enzyme: Option<bool> = "enzyme", plugins: Option<bool> = "plugins", ccache: Option<StringOrBool> = "ccache", static_libstdcpp: Option<bool> = "static-libstdcpp", @@ -1603,6 +1605,7 @@ impl Config { // we'll infer default values for them later let mut llvm_assertions = None; let mut llvm_tests = None; + let mut llvm_enzyme = None; let mut llvm_plugins = None; let mut debug = None; let mut debug_assertions = None; @@ -1722,6 +1725,8 @@ impl Config { config.llvm_tools_enabled = llvm_tools.unwrap_or(true); config.rustc_parallel = parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly"); + config.llvm_enzyme = + llvm_enzyme.unwrap_or(config.channel == "dev" || config.channel == "nightly"); config.rustc_default_linker = default_linker; config.musl_root = musl_root.map(PathBuf::from); config.save_toolstates = save_toolstates.map(PathBuf::from); @@ -1806,6 +1811,7 @@ impl Config { release_debuginfo, assertions, tests, + enzyme, plugins, ccache, static_libstdcpp, @@ -1839,6 +1845,7 @@ impl Config { set(&mut config.ninja_in_file, ninja); llvm_assertions = assertions; llvm_tests = tests; + llvm_enzyme = enzyme; llvm_plugins = plugins; set(&mut config.llvm_optimize, optimize_toml); set(&mut config.llvm_thin_lto, thin_lto); @@ -2055,6 +2062,7 @@ impl Config { config.llvm_assertions = llvm_assertions.unwrap_or(false); config.llvm_tests = llvm_tests.unwrap_or(false); + config.llvm_enzyme = llvm_enzyme.unwrap_or(false); config.llvm_plugins = llvm_plugins.unwrap_or(false); config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 1e3f8da5258..3f5ec70b9ab 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -228,25 +228,42 @@ impl Config { fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) { println!("downloading {url}"); // Try curl. If that fails and we are on windows, fallback to PowerShell. + // options should be kept in sync with + // src/bootstrap/src/core/download.rs + // for consistency let mut curl = command("curl"); curl.args([ - "-y", + // follow redirect + "--location", + // timeout if speed is < 10 bytes/sec for > 30 seconds + "--speed-time", "30", - "-Y", - "10", // timeout if speed is < 10 bytes/sec for > 30 seconds + "--speed-limit", + "10", + // timeout if cannot connect within 30 seconds "--connect-timeout", - "30", // timeout if cannot connect within 30 seconds - "-o", + "30", + // output file + "--output", tempfile.to_str().unwrap(), + // if there is an error, don't restart the download, + // instead continue where it left off. "--continue-at", "-", + // retry up to 3 times. note that this means a maximum of 4 + // attempts will be made, since the first attempt isn't a *re*try. "--retry", "3", - "-SRf", + // show errors, even if --silent is specified + "--show-error", + // set timestamp of downloaded file to that of the server + "--remote-time", + // fail on non-ok http status + "--fail", ]); // Don't print progress in CI; the \r wrapping looks bad and downloads don't take long enough for progress to be useful. if CiEnv::is_ci() { - curl.arg("-s"); + curl.arg("--silent"); } else { curl.arg("--progress-bar"); } diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 1016607fc83..d665544f593 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::path::PathBuf; use serde_derive::Deserialize; @@ -21,6 +22,7 @@ struct Package { manifest_path: String, dependencies: Vec<Dependency>, targets: Vec<Target>, + features: BTreeMap<String, Vec<String>>, } /// For more information, see the output of @@ -51,7 +53,13 @@ pub fn build(build: &mut Build) { .map(|dep| dep.name) .collect(); let has_lib = package.targets.iter().any(|t| t.kind.iter().any(|k| k == "lib")); - let krate = Crate { name: name.clone(), deps, path, has_lib }; + let krate = Crate { + name: name.clone(), + deps, + path, + has_lib, + features: package.features.keys().cloned().collect(), + }; let relative_path = krate.local_path(build); build.crates.insert(name.clone(), krate); let existing_path = build.crate_paths.insert(relative_path, name); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 5751c398f30..c76ce340956 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -77,6 +77,9 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; #[allow(clippy::type_complexity)] // It's fine for hard-coded list and type is explained above. const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[ (None, "bootstrap", None), + (Some(Mode::Rustc), "llvm_enzyme", None), + (Some(Mode::Codegen), "llvm_enzyme", None), + (Some(Mode::ToolRustc), "llvm_enzyme", None), (Some(Mode::Rustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "rust_analyzer", None), @@ -140,6 +143,7 @@ pub struct Build { clippy_info: GitInfo, miri_info: GitInfo, rustfmt_info: GitInfo, + enzyme_info: GitInfo, in_tree_llvm_info: GitInfo, local_rebuild: bool, fail_fast: bool, @@ -183,6 +187,7 @@ struct Crate { deps: HashSet<String>, path: PathBuf, has_lib: bool, + features: Vec<String>, } impl Crate { @@ -306,6 +311,7 @@ impl Build { let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); + let enzyme_info = GitInfo::new(omit_git_hash, &src.join("src/tools/enzyme")); // we always try to use git for LLVM builds let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project")); @@ -332,14 +338,20 @@ impl Build { .trim() .to_string(); - let initial_libdir = initial_target_dir - .parent() - .unwrap() - .parent() - .unwrap() - .strip_prefix(&initial_sysroot) - .unwrap() - .to_path_buf(); + // FIXME(Zalathar): Determining this path occasionally fails locally for + // unknown reasons, so we print some extra context to help track down why. + let find_initial_libdir = || { + let initial_libdir = + initial_target_dir.parent()?.parent()?.strip_prefix(&initial_sysroot).ok()?; + Some(initial_libdir.to_path_buf()) + }; + let Some(initial_libdir) = find_initial_libdir() else { + panic!( + "couldn't determine `initial_libdir` \ + from target dir {initial_target_dir:?} \ + and sysroot {initial_sysroot:?}" + ) + }; let version = std::fs::read_to_string(src.join("src").join("version")) .expect("failed to read src/version"); @@ -393,6 +405,7 @@ impl Build { clippy_info, miri_info, rustfmt_info, + enzyme_info, in_tree_llvm_info, cc: RefCell::new(HashMap::new()), cxx: RefCell::new(HashMap::new()), @@ -666,16 +679,24 @@ impl Build { } /// Gets the space-separated set of activated features for the compiler. - fn rustc_features(&self, kind: Kind, target: TargetSelection) -> String { + fn rustc_features(&self, kind: Kind, target: TargetSelection, crates: &[String]) -> String { + let possible_features_by_crates: HashSet<_> = crates + .iter() + .flat_map(|krate| &self.crates[krate].features) + .map(std::ops::Deref::deref) + .collect(); + let check = |feature: &str| -> bool { + crates.is_empty() || possible_features_by_crates.contains(feature) + }; let mut features = vec![]; - if self.config.jemalloc { + if self.config.jemalloc && check("jemalloc") { features.push("jemalloc"); } - if self.config.llvm_enabled(target) || kind == Kind::Check { + if (self.config.llvm_enabled(target) || kind == Kind::Check) && check("llvm") { features.push("llvm"); } // keep in sync with `bootstrap/compile.rs:rustc_cargo_env` - if self.config.rustc_parallel { + if self.config.rustc_parallel && check("rustc_use_parallel_compiler") { features.push("rustc_use_parallel_compiler"); } if self.config.rust_randomize_layout { @@ -687,7 +708,7 @@ impl Build { // which is everything (including debug/trace/etc.) // if its unset, if debug_assertions is on, then debug_logging will also be on // as well as tracing *ignoring* this feature when debug_assertions is on - if !self.config.rust_debug_logging { + if !self.config.rust_debug_logging && check("max_level_info") { features.push("max_level_info"); } @@ -740,6 +761,10 @@ impl Build { } } + fn enzyme_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("enzyme") + } + fn lld_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("lld") } diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 29e6b74aace..a2c7ab31df8 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -87,15 +87,29 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { } pub fn find(build: &Build) { - // For all targets we're going to need a C compiler for building some shims - // and such as well as for being a linker for Rust code. - let targets = build - .targets - .iter() - .chain(&build.hosts) - .cloned() - .chain(iter::once(build.build)) - .collect::<HashSet<_>>(); + let targets: HashSet<_> = match build.config.cmd { + // We don't need to check cross targets for these commands. + crate::Subcommand::Clean { .. } + | crate::Subcommand::Check { .. } + | crate::Subcommand::Suggest { .. } + | crate::Subcommand::Format { .. } + | crate::Subcommand::Setup { .. } => { + build.hosts.iter().cloned().chain(iter::once(build.build)).collect() + } + + _ => { + // For all targets we're going to need a C compiler for building some shims + // and such as well as for being a linker for Rust code. + build + .targets + .iter() + .chain(&build.hosts) + .cloned() + .chain(iter::once(build.build)) + .collect() + } + }; + for target in targets.into_iter() { find_target(build, target); } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 3fec2d953d9..80ab09881fe 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -245,4 +245,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Removed `rust.split-debuginfo` as it was deprecated long time ago.", }, + ChangeInfo { + change_id: 129176, + severity: ChangeSeverity::Info, + summary: "New option `llvm.enzyme` to control whether the llvm based autodiff tool (Enzyme) is built.", + }, ]; diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 29b4889a6ab..e728da67dc2 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -879,7 +879,9 @@ impl<'src> Classifier<'src> { | TokenKind::UnknownPrefix | TokenKind::InvalidPrefix | TokenKind::InvalidIdent => Class::Ident(self.new_span(before, text)), - TokenKind::Lifetime { .. } => Class::Lifetime, + TokenKind::Lifetime { .. } + | TokenKind::RawLifetime + | TokenKind::UnknownPrefixLifetime => Class::Lifetime, TokenKind::Eof => panic!("Eof in advance"), }; // Anything that didn't return above is the simple case where we the diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 60dc142b9ff..b0af8d8c23e 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -29,7 +29,7 @@ use itertools::Itertools; use regex::Regex; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::Symbol; @@ -832,7 +832,7 @@ impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> { // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. let Some(impl_did) = impl_item_id.as_def_id() else { continue }; let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); - let reject_cx = DeepRejectCtxt::new(self.cx.tcx(), TreatParams::AsCandidateKey); + let reject_cx = DeepRejectCtxt::relate_infer_infer(self.cx.tcx()); if !reject_cx.types_may_unify(aliased_ty, for_ty) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index a5da52b0be5..80360697941 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { } fn is_non_trait_box(ty: Ty<'_>) -> bool { - ty.is_box() && !ty.boxed_ty().is_trait() + ty.boxed_ty().is_some_and(|boxed| !boxed.is_trait()) } struct EscapeDelegate<'a, 'tcx> { @@ -191,8 +191,8 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { fn is_large_box(&self, ty: Ty<'tcx>) -> bool { // Large types need to be boxed to avoid stack overflows. - if ty.is_box() { - self.cx.layout_of(ty.boxed_ty()).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack + if let Some(boxed_ty) = ty.boxed_ty() { + self.cx.layout_of(boxed_ty).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index d7126990edb..f61bb3a6bf4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -5187,8 +5187,8 @@ impl SelfKind { fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { if ty == parent_ty { true - } else if ty.is_box() { - ty.boxed_ty() == parent_ty + } else if let Some(boxed_ty) = ty.boxed_ty() { + boxed_ty == parent_ty } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) { if let ty::Adt(_, args) = ty.kind() { args.types().next().map_or(false, |t| t == parent_ty) diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index 0d2b0a31317..fe860e5ae26 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -16,7 +16,7 @@ pub(super) fn derefs_to_slice<'tcx>( fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { match ty.kind() { ty::Slice(_) => true, - ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), + ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => may_slice(cx, boxed), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec), ty::Array(_, size) => size.try_eval_target_usize(cx.tcx, cx.param_env).is_some(), ty::Ref(_, inner, _) => may_slice(cx, *inner), @@ -33,7 +33,7 @@ pub(super) fn derefs_to_slice<'tcx>( } else { match ty.kind() { ty::Slice(_) => Some(expr), - ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), + _ if ty.boxed_ty().is_some_and(|boxed| may_slice(cx, boxed)) => Some(expr), ty::Ref(_, inner, _) => { if may_slice(cx, *inner) { Some(expr) diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 373bf61d8ff..a2ae36cc484 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -619,10 +619,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, &self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) - | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg) + | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) || transmute_undefined_repr::check(cx, e, from_ty, to_ty)) | (eager_transmute::check(cx, e, arg, from_ty, to_ty)); diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs index ab3bb5e1062..cb46109c27e 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -15,10 +15,9 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, mut arg: &'tcx Expr<'_>, - const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => { + (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => { span_lint_and_then( cx, TRANSMUTE_FLOAT_TO_INT, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs index d51888e3097..e00fb90c307 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -14,10 +14,9 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, - const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => { + (ty::Int(_) | ty::Uint(_), ty::Float(_)) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 88b0ac5a368..362f2bb6960 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -14,18 +14,12 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, - const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => { if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) { return false; } - if matches!(from_ty.kind(), ty::Float(_)) && const_context { - // TODO: Remove when const_float_bits_conv is stabilized - // rust#72447 - return false; - } span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index 3f130bf5a67..14f4aa6676b 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -75,11 +75,9 @@ impl UnnecessaryBoxReturns { .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder()) .output(); - if !return_ty.is_box() { + let Some(boxed_ty) = return_ty.boxed_ty() else { return; - } - - let boxed_ty = return_ty.boxed_ty(); + }; // It's sometimes useful to return Box<T> if T is unsized, so don't lint those. // Also, don't lint if we know that T is very large, in which case returning diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index f80981c11af..585134209ca 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -704,8 +704,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS /// If the type is function like, get the signature for it. pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> { - if ty.is_box() { - return ty_sig(cx, ty.boxed_ty()); + if let Some(boxed_ty) = ty.boxed_ty() { + return ty_sig(cx, boxed_ty); } match *ty.kind() { ty::Closure(id, subs) => { diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index 46629526367..eeea3f080b1 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -140,24 +140,32 @@ mod int_to_float { mod issue_5747 { const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; + //~^ ERROR: transmute from a `u16` to a `f16` const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; + //~^ ERROR: transmute from a `u32` to a `f32` const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; + //~^ ERROR: transmute from a `i64` to a `f64` const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; + //~^ ERROR: transmute from a `i128` to a `f128` const fn from_bits_16(v: i16) -> f16 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `i16` to a `f16` } const fn from_bits_32(v: i32) -> f32 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `i32` to a `f32` } const fn from_bits_64(v: u64) -> f64 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `u64` to a `f64` } const fn from_bits_128(v: u128) -> f128 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `u128` to a `f128` } } } @@ -205,9 +213,13 @@ mod num_to_bytes { //~^ ERROR: transmute from a `i128` to a `[u8; 16]` let _: [u8; 2] = std::mem::transmute(0.0f16); + //~^ ERROR: transmute from a `f16` to a `[u8; 2]` let _: [u8; 4] = std::mem::transmute(0.0f32); + //~^ ERROR: transmute from a `f32` to a `[u8; 4]` let _: [u8; 8] = std::mem::transmute(0.0f64); + //~^ ERROR: transmute from a `f64` to a `[u8; 8]` let _: [u8; 16] = std::mem::transmute(0.0f128); + //~^ ERROR: transmute from a `f128` to a `[u8; 16]` } } } diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 0072f62962a..41a10f381dc 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -148,8 +148,56 @@ error: transmute from a `i128` to a `f128` LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` +error: transmute from a `u16` to a `f16` + --> tests/ui/transmute.rs:142:39 + | +LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` + +error: transmute from a `u32` to a `f32` + --> tests/ui/transmute.rs:144:39 + | +LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` + +error: transmute from a `i64` to a `f64` + --> tests/ui/transmute.rs:146:39 + | +LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` + +error: transmute from a `i128` to a `f128` + --> tests/ui/transmute.rs:148:41 + | +LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` + +error: transmute from a `i16` to a `f16` + --> tests/ui/transmute.rs:152:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)` + +error: transmute from a `i32` to a `f32` + --> tests/ui/transmute.rs:157:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)` + +error: transmute from a `u64` to a `f64` + --> tests/ui/transmute.rs:162:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)` + +error: transmute from a `u128` to a `f128` + --> tests/ui/transmute.rs:167:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)` + error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:168:30 + --> tests/ui/transmute.rs:176:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -158,97 +206,121 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:171:30 + --> tests/ui/transmute.rs:179:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:173:31 + --> tests/ui/transmute.rs:181:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:175:30 + --> tests/ui/transmute.rs:183:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:177:30 + --> tests/ui/transmute.rs:185:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:179:31 + --> tests/ui/transmute.rs:187:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:182:30 + --> tests/ui/transmute.rs:190:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:184:30 + --> tests/ui/transmute.rs:192:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:186:30 + --> tests/ui/transmute.rs:194:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:188:31 + --> tests/ui/transmute.rs:196:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:194:30 + --> tests/ui/transmute.rs:202:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:196:30 + --> tests/ui/transmute.rs:204:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:198:31 + --> tests/ui/transmute.rs:206:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:200:30 + --> tests/ui/transmute.rs:208:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:202:30 + --> tests/ui/transmute.rs:210:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:204:31 + --> tests/ui/transmute.rs:212:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` +error: transmute from a `f16` to a `[u8; 2]` + --> tests/ui/transmute.rs:215:30 + | +LL | let _: [u8; 2] = std::mem::transmute(0.0f16); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` + +error: transmute from a `f32` to a `[u8; 4]` + --> tests/ui/transmute.rs:217:30 + | +LL | let _: [u8; 4] = std::mem::transmute(0.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` + +error: transmute from a `f64` to a `[u8; 8]` + --> tests/ui/transmute.rs:219:30 + | +LL | let _: [u8; 8] = std::mem::transmute(0.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` + +error: transmute from a `f128` to a `[u8; 16]` + --> tests/ui/transmute.rs:221:31 + | +LL | let _: [u8; 16] = std::mem::transmute(0.0f128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` + error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:218:28 + --> tests/ui/transmute.rs:230:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -257,16 +329,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:221:32 + --> tests/ui/transmute.rs:233:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:223:30 + --> tests/ui/transmute.rs:235:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 42 previous errors +error: aborting due to 54 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed index 4361a7407d1..83814ca43b9 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128)] -#![feature(f16)] +#![feature(f128, f128_const)] +#![feature(f16, f16_const)] fn float_to_int() { let _: u32 = unsafe { 1f32.to_bits() }; @@ -20,25 +20,33 @@ fn float_to_int() { } mod issue_5747 { - const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; - const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; - const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; - const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + const VALUE16: i16 = unsafe { 1f16.to_bits() as i16 }; + //~^ ERROR: transmute from a `f16` to a `i16` + const VALUE32: i32 = unsafe { 1f32.to_bits() as i32 }; + //~^ ERROR: transmute from a `f32` to a `i32` + const VALUE64: u64 = unsafe { 1f64.to_bits() }; + //~^ ERROR: transmute from a `f64` to a `u64` + const VALUE128: u128 = unsafe { 1f128.to_bits() }; + //~^ ERROR: transmute from a `f128` to a `u128` const fn to_bits_16(v: f16) -> u16 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() } + //~^ ERROR: transmute from a `f16` to a `u16` } const fn to_bits_32(v: f32) -> u32 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() } + //~^ ERROR: transmute from a `f32` to a `u32` } const fn to_bits_64(v: f64) -> i64 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() as i64 } + //~^ ERROR: transmute from a `f64` to a `i64` } const fn to_bits_128(v: f128) -> i128 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() as i128 } + //~^ ERROR: transmute from a `f128` to a `i128` } } diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs index 363ce0bcb16..64d6e917203 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128)] -#![feature(f16)] +#![feature(f128, f128_const)] +#![feature(f16, f16_const)] fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; @@ -21,24 +21,32 @@ fn float_to_int() { mod issue_5747 { const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; + //~^ ERROR: transmute from a `f16` to a `i16` const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; + //~^ ERROR: transmute from a `f32` to a `i32` const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; + //~^ ERROR: transmute from a `f64` to a `u64` const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + //~^ ERROR: transmute from a `f128` to a `u128` const fn to_bits_16(v: f16) -> u16 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f16` to a `u16` } const fn to_bits_32(v: f32) -> u32 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f32` to a `u32` } const fn to_bits_64(v: f64) -> i64 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f64` to a `i64` } const fn to_bits_128(v: f128) -> i128 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f128` to a `i128` } } diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr index 9cac75f72cd..0cabab58ab0 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr @@ -37,5 +37,53 @@ error: transmute from a `f64` to a `u64` LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` -error: aborting due to 6 previous errors +error: transmute from a `f16` to a `i16` + --> tests/ui/transmute_float_to_int.rs:23:35 + | +LL | const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f16.to_bits() as i16` + +error: transmute from a `f32` to a `i32` + --> tests/ui/transmute_float_to_int.rs:25:35 + | +LL | const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` + +error: transmute from a `f64` to a `u64` + --> tests/ui/transmute_float_to_int.rs:27:35 + | +LL | const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` + +error: transmute from a `f128` to a `u128` + --> tests/ui/transmute_float_to_int.rs:29:37 + | +LL | const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f128.to_bits()` + +error: transmute from a `f16` to a `u16` + --> tests/ui/transmute_float_to_int.rs:33:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` + +error: transmute from a `f32` to a `u32` + --> tests/ui/transmute_float_to_int.rs:38:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` + +error: transmute from a `f64` to a `i64` + --> tests/ui/transmute_float_to_int.rs:43:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i64` + +error: transmute from a `f128` to a `i128` + --> tests/ui/transmute_float_to_int.rs:48:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i128` + +error: aborting due to 14 previous errors diff --git a/src/tools/enzyme b/src/tools/enzyme new file mode 160000 +Subproject 2fe5164a2423dd67ef25e2c4fb204fd06362494 diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 72bb9db7e74..532a27b22aa 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -56,6 +56,8 @@ pub struct LintExtractor<'a> { pub rustc_path: &'a Path, /// The target arch to build the docs for. pub rustc_target: &'a str, + /// The target linker overriding `rustc`'s default + pub rustc_linker: Option<&'a str>, /// Verbose output. pub verbose: bool, /// Validate the style and the code example. @@ -459,6 +461,9 @@ impl<'a> LintExtractor<'a> { } cmd.arg("--error-format=json"); cmd.arg("--target").arg(self.rustc_target); + if let Some(target_linker) = self.rustc_linker { + cmd.arg(format!("-Clinker={target_linker}")); + } if options.contains(&"test") { cmd.arg("--test"); } diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 2055fed2b48..e377283b1a4 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -27,6 +27,7 @@ fn doit() -> Result<(), Box<dyn Error>> { let mut out_path = None; let mut rustc_path = None; let mut rustc_target = None; + let mut rustc_linker = None; let mut verbose = false; let mut validate = false; while let Some(arg) = args.next() { @@ -55,6 +56,12 @@ fn doit() -> Result<(), Box<dyn Error>> { None => return Err("--rustc-target requires a value".into()), }; } + "--rustc-linker" => { + rustc_linker = match args.next() { + Some(s) => Some(s), + None => return Err("--rustc-linker requires a value".into()), + }; + } "-v" | "--verbose" => verbose = true, "--validate" => validate = true, s => return Err(format!("unexpected argument `{}`", s).into()), @@ -77,6 +84,7 @@ fn doit() -> Result<(), Box<dyn Error>> { out_path: &out_path.unwrap(), rustc_path: &rustc_path.unwrap(), rustc_target: &rustc_target.unwrap(), + rustc_linker: rustc_linker.as_deref(), verbose, validate, }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index ee15b1b5ce9..5c25a55362e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -464,6 +464,9 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // 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, INTERNAL_UNSTABLE), + // Used by the `rustc::untracked_query_information` lint to warn methods which + // might break incremental compilation. + rustc_attr!(rustc_lint_untracked_query_information, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), // Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints // to assist in changes to diagnostic APIs. rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index ff924830ae0..3590486bd29 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -198,6 +198,13 @@ impl<'a> Converter<'a> { } LIFETIME_IDENT } + rustc_lexer::TokenKind::UnknownPrefixLifetime => { + err = "Unknown lifetime prefix"; + LIFETIME_IDENT + } + rustc_lexer::TokenKind::RawLifetime => { + LIFETIME_IDENT + } rustc_lexer::TokenKind::Semi => T![;], rustc_lexer::TokenKind::Comma => T![,], diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 6ba5217bc92..75c75c523b0 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -462,7 +462,7 @@ fn rewrite_empty_block( return None; } - let label_str = rewrite_label(label); + let label_str = rewrite_label(context, label); if attrs.map_or(false, |a| !inner_attributes(a).is_empty()) { return None; } @@ -527,7 +527,7 @@ fn rewrite_single_line_block( if let Some(block_expr) = stmt::Stmt::from_simple_block(context, block, attrs) { let expr_shape = shape.offset_left(last_line_width(prefix))?; let expr_str = block_expr.rewrite(context, expr_shape)?; - let label_str = rewrite_label(label); + let label_str = rewrite_label(context, label); let result = format!("{prefix}{label_str}{{ {expr_str} }}"); if result.len() <= shape.width && !result.contains('\n') { return Some(result); @@ -562,7 +562,7 @@ pub(crate) fn rewrite_block_with_visitor( } let inner_attrs = attrs.map(inner_attributes); - let label_str = rewrite_label(label); + let label_str = rewrite_label(context, label); visitor.visit_block(block, inner_attrs.as_deref(), has_braces); let visitor_context = visitor.get_context(); context @@ -939,7 +939,7 @@ impl<'a> ControlFlow<'a> { fresh_shape }; - let label_string = rewrite_label(self.label); + let label_string = rewrite_label(context, self.label); // 1 = space after keyword. let offset = self.keyword.len() + label_string.len() + 1; @@ -1168,9 +1168,9 @@ impl<'a> Rewrite for ControlFlow<'a> { } } -fn rewrite_label(opt_label: Option<ast::Label>) -> Cow<'static, str> { +fn rewrite_label(context: &RewriteContext<'_>, opt_label: Option<ast::Label>) -> Cow<'static, str> { match opt_label { - Some(label) => Cow::from(format!("{}: ", label.ident)), + Some(label) => Cow::from(format!("{}: ", context.snippet(label.ident.span))), None => Cow::from(""), } } diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index b14b74a4938..524fc666fae 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -1074,7 +1074,7 @@ fn force_space_before(tok: &TokenKind) -> bool { fn ident_like(tok: &Token) -> bool { matches!( tok.kind, - TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(_) + TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(..) ) } @@ -1099,7 +1099,9 @@ fn next_space(tok: &TokenKind) -> SpaceState { | TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_) => SpaceState::Never, - TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(_) => SpaceState::Ident, + TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(..) => { + SpaceState::Ident + } _ => SpaceState::Always, } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 875c61113c5..7730aa467ce 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -548,7 +548,7 @@ impl Rewrite for ast::AnonConst { impl Rewrite for ast::Lifetime { fn rewrite(&self, context: &RewriteContext<'_>, _: Shape) -> Option<String> { - Some(rewrite_ident(context, self.ident).to_owned()) + Some(context.snippet(self.ident.span).to_owned()) } } diff --git a/src/tools/rustfmt/tests/target/raw-lifetimes.rs b/src/tools/rustfmt/tests/target/raw-lifetimes.rs new file mode 100644 index 00000000000..62fb9be6882 --- /dev/null +++ b/src/tools/rustfmt/tests/target/raw-lifetimes.rs @@ -0,0 +1,15 @@ +// rustfmt-edition: 2021 + +// Simple idempotence test for raw lifetimes. + +fn test<'r#gen>() -> &'r#gen () { + // Test raw lifetimes... +} + +fn label() { + 'r#label: { + // Test raw labels. + } +} + +fn main() {} diff --git a/src/tools/tidy/config/black.toml b/src/tools/tidy/config/black.toml index e73847a93ba..a1e1eef987a 100644 --- a/src/tools/tidy/config/black.toml +++ b/src/tools/tidy/config/black.toml @@ -12,5 +12,6 @@ extend-exclude = """(\ src/llvm-project/|\ src/doc/embedded-book/|\ src/tools/rustc-perf/|\ + src/tools/enzyme/|\ library/backtrace/ )""" diff --git a/src/tools/tidy/config/ruff.toml b/src/tools/tidy/config/ruff.toml index c87c17f7833..2be109010a0 100644 --- a/src/tools/tidy/config/ruff.toml +++ b/src/tools/tidy/config/ruff.toml @@ -16,6 +16,7 @@ extend-exclude = [ "src/llvm-project/", "src/doc/embedded-book/", "library/backtrace/", + "src/tools/enzyme/", "src/tools/rustc-perf/", # Hack: CI runs from a subdirectory under the main checkout "../src/doc/nomicon/", @@ -29,6 +30,7 @@ extend-exclude = [ "../src/llvm-project/", "../src/doc/embedded-book/", "../library/backtrace/", + "../src/tools/enzyme/", "../src/tools/rustc-perf/", ] diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index d4721b5a5fd..4a69022ebdc 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -24,6 +24,7 @@ pub fn filter_dirs(path: &Path) -> bool { "src/tools/rust-analyzer", "src/tools/rustc-perf", "src/tools/rustfmt", + "src/tools/enzyme", "src/doc/book", "src/doc/edition-guide", "src/doc/embedded-book", diff --git a/tests/assembly/asm/aarch64-modifiers.rs b/tests/assembly/asm/aarch64-modifiers.rs index b7ef1d77ea0..a4a41dd96c1 100644 --- a/tests/assembly/asm/aarch64-modifiers.rs +++ b/tests/assembly/asm/aarch64-modifiers.rs @@ -1,6 +1,7 @@ //@ assembly-output: emit-asm //@ compile-flags: -O -C panic=abort //@ compile-flags: --target aarch64-unknown-linux-gnu +//@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: aarch64 #![feature(no_core, lang_items, rustc_attrs)] @@ -29,12 +30,6 @@ macro_rules! check { // -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0 #[no_mangle] pub unsafe extern "C" fn $func() -> i32 { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!($code, out($reg) y); y diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs index f36345670e3..cf1882ba1a2 100644 --- a/tests/assembly/asm/aarch64-types.rs +++ b/tests/assembly/asm/aarch64-types.rs @@ -4,6 +4,7 @@ //@ [aarch64] needs-llvm-components: aarch64 //@ [arm64ec] compile-flags: --target arm64ec-pc-windows-msvc //@ [arm64ec] needs-llvm-components: aarch64 +//@ compile-flags: -Zmerge-functions=disabled #![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch, f16, f128)] #![crate_type = "rlib"] @@ -132,12 +133,6 @@ macro_rules! check { // LLVM issue: <https://github.com/llvm/llvm-project/issues/94434> #[no_mangle] pub unsafe fn $func(inp: &$ty, out: &mut $ty) { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let x = *inp; let y; asm!( @@ -155,12 +150,6 @@ macro_rules! check_reg { // FIXME(f16_f128): See FIXME in `check!` #[no_mangle] pub unsafe fn $func(inp: &$ty, out: &mut $ty) { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let x = *inp; let y; asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); diff --git a/tests/assembly/asm/arm-modifiers.rs b/tests/assembly/asm/arm-modifiers.rs index 0674e169d72..d421e0e6954 100644 --- a/tests/assembly/asm/arm-modifiers.rs +++ b/tests/assembly/asm/arm-modifiers.rs @@ -2,6 +2,7 @@ //@ compile-flags: -O -C panic=abort //@ compile-flags: --target armv7-unknown-linux-gnueabihf //@ compile-flags: -C target-feature=+neon +//@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: arm #![feature(no_core, lang_items, rustc_attrs, repr_simd)] @@ -40,12 +41,6 @@ macro_rules! check { // -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0 #[no_mangle] pub unsafe extern "C" fn $func() -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); y diff --git a/tests/assembly/asm/arm-types.rs b/tests/assembly/asm/arm-types.rs index eeff1a070b4..448b92aa839 100644 --- a/tests/assembly/asm/arm-types.rs +++ b/tests/assembly/asm/arm-types.rs @@ -2,6 +2,7 @@ //@ assembly-output: emit-asm //@ compile-flags: --target armv7-unknown-linux-gnueabihf //@ compile-flags: -C opt-level=0 +//@ compile-flags: -Zmerge-functions=disabled //@[d32] compile-flags: -C target-feature=+d32 //@[neon] compile-flags: -C target-feature=+neon --cfg d32 //@[neon] filecheck-flags: --check-prefix d32 @@ -114,12 +115,6 @@ macro_rules! check { ($func:ident $ty:ident $class:ident $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); y @@ -131,12 +126,6 @@ macro_rules! check_reg { ($func:ident $ty:ident $reg:tt $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); y diff --git a/tests/assembly/asm/hexagon-types.rs b/tests/assembly/asm/hexagon-types.rs index 269c7582a1c..9389fcf9cba 100644 --- a/tests/assembly/asm/hexagon-types.rs +++ b/tests/assembly/asm/hexagon-types.rs @@ -1,5 +1,6 @@ //@ assembly-output: emit-asm //@ compile-flags: --target hexagon-unknown-linux-musl +//@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: hexagon #![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] @@ -41,12 +42,6 @@ macro_rules! check { ($func:ident $ty:ident $class:ident) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!("{} = {}", out($class) y, in($class) x); y @@ -58,12 +53,6 @@ macro_rules! check_reg { ($func:ident $ty:ident $reg:tt) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); y @@ -77,12 +66,6 @@ macro_rules! check_reg { // CHECK: InlineAsm End #[no_mangle] pub unsafe fn sym_static() { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - asm!("r0 = #{}", sym extern_static); } @@ -92,12 +75,6 @@ pub unsafe fn sym_static() { // CHECK: InlineAsm End #[no_mangle] pub unsafe fn sym_fn() { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - asm!("r0 = #{}", sym extern_func); } diff --git a/tests/assembly/asm/loongarch-type.rs b/tests/assembly/asm/loongarch-type.rs index e4c46cfcf81..1b097f41105 100644 --- a/tests/assembly/asm/loongarch-type.rs +++ b/tests/assembly/asm/loongarch-type.rs @@ -1,5 +1,6 @@ //@ assembly-output: emit-asm //@ compile-flags: --target loongarch64-unknown-linux-gnu +//@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: loongarch #![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)] @@ -39,11 +40,6 @@ extern "C" { static extern_static: u8; } -// Hack to avoid function merging -extern "Rust" { - fn dont_merge(s: &str); -} - // CHECK-LABEL: sym_fn: // CHECK: #APP // CHECK: pcalau12i $t0, %got_pc_hi20(extern_func) @@ -67,8 +63,6 @@ pub unsafe fn sym_static() { macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); y @@ -78,8 +72,6 @@ macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); y diff --git a/tests/assembly/asm/mips-types.rs b/tests/assembly/asm/mips-types.rs index bd62f4a5236..f40a28be4a7 100644 --- a/tests/assembly/asm/mips-types.rs +++ b/tests/assembly/asm/mips-types.rs @@ -4,6 +4,7 @@ //@[mips32] needs-llvm-components: mips //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 //@[mips64] needs-llvm-components: mips +//@ compile-flags: -Zmerge-functions=disabled #![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] #![crate_type = "rlib"] @@ -43,16 +44,9 @@ extern "C" { static extern_static: u8; } -// Hack to avoid function merging -extern "Rust" { - fn dont_merge(s: &str); -} - macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); y @@ -62,8 +56,6 @@ macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); y diff --git a/tests/assembly/asm/powerpc-types.rs b/tests/assembly/asm/powerpc-types.rs index bc8af08ad11..85321e5f345 100644 --- a/tests/assembly/asm/powerpc-types.rs +++ b/tests/assembly/asm/powerpc-types.rs @@ -4,6 +4,7 @@ //@[powerpc] needs-llvm-components: powerpc //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu //@[powerpc64] needs-llvm-components: powerpc +//@ compile-flags: -Zmerge-functions=disabled #![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] #![crate_type = "rlib"] @@ -43,16 +44,9 @@ extern "C" { static extern_static: u8; } -// Hack to avoid function merging -extern "Rust" { - fn dont_merge(s: &str); -} - macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); y @@ -62,8 +56,6 @@ macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { macro_rules! check_reg { ($func:ident, $ty:ty, $rego:tt, $regc:tt, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " ", $rego, ", ", $rego), lateout($regc) y, in($regc) x); y diff --git a/tests/assembly/asm/riscv-types.rs b/tests/assembly/asm/riscv-types.rs index 51b3aaf99d9..1f5d7d85b0a 100644 --- a/tests/assembly/asm/riscv-types.rs +++ b/tests/assembly/asm/riscv-types.rs @@ -27,6 +27,7 @@ //@[riscv32-zfh] filecheck-flags: --check-prefix zfhmin //@ compile-flags: -C target-feature=+d +//@ compile-flags: -Zmerge-functions=disabled #![feature(no_core, lang_items, rustc_attrs, f16)] #![crate_type = "rlib"] @@ -90,12 +91,6 @@ macro_rules! check { ($func:ident $ty:ident $class:ident $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); y @@ -107,12 +102,6 @@ macro_rules! check_reg { ($func:ident $ty:ident $reg:tt $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); y diff --git a/tests/assembly/asm/s390x-types.rs b/tests/assembly/asm/s390x-types.rs index 661907360bd..e68b18d7aa6 100644 --- a/tests/assembly/asm/s390x-types.rs +++ b/tests/assembly/asm/s390x-types.rs @@ -2,6 +2,7 @@ //@ assembly-output: emit-asm //@[s390x] compile-flags: --target s390x-unknown-linux-gnu //@[s390x] needs-llvm-components: systemz +//@ compile-flags: -Zmerge-functions=disabled #![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] #![crate_type = "rlib"] @@ -42,16 +43,9 @@ extern "C" { static extern_static: u8; } -// Hack to avoid function merging -extern "Rust" { - fn dont_merge(s: &str); -} - macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); y @@ -61,8 +55,6 @@ macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " %", $reg, ", %", $reg), lateout($reg) y, in($reg) x); y diff --git a/tests/assembly/asm/x86-modifiers.rs b/tests/assembly/asm/x86-modifiers.rs index c5e393b1056..5a48af9205f 100644 --- a/tests/assembly/asm/x86-modifiers.rs +++ b/tests/assembly/asm/x86-modifiers.rs @@ -7,6 +7,7 @@ //@[i686] needs-llvm-components: x86 //@ compile-flags: -C llvm-args=--x86-asm-syntax=intel //@ compile-flags: -C target-feature=+avx512bw +//@ compile-flags: -Zmerge-functions=disabled #![feature(no_core, lang_items, rustc_attrs)] #![crate_type = "rlib"] @@ -38,12 +39,6 @@ macro_rules! check { // -O and extern "C" guarantee that the selected register is always ax/xmm0 #[no_mangle] pub unsafe extern "C" fn $func() -> i32 { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); y diff --git a/tests/assembly/asm/x86-types.rs b/tests/assembly/asm/x86-types.rs index 8e229614420..a40bc10d991 100644 --- a/tests/assembly/asm/x86-types.rs +++ b/tests/assembly/asm/x86-types.rs @@ -6,6 +6,7 @@ //@[i686] needs-llvm-components: x86 //@ compile-flags: -C llvm-args=--x86-asm-syntax=intel //@ compile-flags: -C target-feature=+avx512bw +//@ compile-flags: -Zmerge-functions=disabled #![feature(no_core, lang_items, rustc_attrs, repr_simd, f16, f128)] #![crate_type = "rlib"] @@ -283,12 +284,6 @@ macro_rules! check { ($func:ident $ty:ident $class:ident $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " {}, {}"), lateout($class) y, in($class) x); y @@ -300,12 +295,6 @@ macro_rules! check_reg { ($func:ident $ty:ident $reg:tt $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); y diff --git a/tests/assembly/s390x-backchain-toggle.rs b/tests/assembly/s390x-backchain-toggle.rs new file mode 100644 index 00000000000..8b6d0cf2123 --- /dev/null +++ b/tests/assembly/s390x-backchain-toggle.rs @@ -0,0 +1,46 @@ +//@ revisions: enable-backchain disable-backchain +//@ assembly-output: emit-asm +//@ compile-flags: -O --crate-type=lib --target=s390x-unknown-linux-gnu +//@ needs-llvm-components: systemz +//@[enable-backchain] compile-flags: -Ctarget-feature=+backchain +//@[disable-backchain] compile-flags: -Ctarget-feature=-backchain +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +extern "C" { + fn extern_func(); +} + +// CHECK-LABEL: test_backchain +#[no_mangle] +extern "C" fn test_backchain() -> i32 { + // Here we try to match if backchain register is saved to the parameter area (stored in r15/sp) + // And also if a new parameter area (160 bytes) is allocated for the upcoming function call + // enable-backchain: lgr [[REG1:.*]], %r15 + // enable-backchain-NEXT: aghi %r15, -160 + // enable-backchain: stg [[REG1]], 0(%r15) + // disable-backchain: aghi %r15, -160 + // disable-backchain-NOT: stg %r{{.*}}, 0(%r15) + unsafe { + extern_func(); + } + // enable-backchain-NEXT: brasl %r{{.*}}, extern_func@PLT + // disable-backchain: brasl %r{{.*}}, extern_func@PLT + + // Make sure that the expected return value is written into %r2 (return register): + // enable-backchain-NEXT: lghi %r2, 1 + // disable-backchain: lghi %r2, 0 + #[cfg(target_feature = "backchain")] + { + 1 + } + #[cfg(not(target_feature = "backchain"))] + { + 0 + } + // CHECK: br %r{{.*}} +} diff --git a/tests/codegen/intrinsics/likely.rs b/tests/codegen/intrinsics/likely.rs index 098fd9936ce..9dc31d21045 100644 --- a/tests/codegen/intrinsics/likely.rs +++ b/tests/codegen/intrinsics/likely.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -C no-prepopulate-passes +//@ compile-flags: -C no-prepopulate-passes -Copt-level=1 #![crate_type = "lib"] #![feature(core_intrinsics)] diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs new file mode 100644 index 00000000000..a45b95780f7 --- /dev/null +++ b/tests/codegen/naked-asan.rs @@ -0,0 +1,22 @@ +// Make sure we do not request sanitizers for naked functions. + +//@ only-x86_64 +//@ needs-sanitizer-address +//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static + +#![crate_type = "lib"] +#![no_std] +#![feature(abi_x86_interrupt, naked_functions)] + +// CHECK: define x86_intrcc void @page_fault_handler(ptr {{.*}}%0, i64 {{.*}}%1){{.*}}#[[ATTRS:[0-9]+]] { +// CHECK-NOT: memcpy +#[naked] +#[no_mangle] +pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { + unsafe { + core::arch::asm!("ud2", options(noreturn)); + } +} + +// CHECK: #[[ATTRS]] = +// CHECK-NOT: sanitize_address diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index 9e5a4bdc60f..1ba165f1e49 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -92,20 +92,18 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 25, 1) to (start + 0, 23) Function name: async::g::{closure#0} (unused) -Raw bytes (69): 0x[01, 01, 00, 0d, 00, 19, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (59): 0x[01, 01, 00, 0b, 00, 19, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 13 +Number of file 0 mappings: 11 - Code(Zero) at (prev + 25, 23) to (start + 1, 12) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Zero) at (prev + 0, 14) to (start + 0, 17) -- Code(Zero) at (prev + 0, 18) to (start + 0, 23) +- Code(Zero) at (prev + 0, 14) to (start + 0, 23) - Code(Zero) at (prev + 0, 27) to (start + 0, 28) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Zero) at (prev + 1, 9) to (start + 0, 10) -- Code(Zero) at (prev + 0, 14) to (start + 0, 17) -- Code(Zero) at (prev + 0, 18) to (start + 0, 23) +- Code(Zero) at (prev + 0, 14) to (start + 0, 23) - Code(Zero) at (prev + 0, 27) to (start + 0, 28) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) @@ -120,15 +118,14 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 0, 22) Function name: async::h::{closure#0} (unused) -Raw bytes (44): 0x[01, 01, 00, 08, 00, 21, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 13, 00, 00, 14, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (39): 0x[01, 01, 00, 07, 00, 21, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 8 +Number of file 0 mappings: 7 - Code(Zero) at (prev + 33, 22) to (start + 3, 12) - Code(Zero) at (prev + 4, 9) to (start + 0, 10) -- Code(Zero) at (prev + 0, 14) to (start + 0, 19) -- Code(Zero) at (prev + 0, 20) to (start + 0, 25) +- Code(Zero) at (prev + 0, 14) to (start + 0, 25) - Code(Zero) at (prev + 0, 26) to (start + 0, 27) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) @@ -143,28 +140,25 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 42, 1) to (start + 0, 19) Function name: async::i::{closure#0} -Raw bytes (78): 0x[01, 01, 02, 07, 21, 19, 1d, 0e, 01, 2a, 13, 04, 0c, 0d, 05, 09, 00, 0a, 01, 00, 0e, 00, 12, 05, 00, 13, 00, 18, 09, 00, 1c, 00, 21, 0d, 00, 27, 00, 2a, 15, 00, 2b, 00, 30, 1d, 01, 09, 00, 0a, 11, 00, 0e, 00, 11, 25, 00, 12, 00, 17, 29, 00, 1b, 00, 20, 1d, 00, 24, 00, 26, 21, 01, 0e, 00, 10, 03, 02, 01, 00, 02] +Raw bytes (63): 0x[01, 01, 02, 07, 19, 11, 15, 0b, 01, 2a, 13, 04, 0c, 09, 05, 09, 00, 0a, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 0d, 00, 0e, 00, 17, 1d, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 19, 01, 0e, 00, 10, 03, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(8) -- expression 1 operands: lhs = Counter(6), rhs = Counter(7) -Number of file 0 mappings: 14 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(6) +- expression 1 operands: lhs = Counter(4), rhs = Counter(5) +Number of file 0 mappings: 11 - Code(Counter(0)) at (prev + 42, 19) to (start + 4, 12) -- Code(Counter(3)) at (prev + 5, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 18) -- Code(Counter(1)) at (prev + 0, 19) to (start + 0, 24) -- Code(Counter(2)) at (prev + 0, 28) to (start + 0, 33) -- Code(Counter(3)) at (prev + 0, 39) to (start + 0, 42) -- Code(Counter(5)) at (prev + 0, 43) to (start + 0, 48) -- Code(Counter(7)) at (prev + 1, 9) to (start + 0, 10) -- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 17) -- Code(Counter(9)) at (prev + 0, 18) to (start + 0, 23) -- Code(Counter(10)) at (prev + 0, 27) to (start + 0, 32) -- Code(Counter(7)) at (prev + 0, 36) to (start + 0, 38) -- Code(Counter(8)) at (prev + 1, 14) to (start + 0, 16) +- Code(Counter(2)) at (prev + 5, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 24) +- Code(Counter(1)) at (prev + 0, 28) to (start + 0, 33) +- Code(Counter(2)) at (prev + 0, 39) to (start + 0, 48) +- Code(Counter(5)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 23) +- Code(Counter(7)) at (prev + 0, 27) to (start + 0, 32) +- Code(Counter(5)) at (prev + 0, 36) to (start + 0, 38) +- Code(Counter(6)) at (prev + 1, 14) to (start + 0, 16) - Code(Expression(0, Add)) at (prev + 2, 1) to (start + 0, 2) - = ((c6 + c7) + c8) + = ((c4 + c5) + c6) Function name: async::j Raw bytes (58): 0x[01, 01, 02, 07, 0d, 05, 09, 0a, 01, 35, 01, 00, 0d, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02] diff --git a/tests/coverage/async.coverage b/tests/coverage/async.coverage index f5473829b02..995674257c4 100644 --- a/tests/coverage/async.coverage +++ b/tests/coverage/async.coverage @@ -45,9 +45,9 @@ LL| 1| // executed asynchronously. LL| 1| match x { LL| 1| y if c(x).await == y + 1 => { d().await; } - ^0 ^0 ^0 ^0 + ^0 ^0 LL| 1| y if f().await == y + 1 => (), - ^0 ^0 ^0 + ^0 ^0 LL| 1| _ => (), LL| | } LL| 1|} diff --git a/tests/coverage/await_ready.cov-map b/tests/coverage/await_ready.cov-map new file mode 100644 index 00000000000..0c9f2ae29a8 --- /dev/null +++ b/tests/coverage/await_ready.cov-map @@ -0,0 +1,25 @@ +Function name: await_ready::await_ready +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 00, 1e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 30) + +Function name: await_ready::await_ready::{closure#0} +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0a, 1e, 03, 0f, 05, 04, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 10, 30) to (start + 3, 15) +- Code(Counter(1)) at (prev + 4, 1) to (start + 0, 2) + +Function name: await_ready::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 10, 01, 03, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 16, 1) to (start + 3, 2) + diff --git a/tests/coverage/await_ready.coverage b/tests/coverage/await_ready.coverage new file mode 100644 index 00000000000..0075f09426e --- /dev/null +++ b/tests/coverage/await_ready.coverage @@ -0,0 +1,38 @@ + LL| |#![feature(coverage_attribute)] + LL| |#![feature(custom_inner_attributes)] // for #![rustfmt::skip] + LL| |#![feature(noop_waker)] + LL| |#![rustfmt::skip] + LL| |//@ edition: 2021 + LL| | + LL| |#[coverage(off)] + LL| |async fn ready() -> u8 { 1 } + LL| | + LL| 1|async fn await_ready() -> u8 { + LL| 1| // await should be covered even if the function never yields + LL| 1| ready() + LL| 1| .await + LL| 1|} + LL| | + LL| 1|fn main() { + LL| 1| let mut future = Box::pin(await_ready()); + LL| 1| executor::block_on(future.as_mut()); + LL| 1|} + LL| | + LL| |mod executor { + LL| | use core::future::Future; + LL| | use core::pin::pin; + LL| | use core::task::{Context, Poll, Waker}; + LL| | + LL| | #[coverage(off)] + LL| | pub fn block_on<F: Future>(mut future: F) -> F::Output { + LL| | let mut future = pin!(future); + LL| | let mut context = Context::from_waker(Waker::noop()); + LL| | + LL| | loop { + LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + LL| | break val; + LL| | } + LL| | } + LL| | } + LL| |} + diff --git a/tests/coverage/await_ready.rs b/tests/coverage/await_ready.rs new file mode 100644 index 00000000000..9212a4ba705 --- /dev/null +++ b/tests/coverage/await_ready.rs @@ -0,0 +1,37 @@ +#![feature(coverage_attribute)] +#![feature(custom_inner_attributes)] // for #![rustfmt::skip] +#![feature(noop_waker)] +#![rustfmt::skip] +//@ edition: 2021 + +#[coverage(off)] +async fn ready() -> u8 { 1 } + +async fn await_ready() -> u8 { + // await should be covered even if the function never yields + ready() + .await +} + +fn main() { + let mut future = Box::pin(await_ready()); + executor::block_on(future.as_mut()); +} + +mod executor { + use core::future::Future; + use core::pin::pin; + use core::task::{Context, Poll, Waker}; + + #[coverage(off)] + pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = pin!(future); + let mut context = Context::from_waker(Waker::noop()); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/tests/crashes/118987.rs b/tests/crashes/118987.rs deleted file mode 100644 index 4382a7bcb63..00000000000 --- a/tests/crashes/118987.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #118987 -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete - -trait Assoc { - type Output; -} - -default impl<T: Clone> Assoc for T { - type Output = bool; -} - -impl Assoc for u8 {} - -trait Foo {} - -impl Foo for <u8 as Assoc>::Output {} -impl Foo for <u16 as Assoc>::Output {} diff --git a/tests/crashes/123629.rs b/tests/crashes/123629.rs new file mode 100644 index 00000000000..61532321806 --- /dev/null +++ b/tests/crashes/123629.rs @@ -0,0 +1,10 @@ +//@ known-bug: #123629 +#![feature(generic_assert)] + +fn foo() +where + for<const N: usize = { assert!(u) }> ():, +{ +} + +fn main() {} diff --git a/tests/crashes/127033.rs b/tests/crashes/127033.rs new file mode 100644 index 00000000000..919c9dfd30e --- /dev/null +++ b/tests/crashes/127033.rs @@ -0,0 +1,18 @@ +//@ known-bug: #127033 +//@ compile-flags: --edition=2021 + +pub trait RaftLogStorage { + fn save_vote(vote: ()) -> impl std::future::Future + Send; +} + +struct X; +impl RaftLogStorage for X { + fn save_vote(vote: ()) -> impl std::future::Future { + loop {} + async { + vote + } + } +} + +fn main() {} diff --git a/tests/crashes/129372.rs b/tests/crashes/129372.rs new file mode 100644 index 00000000000..43be01b35df --- /dev/null +++ b/tests/crashes/129372.rs @@ -0,0 +1,52 @@ +//@ known-bug: #129372 +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 + +pub struct Wrapper<T>(T); +struct Struct; + +pub trait TraitA { + type AssocA<'t>; +} +pub trait TraitB { + type AssocB; +} + +pub fn helper(v: impl MethodTrait) { + let _local_that_causes_ice = v.method(); +} + +pub fn main() { + helper(Wrapper(Struct)); +} + +pub trait MethodTrait { + type Assoc<'a>; + + fn method(self) -> impl for<'a> FnMut(&'a ()) -> Self::Assoc<'a>; +} + +impl<T: TraitB> MethodTrait for T +where + <T as TraitB>::AssocB: TraitA, +{ + type Assoc<'a> = <T::AssocB as TraitA>::AssocA<'a>; + + fn method(self) -> impl for<'a> FnMut(&'a ()) -> Self::Assoc<'a> { + move |_| loop {} + } +} + +impl<T, B> TraitB for Wrapper<B> +where + B: TraitB<AssocB = T>, +{ + type AssocB = T; +} + +impl TraitB for Struct { + type AssocB = Struct; +} + +impl TraitA for Struct { + type AssocA<'t> = Self; +} diff --git a/tests/ui-fulldeps/internal-lints/query_completeness.rs b/tests/ui-fulldeps/internal-lints/query_completeness.rs new file mode 100644 index 00000000000..50b0fb4c3fc --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/query_completeness.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Z unstable-options +// #[cfg(bootstrap)]: We can stop ignoring next beta bump; afterward this ALWAYS should run. +//@ ignore-stage1 (requires matching sysroot built with in-tree compiler) +#![feature(rustc_private)] +#![deny(rustc::untracked_query_information)] + +extern crate rustc_data_structures; + +use rustc_data_structures::steal::Steal; + +fn use_steal(x: Steal<()>) { + let _ = x.is_stolen(); + //~^ ERROR `is_stolen` accesses information that is not tracked by the query system +} + +fn main() {} diff --git a/tests/ui-fulldeps/internal-lints/query_completeness.stderr b/tests/ui-fulldeps/internal-lints/query_completeness.stderr new file mode 100644 index 00000000000..35bb867f40e --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/query_completeness.stderr @@ -0,0 +1,15 @@ +error: `is_stolen` accesses information that is not tracked by the query system + --> $DIR/query_completeness.rs:12:15 + | +LL | let _ = x.is_stolen(); + | ^^^^^^^^^ + | + = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale +note: the lint level is defined here + --> $DIR/query_completeness.rs:5:9 + | +LL | #![deny(rustc::untracked_query_information)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/asm/const-refs-to-static.rs b/tests/ui/asm/const-refs-to-static.rs new file mode 100644 index 00000000000..9fc010b5763 --- /dev/null +++ b/tests/ui/asm/const-refs-to-static.rs @@ -0,0 +1,21 @@ +//@ needs-asm-support +//@ ignore-nvptx64 +//@ ignore-spirv + +#![feature(const_refs_to_static)] + +use std::arch::{asm, global_asm}; +use std::ptr::addr_of; + +static FOO: u8 = 42; + +global_asm!("{}", const addr_of!(FOO)); +//~^ ERROR invalid type for `const` operand + +#[no_mangle] +fn inline() { + unsafe { asm!("{}", const addr_of!(FOO)) }; + //~^ ERROR invalid type for `const` operand +} + +fn main() {} diff --git a/tests/ui/asm/const-refs-to-static.stderr b/tests/ui/asm/const-refs-to-static.stderr new file mode 100644 index 00000000000..8fd69da0d1e --- /dev/null +++ b/tests/ui/asm/const-refs-to-static.stderr @@ -0,0 +1,22 @@ +error: invalid type for `const` operand + --> $DIR/const-refs-to-static.rs:12:19 + | +LL | global_asm!("{}", const addr_of!(FOO)); + | ^^^^^^------------- + | | + | is a `*const u8` + | + = help: `const` operands must be of an integer type + +error: invalid type for `const` operand + --> $DIR/const-refs-to-static.rs:17:25 + | +LL | unsafe { asm!("{}", const addr_of!(FOO)) }; + | ^^^^^^------------- + | | + | is a `*const u8` + | + = help: `const` operands must be of an integer type + +error: aborting due to 2 previous errors + diff --git a/tests/ui/associated-types/associated-types-coherence-failure.stderr b/tests/ui/associated-types/associated-types-coherence-failure.stderr index 211613b3714..25c22e5f82a 100644 --- a/tests/ui/associated-types/associated-types-coherence-failure.stderr +++ b/tests/ui/associated-types/associated-types-coherence-failure.stderr @@ -1,20 +1,20 @@ -error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `Cow<'_, _>` +error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `<_ as ToOwned>::Owned` --> $DIR/associated-types-coherence-failure.rs:21:1 | LL | impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned { | ----------------------------------------------------------------------------- first implementation here ... LL | impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Cow<'_, _>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<_ as ToOwned>::Owned` -error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `&_` +error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `<_ as ToOwned>::Owned` --> $DIR/associated-types-coherence-failure.rs:28:1 | LL | impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned { | ----------------------------------------------------------------------------- first implementation here ... LL | impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<_ as ToOwned>::Owned` error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/async-closures/tainted-body-2.rs b/tests/ui/async-await/async-closures/tainted-body-2.rs new file mode 100644 index 00000000000..73c6bdc30a0 --- /dev/null +++ b/tests/ui/async-await/async-closures/tainted-body-2.rs @@ -0,0 +1,18 @@ +//@ edition: 2021 + +#![feature(async_closure)] + +// Ensure that building a by-ref async closure body doesn't ICE when the parent +// body is tainted. + +fn main() { + missing; + //~^ ERROR cannot find value `missing` in this scope + + // We don't do numerical inference fallback when the body is tainted. + // This leads to writeback folding the type of the coroutine-closure + // into an error type, since its signature contains that numerical + // infer var. + let c = async |_| {}; + c(1); +} diff --git a/tests/ui/async-await/async-closures/tainted-body-2.stderr b/tests/ui/async-await/async-closures/tainted-body-2.stderr new file mode 100644 index 00000000000..798d47064d9 --- /dev/null +++ b/tests/ui/async-await/async-closures/tainted-body-2.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `missing` in this scope + --> $DIR/tainted-body-2.rs:9:5 + | +LL | missing; + | ^^^^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/async-await/async-closures/validate-synthetic-body.rs b/tests/ui/async-await/async-closures/validate-synthetic-body.rs new file mode 100644 index 00000000000..67e683ac08a --- /dev/null +++ b/tests/ui/async-await/async-closures/validate-synthetic-body.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ edition: 2021 + +#![feature(async_closure)] + +// Make sure that we don't hit a query cycle when validating +// the by-move coroutine body for an async closure. + +use std::future::Future; + +async fn test<Fut: Future>(operation: impl Fn() -> Fut) { + operation().await; +} + +pub async fn orchestrate_simple_crud() { + test(async || async {}.await).await; +} + +fn main() {} diff --git a/tests/ui/auto-traits/opaque_type_candidate_selection.rs b/tests/ui/auto-traits/opaque_type_candidate_selection.rs deleted file mode 100644 index d6973b76a6e..00000000000 --- a/tests/ui/auto-traits/opaque_type_candidate_selection.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! used to ICE: #119272 - -//@ check-pass - -#![feature(type_alias_impl_trait)] -mod defining_scope { - use super::*; - pub type Alias<T> = impl Sized; - - pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> { - x - } -} - -struct Container<T: Trait<U>, U> { - x: <T as Trait<U>>::Assoc, -} - -trait Trait<T> { - type Assoc; -} - -impl<T> Trait<T> for T { - type Assoc = Box<u32>; -} -impl<T> Trait<T> for defining_scope::Alias<T> { - type Assoc = usize; -} - -fn main() {} diff --git a/tests/ui/coherence/coherence-negative-outlives-lifetimes.stock.stderr b/tests/ui/coherence/coherence-negative-outlives-lifetimes.stock.stderr index dbb22d8937d..1d28bb46812 100644 --- a/tests/ui/coherence/coherence-negative-outlives-lifetimes.stock.stderr +++ b/tests/ui/coherence/coherence-negative-outlives-lifetimes.stock.stderr @@ -5,6 +5,8 @@ LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {} | ---------------------------------------------- first implementation here LL | impl<'a, T> MyTrait<'a> for &'a T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + | + = note: downstream crates may implement trait `MyPredicate<'_>` for type `&_` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr b/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr index dbb22d8937d..1d28bb46812 100644 --- a/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr +++ b/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr @@ -5,6 +5,8 @@ LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {} | ---------------------------------------------- first implementation here LL | impl<'a, T> MyTrait<'a> for &'a T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + | + = note: downstream crates may implement trait `MyPredicate<'_>` for type `&_` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-overlap-downstream-inherent.old.stderr b/tests/ui/coherence/coherence-overlap-downstream-inherent.old.stderr deleted file mode 100644 index 2938bc629b2..00000000000 --- a/tests/ui/coherence/coherence-overlap-downstream-inherent.old.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0592]: duplicate definitions with name `dummy` - --> $DIR/coherence-overlap-downstream-inherent.rs:10:26 - | -LL | impl<T:Sugar> Sweet<T> { fn dummy(&self) { } } - | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy` -LL | -LL | impl<T:Fruit> Sweet<T> { fn dummy(&self) { } } - | --------------- other definition for `dummy` - -error[E0592]: duplicate definitions with name `f` - --> $DIR/coherence-overlap-downstream-inherent.rs:16:38 - | -LL | impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } - | ^^^^^^^^^^^ duplicate definitions for `f` -LL | -LL | impl<X> A<i32, X> { fn f(&self) {} } - | ----------- other definition for `f` - | - = note: downstream crates may implement trait `Bar<_>` for type `i32` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0592`. diff --git a/tests/ui/coherence/coherence-overlap-downstream-inherent.rs b/tests/ui/coherence/coherence-overlap-downstream-inherent.rs index 3e90b7c7fdd..5dea33e330b 100644 --- a/tests/ui/coherence/coherence-overlap-downstream-inherent.rs +++ b/tests/ui/coherence/coherence-overlap-downstream-inherent.rs @@ -1,6 +1,3 @@ -//@ revisions: old next -//@[next] compile-flags: -Znext-solver - // Tests that we consider `T: Sugar + Fruit` to be ambiguous, even // though no impls are found. diff --git a/tests/ui/coherence/coherence-overlap-downstream-inherent.next.stderr b/tests/ui/coherence/coherence-overlap-downstream-inherent.stderr index 2938bc629b2..bbce4b530b4 100644 --- a/tests/ui/coherence/coherence-overlap-downstream-inherent.next.stderr +++ b/tests/ui/coherence/coherence-overlap-downstream-inherent.stderr @@ -1,5 +1,5 @@ error[E0592]: duplicate definitions with name `dummy` - --> $DIR/coherence-overlap-downstream-inherent.rs:10:26 + --> $DIR/coherence-overlap-downstream-inherent.rs:7:26 | LL | impl<T:Sugar> Sweet<T> { fn dummy(&self) { } } | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy` @@ -8,7 +8,7 @@ LL | impl<T:Fruit> Sweet<T> { fn dummy(&self) { } } | --------------- other definition for `dummy` error[E0592]: duplicate definitions with name `f` - --> $DIR/coherence-overlap-downstream-inherent.rs:16:38 + --> $DIR/coherence-overlap-downstream-inherent.rs:13:38 | LL | impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } | ^^^^^^^^^^^ duplicate definitions for `f` diff --git a/tests/ui/coherence/coherence-overlap-downstream.next.stderr b/tests/ui/coherence/coherence-overlap-downstream.next.stderr deleted file mode 100644 index 6c2e9466b4b..00000000000 --- a/tests/ui/coherence/coherence-overlap-downstream.next.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0119]: conflicting implementations of trait `Sweet` - --> $DIR/coherence-overlap-downstream.rs:11:1 - | -LL | impl<T:Sugar> Sweet for T { } - | ------------------------- first implementation here -LL | impl<T:Fruit> Sweet for T { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation - -error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32` - --> $DIR/coherence-overlap-downstream.rs:17:1 - | -LL | impl<X, T> Foo<X> for T where T: Bar<X> {} - | --------------------------------------- first implementation here -LL | impl<X> Foo<X> for i32 {} - | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` - | - = note: downstream crates may implement trait `Bar<_>` for type `i32` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-overlap-downstream.rs b/tests/ui/coherence/coherence-overlap-downstream.rs index 8b99296d12a..738ec0e3d45 100644 --- a/tests/ui/coherence/coherence-overlap-downstream.rs +++ b/tests/ui/coherence/coherence-overlap-downstream.rs @@ -1,6 +1,3 @@ -//@ revisions: old next -//@[next] compile-flags: -Znext-solver - // Tests that we consider `T: Sugar + Fruit` to be ambiguous, even // though no impls are found. diff --git a/tests/ui/coherence/coherence-overlap-downstream.old.stderr b/tests/ui/coherence/coherence-overlap-downstream.stderr index 6c2e9466b4b..9ab099489d9 100644 --- a/tests/ui/coherence/coherence-overlap-downstream.old.stderr +++ b/tests/ui/coherence/coherence-overlap-downstream.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Sweet` - --> $DIR/coherence-overlap-downstream.rs:11:1 + --> $DIR/coherence-overlap-downstream.rs:8:1 | LL | impl<T:Sugar> Sweet for T { } | ------------------------- first implementation here @@ -7,7 +7,7 @@ LL | impl<T:Fruit> Sweet for T { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32` - --> $DIR/coherence-overlap-downstream.rs:17:1 + --> $DIR/coherence-overlap-downstream.rs:14:1 | LL | impl<X, T> Foo<X> for T where T: Bar<X> {} | --------------------------------------- first implementation here diff --git a/tests/ui/coherence/coherence-overlap-issue-23516-inherent.old.stderr b/tests/ui/coherence/coherence-overlap-issue-23516-inherent.old.stderr deleted file mode 100644 index 2f3ad627808..00000000000 --- a/tests/ui/coherence/coherence-overlap-issue-23516-inherent.old.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0592]: duplicate definitions with name `dummy` - --> $DIR/coherence-overlap-issue-23516-inherent.rs:12:25 - | -LL | impl<T:Sugar> Cake<T> { fn dummy(&self) { } } - | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy` -LL | -LL | impl<U:Sugar> Cake<Box<U>> { fn dummy(&self) { } } - | --------------- other definition for `dummy` - | - = note: downstream crates may implement trait `Sugar` for type `std::boxed::Box<_>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0592`. diff --git a/tests/ui/coherence/coherence-overlap-issue-23516-inherent.rs b/tests/ui/coherence/coherence-overlap-issue-23516-inherent.rs index 53b0a40fa66..a272e620fca 100644 --- a/tests/ui/coherence/coherence-overlap-issue-23516-inherent.rs +++ b/tests/ui/coherence/coherence-overlap-issue-23516-inherent.rs @@ -1,6 +1,3 @@ -//@ revisions: old next -//@[next] compile-flags: -Znext-solver - // Tests that we consider `Box<U>: !Sugar` to be ambiguous, even // though we see no impl of `Sugar` for `Box`. Therefore, an overlap // error is reported for the following pair of impls (#23516). diff --git a/tests/ui/coherence/coherence-overlap-issue-23516-inherent.next.stderr b/tests/ui/coherence/coherence-overlap-issue-23516-inherent.stderr index 2f3ad627808..aacdeb5b0f9 100644 --- a/tests/ui/coherence/coherence-overlap-issue-23516-inherent.next.stderr +++ b/tests/ui/coherence/coherence-overlap-issue-23516-inherent.stderr @@ -1,5 +1,5 @@ error[E0592]: duplicate definitions with name `dummy` - --> $DIR/coherence-overlap-issue-23516-inherent.rs:12:25 + --> $DIR/coherence-overlap-issue-23516-inherent.rs:9:25 | LL | impl<T:Sugar> Cake<T> { fn dummy(&self) { } } | ^^^^^^^^^^^^^^^ duplicate definitions for `dummy` diff --git a/tests/ui/coherence/coherence-overlap-issue-23516.old.stderr b/tests/ui/coherence/coherence-overlap-issue-23516.old.stderr deleted file mode 100644 index b9494774025..00000000000 --- a/tests/ui/coherence/coherence-overlap-issue-23516.old.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0119]: conflicting implementations of trait `Sweet` for type `Box<_>` - --> $DIR/coherence-overlap-issue-23516.rs:11:1 - | -LL | impl<T:Sugar> Sweet for T { } - | ------------------------- first implementation here -LL | impl<U:Sugar> Sweet for Box<U> { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` - | - = note: downstream crates may implement trait `Sugar` for type `std::boxed::Box<_>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-overlap-issue-23516.rs b/tests/ui/coherence/coherence-overlap-issue-23516.rs index 620e00cd057..63e42e8f412 100644 --- a/tests/ui/coherence/coherence-overlap-issue-23516.rs +++ b/tests/ui/coherence/coherence-overlap-issue-23516.rs @@ -1,6 +1,3 @@ -//@ revisions: old next -//@[next] compile-flags: -Znext-solver - // Tests that we consider `Box<U>: !Sugar` to be ambiguous, even // though we see no impl of `Sugar` for `Box`. Therefore, an overlap // error is reported for the following pair of impls (#23516). diff --git a/tests/ui/coherence/coherence-overlap-issue-23516.next.stderr b/tests/ui/coherence/coherence-overlap-issue-23516.stderr index b9494774025..7b1b240291a 100644 --- a/tests/ui/coherence/coherence-overlap-issue-23516.next.stderr +++ b/tests/ui/coherence/coherence-overlap-issue-23516.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Sweet` for type `Box<_>` - --> $DIR/coherence-overlap-issue-23516.rs:11:1 + --> $DIR/coherence-overlap-issue-23516.rs:8:1 | LL | impl<T:Sugar> Sweet for T { } | ------------------------- first implementation here diff --git a/tests/ui/coherence/coherence-overlap-negate-not-use-feature-gate.stderr b/tests/ui/coherence/coherence-overlap-negate-not-use-feature-gate.stderr index 21c82eedd5d..c5bb695eb18 100644 --- a/tests/ui/coherence/coherence-overlap-negate-not-use-feature-gate.stderr +++ b/tests/ui/coherence/coherence-overlap-negate-not-use-feature-gate.stderr @@ -5,6 +5,8 @@ LL | impl<T: DerefMut> Foo for T {} | --------------------------- first implementation here LL | impl<U> Foo for &U {} | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + | + = note: downstream crates may implement trait `std::ops::DerefMut` for type `&_` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr deleted file mode 100644 index 2ffb6000ec8..00000000000 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>` - --> $DIR/coherence-overlap-unnormalizable-projection-0.rs:27:1 - | -LL | / impl<T> Trait for T -LL | | where -LL | | T: 'static, -LL | | for<'a> T: WithAssoc<'a>, -LL | | for<'a> <T as WithAssoc<'a>>::Assoc: WhereBound, - | |____________________________________________________- first implementation here -... -LL | impl<T> Trait for Box<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` - | - = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` - = note: downstream crates may implement trait `WhereBound` for type `<std::boxed::Box<_> as WithAssoc<'a>>::Assoc` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.rs b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.rs index b8b6d8846ef..0695076e221 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.rs +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.rs @@ -2,9 +2,6 @@ // "Coherence incorrectly considers `unnormalizable_projection: Trait` to not hold even if it could" #![crate_type = "lib"] -//@ revisions: classic next -//@[next] compile-flags: -Znext-solver - trait WhereBound {} impl WhereBound for () {} diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.next.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.stderr index 99abdf65abd..57befbe6e68 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.next.stderr +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>` - --> $DIR/coherence-overlap-unnormalizable-projection-0.rs:27:1 + --> $DIR/coherence-overlap-unnormalizable-projection-0.rs:24:1 | LL | / impl<T> Trait for T LL | | where diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr deleted file mode 100644 index 49b236f9d2a..00000000000 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>` - --> $DIR/coherence-overlap-unnormalizable-projection-1.rs:26:1 - | -LL | / impl<T> Trait for T -LL | | where -LL | | T: 'static, -LL | | for<'a> T: WithAssoc<'a>, -LL | | for<'a> Box<<T as WithAssoc<'a>>::Assoc>: WhereBound, - | |_________________________________________________________- first implementation here -... -LL | impl<T> Trait for Box<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` - | - = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` - = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.rs b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.rs index 8eeadb3dc75..f5fb5aefb5c 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.rs +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.rs @@ -2,9 +2,6 @@ // "Coherence incorrectly considers `unnormalizable_projection: Trait` to not hold even if it could" #![crate_type = "lib"] -//@ revisions: classic next -//@[next] compile-flags: -Znext-solver - pub trait WhereBound {} impl WhereBound for () {} diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.stderr index 781ab0fcbf7..22673cef640 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>` - --> $DIR/coherence-overlap-unnormalizable-projection-1.rs:26:1 + --> $DIR/coherence-overlap-unnormalizable-projection-1.rs:23:1 | LL | / impl<T> Trait for T LL | | where diff --git a/tests/ui/coherence/coherent-due-to-fulfill.rs b/tests/ui/coherence/coherent-due-to-fulfill.rs index 084f9be0a8c..f4555ee5171 100644 --- a/tests/ui/coherence/coherent-due-to-fulfill.rs +++ b/tests/ui/coherence/coherent-due-to-fulfill.rs @@ -1,6 +1,4 @@ -//@ compile-flags: -Znext-solver=coherence //@ check-pass - trait Mirror { type Assoc; } diff --git a/tests/ui/coherence/incoherent-even-though-we-fulfill.rs b/tests/ui/coherence/incoherent-even-though-we-fulfill.rs index b3c9cf328c2..28e5b6d3db0 100644 --- a/tests/ui/coherence/incoherent-even-though-we-fulfill.rs +++ b/tests/ui/coherence/incoherent-even-though-we-fulfill.rs @@ -1,5 +1,3 @@ -//@ compile-flags: -Znext-solver=coherence - trait Mirror { type Assoc; } diff --git a/tests/ui/coherence/incoherent-even-though-we-fulfill.stderr b/tests/ui/coherence/incoherent-even-though-we-fulfill.stderr index b16465d2011..0b15a4e100e 100644 --- a/tests/ui/coherence/incoherent-even-though-we-fulfill.stderr +++ b/tests/ui/coherence/incoherent-even-though-we-fulfill.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Foo` for type `()` - --> $DIR/incoherent-even-though-we-fulfill.rs:17:1 + --> $DIR/incoherent-even-though-we-fulfill.rs:15:1 | LL | impl<T> Foo for T where (): Mirror<Assoc = T> {} | --------------------------------------------- first implementation here diff --git a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr deleted file mode 100644 index 74be598c44c..00000000000 --- a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.old.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0119]: conflicting implementations of trait `From<()>` for type `S` - --> $DIR/inter-crate-ambiguity-causes-notes.rs:12:1 - | -LL | impl From<()> for S { - | ------------------- first implementation here -... -LL | / impl<I> From<I> for S -LL | | -LL | | where -LL | | I: Iterator<Item = ()>, - | |___________________________^ conflicting implementation for `S` - | - = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.rs b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.rs index 3dead2f0d19..5b11c78ab26 100644 --- a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.rs +++ b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.rs @@ -1,6 +1,3 @@ -//@ revisions: old next -//@[next] compile-flags: -Znext-solver - struct S; impl From<()> for S { diff --git a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.next.stderr b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.stderr index 74be598c44c..b32283274c6 100644 --- a/tests/ui/coherence/inter-crate-ambiguity-causes-notes.next.stderr +++ b/tests/ui/coherence/inter-crate-ambiguity-causes-notes.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `From<()>` for type `S` - --> $DIR/inter-crate-ambiguity-causes-notes.rs:12:1 + --> $DIR/inter-crate-ambiguity-causes-notes.rs:9:1 | LL | impl From<()> for S { | ------------------- first implementation here diff --git a/tests/ui/coherence/negative-coherence-check-placeholder-outlives.stderr b/tests/ui/coherence/negative-coherence-check-placeholder-outlives.stderr index f515c39ea8d..bf1ffcb5f00 100644 --- a/tests/ui/coherence/negative-coherence-check-placeholder-outlives.stderr +++ b/tests/ui/coherence/negative-coherence-check-placeholder-outlives.stderr @@ -5,6 +5,8 @@ LL | impl<T> Bar for T where T: Foo {} | ------------------------------ first implementation here LL | impl<T> Bar for Box<T> {} | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` + | + = note: downstream crates may implement trait `Foo` for type `std::boxed::Box<_>` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr b/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr index f24de10f6ac..97e2e9759c1 100644 --- a/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr +++ b/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr @@ -6,6 +6,8 @@ LL | impl<T> Bar for T where T: Foo {} ... LL | impl<T> Bar for &T {} | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + | + = note: downstream crates may implement trait `Foo` for type `&_` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr index 832c56a4554..8d59cbc3466 100644 --- a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr +++ b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr @@ -8,6 +8,7 @@ LL | impl<T: ?Sized> FnMarker for fn(&T) {} | = warning: the behavior may change in a future release = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105> + = note: downstream crates may implement trait `Marker` for type `&_` = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here --> $DIR/negative-coherence-placeholder-region-constraints-on-unification.rs:4:11 diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr deleted file mode 100644 index dcbb73bd1ff..00000000000 --- a/tests/ui/coherence/normalize-for-errors.current.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)` - --> $DIR/normalize-for-errors.rs:17:1 - | -LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {} - | ------------------------------------------------------ first implementation here -LL | -LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)` - | - = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs index c17bb766b5b..3ef91eb0386 100644 --- a/tests/ui/coherence/normalize-for-errors.rs +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -1,7 +1,3 @@ -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver - struct MyType; trait MyTrait<S> {} @@ -18,6 +14,6 @@ impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} //~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, //~| NOTE conflicting implementation for `(Box<(MyType,)>, //~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions -//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions +//~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions fn main() {} diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.stderr index 44952dc1944..6fbcf5b0e1a 100644 --- a/tests/ui/coherence/normalize-for-errors.next.stderr +++ b/tests/ui/coherence/normalize-for-errors.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)` - --> $DIR/normalize-for-errors.rs:17:1 + --> $DIR/normalize-for-errors.rs:13:1 | LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {} | ------------------------------------------------------ first implementation here diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 9544bdbb468..466b991471e 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -3,7 +3,7 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` - --> $DIR/associated-type.rs:31:1 + --> $DIR/associated-type.rs:32:1 | LL | impl<T> Overlap<T> for T { | ------------------------ first implementation here @@ -17,7 +17,7 @@ LL | | for<'a> *const T: ToUnit<'a>, = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details error[E0284]: type annotations needed: cannot normalize `<for<'a> fn(&'a (), ()) as Overlap<for<'a> fn(&'a (), ())>>::Assoc` - --> $DIR/associated-type.rs:44:59 + --> $DIR/associated-type.rs:45:59 | LL | foo::<for<'a> fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); | ^^^^^^ cannot normalize `<for<'a> fn(&'a (), ()) as Overlap<for<'a> fn(&'a (), ())>>::Assoc` diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index ccc7f30fa6f..1e0345f4ec0 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,13 +1,9 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } -error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` - --> $DIR/associated-type.rs:31:1 +error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` + --> $DIR/associated-type.rs:32:1 | LL | impl<T> Overlap<T> for T { | ------------------------ first implementation here @@ -16,7 +12,7 @@ LL | / impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T LL | | LL | | where LL | | for<'a> *const T: ToUnit<'a>, - | |_________________________________^ conflicting implementation for `for<'a> fn(&'a (), _)` + | |_________________________________^ conflicting implementation for `for<'a> fn(&'a (), ())` | = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details diff --git a/tests/ui/coherence/occurs-check/associated-type.rs b/tests/ui/coherence/occurs-check/associated-type.rs index df03d5f60a0..e450c33e809 100644 --- a/tests/ui/coherence/occurs-check/associated-type.rs +++ b/tests/ui/coherence/occurs-check/associated-type.rs @@ -1,4 +1,5 @@ //@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver // A regression test for #105787 diff --git a/tests/ui/coherence/occurs-check/opaques.current.stderr b/tests/ui/coherence/occurs-check/opaques.current.stderr new file mode 100644 index 00000000000..f3fc22027c2 --- /dev/null +++ b/tests/ui/coherence/occurs-check/opaques.current.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait<_>` + --> $DIR/opaques.rs:28:1 + | +LL | impl<T> Trait<T> for T { + | ---------------------- first implementation here +... +LL | impl<T> Trait<T> for defining_scope::Alias<T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/occurs-check/opaques.next.stderr b/tests/ui/coherence/occurs-check/opaques.next.stderr index 11d1edcca2f..3de479963bb 100644 --- a/tests/ui/coherence/occurs-check/opaques.next.stderr +++ b/tests/ui/coherence/occurs-check/opaques.next.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait<_>` - --> $DIR/opaques.rs:30:1 + --> $DIR/opaques.rs:28:1 | LL | impl<T> Trait<T> for T { | ---------------------- first implementation here @@ -8,7 +8,7 @@ LL | impl<T> Trait<T> for defining_scope::Alias<T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error[E0282]: type annotations needed - --> $DIR/opaques.rs:13:20 + --> $DIR/opaques.rs:11:20 | LL | pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> { | ^ cannot infer type diff --git a/tests/ui/coherence/occurs-check/opaques.rs b/tests/ui/coherence/occurs-check/opaques.rs index 241a247c841..e197256c78c 100644 --- a/tests/ui/coherence/occurs-check/opaques.rs +++ b/tests/ui/coherence/occurs-check/opaques.rs @@ -1,10 +1,8 @@ -//@revisions: old next +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver // A regression test for #105787 - -//@[old] known-bug: #105787 -//@[old] check-pass #![feature(type_alias_impl_trait)] mod defining_scope { use super::*; @@ -28,7 +26,7 @@ impl<T> Trait<T> for T { type Assoc = Box<u32>; } impl<T> Trait<T> for defining_scope::Alias<T> { - //[next]~^ ERROR conflicting implementations of trait + //~^ ERROR conflicting implementations of trait type Assoc = usize; } diff --git a/tests/ui/coherence/orphan-check-opaque-types-not-covering.next.stderr b/tests/ui/coherence/orphan-check-opaque-types-not-covering.next.stderr deleted file mode 100644 index 44f76f321cf..00000000000 --- a/tests/ui/coherence/orphan-check-opaque-types-not-covering.next.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - --> $DIR/orphan-check-opaque-types-not-covering.rs:17:6 - | -LL | impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {} - | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - | - = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type - = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last - -error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - --> $DIR/orphan-check-opaque-types-not-covering.rs:26:6 - | -LL | impl<T> foreign::Trait1<Local, T> for Opaque<T> {} - | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - | - = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type - = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-opaque-types-not-covering.rs b/tests/ui/coherence/orphan-check-opaque-types-not-covering.rs index 8dc02b081c5..02e9eb65570 100644 --- a/tests/ui/coherence/orphan-check-opaque-types-not-covering.rs +++ b/tests/ui/coherence/orphan-check-opaque-types-not-covering.rs @@ -1,8 +1,5 @@ // Opaque types never cover type parameters. -//@ revisions: classic next -//@[next] compile-flags: -Znext-solver - //@ aux-crate:foreign=parametrized-trait.rs //@ edition:2021 diff --git a/tests/ui/coherence/orphan-check-opaque-types-not-covering.classic.stderr b/tests/ui/coherence/orphan-check-opaque-types-not-covering.stderr index 44f76f321cf..57f5bbd2278 100644 --- a/tests/ui/coherence/orphan-check-opaque-types-not-covering.classic.stderr +++ b/tests/ui/coherence/orphan-check-opaque-types-not-covering.stderr @@ -1,5 +1,5 @@ error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - --> $DIR/orphan-check-opaque-types-not-covering.rs:17:6 + --> $DIR/orphan-check-opaque-types-not-covering.rs:14:6 | LL | impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) @@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {} = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - --> $DIR/orphan-check-opaque-types-not-covering.rs:26:6 + --> $DIR/orphan-check-opaque-types-not-covering.rs:23:6 | LL | impl<T> foreign::Trait1<Local, T> for Opaque<T> {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) diff --git a/tests/ui/coherence/orphan-check-projections-covering.rs b/tests/ui/coherence/orphan-check-projections-covering.rs index ae1917ec161..804784463a1 100644 --- a/tests/ui/coherence/orphan-check-projections-covering.rs +++ b/tests/ui/coherence/orphan-check-projections-covering.rs @@ -5,9 +5,6 @@ // first which would've lead to real-word regressions. //@ check-pass -//@ revisions: classic next -//@[next] compile-flags: -Znext-solver - //@ aux-crate:foreign=parametrized-trait.rs //@ edition:2021 diff --git a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.next.stderr b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.next.stderr deleted file mode 100644 index 276833fa171..00000000000 --- a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.next.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - --> $DIR/orphan-check-weak-aliases-not-covering.rs:16:6 - | -LL | impl<T> foreign::Trait1<Local, T> for Identity<T> {} - | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - | - = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type - = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.rs b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.rs index 9ebc45a8829..6d9bccc4c68 100644 --- a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.rs +++ b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.rs @@ -1,8 +1,5 @@ // Weak aliases might not cover type parameters. -//@ revisions: classic next -//@[next] compile-flags: -Znext-solver - //@ aux-crate:foreign=parametrized-trait.rs //@ edition:2021 diff --git a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.classic.stderr b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.stderr index 276833fa171..df915141a76 100644 --- a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.classic.stderr +++ b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.stderr @@ -1,5 +1,5 @@ error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) - --> $DIR/orphan-check-weak-aliases-not-covering.rs:16:6 + --> $DIR/orphan-check-weak-aliases-not-covering.rs:13:6 | LL | impl<T> foreign::Trait1<Local, T> for Identity<T> {} | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) diff --git a/tests/ui/coherence/skip-reporting-if-references-err.current.stderr b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr deleted file mode 100644 index 5eef3256b2c..00000000000 --- a/tests/ui/coherence/skip-reporting-if-references-err.current.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0726]: implicit elided lifetime not allowed here - --> $DIR/skip-reporting-if-references-err.rs:10:9 - | -LL | impl<T> ToUnit for T {} - | ^^^^^^ expected lifetime parameter - | -help: indicate the anonymous lifetime - | -LL | impl<T> ToUnit<'_> for T {} - | ++++ - -error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied - --> $DIR/skip-reporting-if-references-err.rs:15:29 - | -LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()` - -error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied - --> $DIR/skip-reporting-if-references-err.rs:15:18 - | -LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()` - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0277, E0726. -For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/coherence/skip-reporting-if-references-err.rs b/tests/ui/coherence/skip-reporting-if-references-err.rs index f9eaa498232..dd8a71c4700 100644 --- a/tests/ui/coherence/skip-reporting-if-references-err.rs +++ b/tests/ui/coherence/skip-reporting-if-references-err.rs @@ -1,8 +1,4 @@ // Regression test for #121006. -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver - trait ToUnit<'a> { type Unit; } @@ -13,7 +9,5 @@ impl<T> ToUnit for T {} trait Overlap {} impl<U> Overlap for fn(U) {} impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} -//[current]~^ ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied -//[current]~| ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied fn main() {} diff --git a/tests/ui/coherence/skip-reporting-if-references-err.next.stderr b/tests/ui/coherence/skip-reporting-if-references-err.stderr index 5de4cf626e4..0ff3e88a0af 100644 --- a/tests/ui/coherence/skip-reporting-if-references-err.next.stderr +++ b/tests/ui/coherence/skip-reporting-if-references-err.stderr @@ -1,5 +1,5 @@ error[E0726]: implicit elided lifetime not allowed here - --> $DIR/skip-reporting-if-references-err.rs:10:9 + --> $DIR/skip-reporting-if-references-err.rs:6:9 | LL | impl<T> ToUnit for T {} | ^^^^^^ expected lifetime parameter diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr b/tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr deleted file mode 100644 index fb01cf158d9..00000000000 --- a/tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0119]: conflicting implementations of trait `Overlap<_>` for type `()` - --> $DIR/super-trait-knowable-1.rs:16:1 - | -LL | impl<T, U: Sub<T>> Overlap<T> for U {} - | ----------------------------------- first implementation here -LL | impl<T> Overlap<T> for () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` - | - = note: downstream crates may implement trait `Sub<_>` for type `()` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-1.rs b/tests/ui/coherence/super-traits/super-trait-knowable-1.rs index 80df8c19ee5..77af4d0f2e3 100644 --- a/tests/ui/coherence/super-traits/super-trait-knowable-1.rs +++ b/tests/ui/coherence/super-traits/super-trait-knowable-1.rs @@ -3,10 +3,7 @@ // We therefore elaborate super trait bounds in the implicit negative // overlap check. -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver -//@[next] check-pass +//@ check-pass trait Super {} trait Sub<T>: Super {} @@ -14,6 +11,5 @@ trait Sub<T>: Super {} trait Overlap<T> {} impl<T, U: Sub<T>> Overlap<T> for U {} impl<T> Overlap<T> for () {} -//[current]~^ ERROR conflicting implementations fn main() {} diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-2.rs b/tests/ui/coherence/super-traits/super-trait-knowable-2.rs index d1f2e8d1c1a..323ee0b10c9 100644 --- a/tests/ui/coherence/super-traits/super-trait-knowable-2.rs +++ b/tests/ui/coherence/super-traits/super-trait-knowable-2.rs @@ -9,9 +9,6 @@ // which caused the old solver to emit a `Tensor: TensorValue` goal in // `fn normalize_to_error` which then failed, causing this test to pass. -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver //@ check-pass pub trait TensorValue { diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr b/tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr deleted file mode 100644 index 542edb8b7f6..00000000000 --- a/tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0119]: conflicting implementations of trait `Overlap<_>` for type `()` - --> $DIR/super-trait-knowable-3.rs:19:1 - | -LL | impl<T, U: Bound<W<T>>> Overlap<T> for U {} - | ---------------------------------------- first implementation here -LL | impl<T> Overlap<T> for () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` - | - = note: downstream crates may implement trait `Sub<_>` for type `()` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-3.rs b/tests/ui/coherence/super-traits/super-trait-knowable-3.rs index 295d7ac48d8..6198d3d303b 100644 --- a/tests/ui/coherence/super-traits/super-trait-knowable-3.rs +++ b/tests/ui/coherence/super-traits/super-trait-knowable-3.rs @@ -2,10 +2,7 @@ // super trait bound is in a nested goal so this would not // compile if we were to only elaborate root goals. -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver -//@[next] check-pass +//@ check-pass trait Super {} trait Sub<T>: Super {} @@ -17,6 +14,5 @@ impl<T: Sub<U>, U> Bound<W<U>> for T {} trait Overlap<T> {} impl<T, U: Bound<W<T>>> Overlap<T> for U {} impl<T> Overlap<T> for () {} -//[current]~^ ERROR conflicting implementations of trait `Overlap<_>` for type `()` fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs index 05a3487ffca..42c930f952d 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs @@ -22,6 +22,7 @@ mod v20 { impl v17<512, v0> { pub const fn v21() -> v18 {} //~^ ERROR cannot find type `v18` in this scope + //~| ERROR duplicate definitions with name `v21` } impl<const v10: usize> v17<v10, v2> { diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr index 39f022fbee9..b336f2b3fca 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr @@ -1,5 +1,5 @@ error[E0432]: unresolved import `v20::v13` - --> $DIR/unevaluated-const-ice-119731.rs:37:15 + --> $DIR/unevaluated-const-ice-119731.rs:38:15 | LL | pub use v20::{v13, v17}; | ^^^ @@ -23,7 +23,7 @@ LL | pub const fn v21() -> v18 {} | ^^^ help: a type alias with a similar name exists: `v11` error[E0412]: cannot find type `v18` in this scope - --> $DIR/unevaluated-const-ice-119731.rs:30:31 + --> $DIR/unevaluated-const-ice-119731.rs:31:31 | LL | pub type v11 = [[usize; v4]; v4]; | --------------------------------- similarly named type alias `v11` defined here @@ -32,7 +32,7 @@ LL | pub const fn v21() -> v18 { | ^^^ help: a type alias with a similar name exists: `v11` error[E0422]: cannot find struct, variant or union type `v18` in this scope - --> $DIR/unevaluated-const-ice-119731.rs:32:13 + --> $DIR/unevaluated-const-ice-119731.rs:33:13 | LL | pub type v11 = [[usize; v4]; v4]; | --------------------------------- similarly named type alias `v11` defined here @@ -73,20 +73,29 @@ LL + #![feature(adt_const_params)] | error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} - --> $DIR/unevaluated-const-ice-119731.rs:27:37 + --> $DIR/unevaluated-const-ice-119731.rs:28:37 | LL | impl<const v10: usize> v17<v10, v2> { | ^^ error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} - --> $DIR/unevaluated-const-ice-119731.rs:27:37 + --> $DIR/unevaluated-const-ice-119731.rs:28:37 | LL | impl<const v10: usize> v17<v10, v2> { | ^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 9 previous errors; 2 warnings emitted +error[E0592]: duplicate definitions with name `v21` + --> $DIR/unevaluated-const-ice-119731.rs:23:9 + | +LL | pub const fn v21() -> v18 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `v21` +... +LL | pub const fn v21() -> v18 { + | ------------------------- other definition for `v21` + +error: aborting due to 10 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0412, E0422, E0425, E0432. +Some errors have detailed explanations: E0412, E0422, E0425, E0432, E0592. For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs index dd0b1e8c9f7..81ac9979bd8 100644 --- a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs +++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs @@ -10,6 +10,5 @@ trait Trait {} impl<const N: u32> Trait for A<N> {} impl<const N: u32> Trait for A<N> {} -//~^ ERROR conflicting implementations of trait `Trait` for type `A<_>` pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr index 80ac96d4870..e29c49ff042 100644 --- a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr @@ -4,16 +4,6 @@ error[E0423]: expected value, found builtin type `u8` LL | struct A<const N: u32 = 1, const M: u32 = u8>; | ^^ not a value -error[E0119]: conflicting implementations of trait `Trait` for type `A<_>` - --> $DIR/unknown-alias-defkind-anonconst-ice-116710.rs:12:1 - | -LL | impl<const N: u32> Trait for A<N> {} - | --------------------------------- first implementation here -LL | -LL | impl<const N: u32> Trait for A<N> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A<_>` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0423. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/const-generics/invariant.rs b/tests/ui/const-generics/invariant.rs index ee4ad4e7c4e..95a28b61dde 100644 --- a/tests/ui/const-generics/invariant.rs +++ b/tests/ui/const-generics/invariant.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; trait SadBee { const ASSOC: usize; } -// fn(&'static ())` is a supertype of `for<'a> fn(&'a ())` while +// `fn(&'static ())` is a supertype of `for<'a> fn(&'a ())` while // we allow two different impls for these types, leading // to different const eval results. impl SadBee for for<'a> fn(&'a ()) { diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs index 3a526c54dc3..869498d1076 100644 --- a/tests/ui/consts/const-float-bits-conv.rs +++ b/tests/ui/consts/const-float-bits-conv.rs @@ -1,10 +1,9 @@ //@ compile-flags: -Zmir-opt-level=0 //@ run-pass -#![feature(const_float_bits_conv)] #![feature(const_float_classify)] -#![feature(f16)] -#![feature(f128)] +#![feature(f16, f16_const)] +#![feature(f128, f128_const)] #![allow(unused_macro_rules)] // Don't promote const fn nop<T>(x: T) -> T { x } diff --git a/tests/ui/consts/const-float-classify.rs b/tests/ui/consts/const-float-classify.rs index c64d31a5c60..6e5097f7f2b 100644 --- a/tests/ui/consts/const-float-classify.rs +++ b/tests/ui/consts/const-float-classify.rs @@ -2,7 +2,6 @@ //@ known-bug: #110395 // FIXME(effects) run-pass -#![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_trait_impl, effects)] #![allow(incomplete_features)] diff --git a/tests/ui/consts/const-float-classify.stderr b/tests/ui/consts/const-float-classify.stderr index 38acb8a2281..a35de8ad0ea 100644 --- a/tests/ui/consts/const-float-classify.stderr +++ b/tests/ui/consts/const-float-classify.stderr @@ -1,5 +1,5 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/const-float-classify.rs:13:12 + --> $DIR/const-float-classify.rs:12:12 | LL | impl const PartialEq<NonDet> for bool { | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/missing_assoc_const_type.rs b/tests/ui/consts/missing_assoc_const_type.rs index 8d95e3dca63..633998e9bc1 100644 --- a/tests/ui/consts/missing_assoc_const_type.rs +++ b/tests/ui/consts/missing_assoc_const_type.rs @@ -16,7 +16,7 @@ impl Range for TwoDigits { const fn digits(x: u8) -> usize { match x { - TwoDigits::FIRST..=TwoDigits::LAST => 0, + TwoDigits::FIRST..=TwoDigits::LAST => 0, //~ ERROR: could not evaluate constant pattern 0..=9 | 100..=255 => panic!(), } } diff --git a/tests/ui/consts/missing_assoc_const_type.stderr b/tests/ui/consts/missing_assoc_const_type.stderr index 28af1f0f321..ef7ff962d2d 100644 --- a/tests/ui/consts/missing_assoc_const_type.stderr +++ b/tests/ui/consts/missing_assoc_const_type.stderr @@ -4,5 +4,11 @@ error: missing type for `const` item LL | const FIRST: = 10; | ^ help: provide a type for the associated constant: `u8` -error: aborting due to 1 previous error +error: could not evaluate constant pattern + --> $DIR/missing_assoc_const_type.rs:19:9 + | +LL | TwoDigits::FIRST..=TwoDigits::LAST => 0, + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/delegation/generics/impl-to-free-fn-pass.rs b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs new file mode 100644 index 00000000000..3b39a457467 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs @@ -0,0 +1,29 @@ +//@ run-pass +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo<T, U>(_: T, y: U) -> U { y } +} + +trait Trait<T> { + fn foo(&self, x: T) -> T { x } +} +struct F; +impl<T> Trait<T> for F {} + +struct S<T>(F, T); + +impl<T, U> Trait<T> for S<U> { + reuse to_reuse::foo { &self.0 } +} + +impl<T> S<T> { + reuse to_reuse::foo; +} + +fn main() { + let s = S(F, 42); + assert_eq!(S::<i32>::foo(F, 1), 1); + assert_eq!(<S<_> as Trait<_>>::foo(&s, 1), 1); +} diff --git a/tests/ui/delegation/generics/impl-to-trait-method.rs b/tests/ui/delegation/generics/impl-to-trait-method.rs new file mode 100644 index 00000000000..39e32e2ed15 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-trait-method.rs @@ -0,0 +1,44 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod bounds { + trait Trait0 {} + + trait Trait1<T> { + fn foo<U>(&self) + where + T: Trait0, + U: Trait0, + Self: Trait0, + //~^ ERROR the trait bound `bounds::S: Trait0` is not satisfied + { + } + } + + struct F; + impl<T> Trait1<T> for F {} + + struct S(F); + + impl<T> Trait1<T> for S { + reuse Trait1::<T>::foo { &self.0 } + //~^ ERROR the trait bound `bounds::F: Trait0` is not satisfied + } +} + +mod unconstrained_parameter { + trait Trait<T> { + fn foo(&self) {} + } + + struct F; + impl<T> Trait<T> for F {} + + struct S(F); + impl S { + reuse Trait::foo { &self.0 } + //~^ ERROR type annotations needed + } +} + +fn main() {} diff --git a/tests/ui/delegation/generics/impl-to-trait-method.stderr b/tests/ui/delegation/generics/impl-to-trait-method.stderr new file mode 100644 index 00000000000..aeba30de043 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-trait-method.stderr @@ -0,0 +1,49 @@ +error[E0277]: the trait bound `bounds::S: Trait0` is not satisfied + --> $DIR/impl-to-trait-method.rs:12:19 + | +LL | Self: Trait0, + | ^^^^^^ the trait `Trait0` is not implemented for `bounds::S` + | +help: this trait has no implementations, consider adding one + --> $DIR/impl-to-trait-method.rs:5:5 + | +LL | trait Trait0 {} + | ^^^^^^^^^^^^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `bounds::F: Trait0` is not satisfied + --> $DIR/impl-to-trait-method.rs:24:34 + | +LL | reuse Trait1::<T>::foo { &self.0 } + | --- ^^^^^^^ the trait `Trait0` is not implemented for `bounds::F` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/impl-to-trait-method.rs:5:5 + | +LL | trait Trait0 {} + | ^^^^^^^^^^^^ +note: required by a bound in `Trait1::foo` + --> $DIR/impl-to-trait-method.rs:12:19 + | +LL | fn foo<U>(&self) + | --- required by a bound in this associated function +... +LL | Self: Trait0, + | ^^^^^^ required by this bound in `Trait1::foo` + +error[E0282]: type annotations needed + --> $DIR/impl-to-trait-method.rs:39:22 + | +LL | reuse Trait::foo { &self.0 } + | ^^^ cannot infer type for type parameter `T` declared on the trait `Trait` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0282. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs new file mode 100644 index 00000000000..72440fe82d4 --- /dev/null +++ b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs @@ -0,0 +1,77 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +use std::iter::{Iterator, Map}; + +pub mod same_trait { + use super::*; + + pub struct MapOuter<I, F> { + pub inner: Map<I, F> + } + + impl<B, I: Iterator, F> Iterator for MapOuter<I, F> + where + F: FnMut(I::Item) -> B, + { + type Item = <Map<I, F> as Iterator>::Item; + + reuse Iterator::{next, fold} { self.inner } + } +} +use same_trait::MapOuter; + +mod another_trait { + use super::*; + + trait ZipImpl<A, B> { + type Item; + + fn next(&mut self) -> Option<Self::Item>; + } + + pub struct Zip<A, B> { + pub a: A, + pub b: B, + } + + impl<A: Iterator, B: Iterator> ZipImpl<A, B> for Zip<A, B> { + type Item = (A::Item, B::Item); + + fn next(&mut self) -> Option<(A::Item, B::Item)> { + let x = self.a.next()?; + let y = self.b.next()?; + Some((x, y)) + } + } + + impl<A: Iterator, B: Iterator> Iterator for Zip<A, B> { + type Item = (A::Item, B::Item); + + // Parameters are inherited from `Iterator::next`, not from `ZipImpl::next`. + // Otherwise, there would be a compilation error due to an unconstrained parameter. + reuse ZipImpl::next; + } +} +use another_trait::Zip; + +fn main() { + { + let x = vec![1, 2, 3]; + let iter = x.iter().map(|val| val * 2); + let outer_iter = MapOuter { inner: iter }; + let val = outer_iter.fold(0, |acc, x| acc + x); + assert_eq!(val, 12); + } + + { + let x = vec![1, 2]; + let y = vec![4, 5]; + + let mut zip = Zip { a: x.iter(), b: y.iter() }; + assert_eq!(zip.next(), Some((&1, &4))); + assert_eq!(zip.next(), Some((&2, &5))); + } +} diff --git a/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs new file mode 100644 index 00000000000..6f3bb178971 --- /dev/null +++ b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs @@ -0,0 +1,23 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait<T> { + fn foo<U>(&self, x: T, y: U) -> (T, U) { + (x, y) + } +} + +impl<T> Trait<T> for () {} +struct S<T>(T, ()); + +impl<T> S<T> { + reuse Trait::foo { self.1 } +} + + +fn main() { + let s = S((), ()); + assert_eq!(s.foo(1u32, 2i32), (1u32, 2i32)); +} diff --git a/tests/ui/delegation/generics/trait-method-to-other-pass.rs b/tests/ui/delegation/generics/trait-method-to-other-pass.rs new file mode 100644 index 00000000000..2094705a05c --- /dev/null +++ b/tests/ui/delegation/generics/trait-method-to-other-pass.rs @@ -0,0 +1,30 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo<T>(x: T) -> T { x } +} + +trait Trait1<T, U> { + fn foo(&self, _: T, x: U) -> U { x } +} + +#[derive(Default)] +struct F; + +impl<T, U> Trait1<T, U> for F {} + +trait Trait2<T> { + fn get_f(&self) -> &F { &F } + reuse Trait1::foo as bar { self.get_f() } + reuse to_reuse::foo as baz; +} + +impl Trait2<u64> for F {} + +fn main() { + assert_eq!(F.bar(1u8, 2u16), 2u16); + assert_eq!(F::baz(1u8), 1u8); +} diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs index 3bfae8face5..ee2bf9e33eb 100644 --- a/tests/ui/delegation/ice-issue-124347.rs +++ b/tests/ui/delegation/ice-issue-124347.rs @@ -1,12 +1,12 @@ #![feature(fn_delegation)] #![allow(incomplete_features)] +// FIXME(fn_delegation): `recursive delegation` error should be emitted here trait Trait { reuse Trait::foo { &self.0 } - //~^ ERROR recursive delegation is not supported yet + //~^ ERROR cycle detected when computing generics of `Trait::foo` } -// FIXME(fn_delegation): `recursive delegation` error should be emitted here reuse foo; //~^ ERROR cycle detected when computing generics of `foo` diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr index 87dd75ffec8..bd0bc970b94 100644 --- a/tests/ui/delegation/ice-issue-124347.stderr +++ b/tests/ui/delegation/ice-issue-124347.stderr @@ -1,8 +1,16 @@ -error: recursive delegation is not supported yet - --> $DIR/ice-issue-124347.rs:5:18 +error[E0391]: cycle detected when computing generics of `Trait::foo` + --> $DIR/ice-issue-124347.rs:6:18 | LL | reuse Trait::foo { &self.0 } - | ^^^ callee defined here + | ^^^ + | + = note: ...which immediately requires computing generics of `Trait::foo` again +note: cycle used when inheriting delegation signature + --> $DIR/ice-issue-124347.rs:6:18 + | +LL | reuse Trait::foo { &self.0 } + | ^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error[E0391]: cycle detected when computing generics of `foo` --> $DIR/ice-issue-124347.rs:10:7 diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs deleted file mode 100644 index d5ac68ecf1b..00000000000 --- a/tests/ui/delegation/not-supported.rs +++ /dev/null @@ -1,116 +0,0 @@ -#![feature(const_trait_impl)] -#![feature(c_variadic)] -#![feature(effects)] -#![feature(fn_delegation)] -#![allow(incomplete_features)] - -mod generics { - trait GenericTrait<T> { - fn bar(&self, x: T) -> T { x } - fn bar1() {} - } - trait Trait { - fn foo(&self, x: i32) -> i32 { x } - fn foo1<'a>(&self, x: &'a i32) -> &'a i32 { x } - fn foo2<T>(&self, x: T) -> T { x } - fn foo3<'a: 'a>(_: &'a u32) {} - - reuse GenericTrait::bar; - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - struct F; - impl Trait for F {} - impl<T> GenericTrait<T> for F {} - - struct S(F); - - impl<T> GenericTrait<T> for S { - reuse <F as GenericTrait<T>>::bar { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::<T>::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl GenericTrait<()> for () { - reuse GenericTrait::bar { &F } - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl Trait for &S { - reuse Trait::foo; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl Trait for S { - reuse Trait::foo1 { &self.0 } - reuse Trait::foo2 { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - //~| ERROR method `foo2` has 0 type parameters but its trait declaration has 1 type parameter - reuse <F as Trait>::foo3; - //~^ ERROR early bound generics are not supported for associated delegation items - //~| ERROR lifetime parameters or bounds on associated function `foo3` do not match the trait declaration - } - - struct GenericS<T>(T); - impl<T> Trait for GenericS<T> { - reuse Trait::foo { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - } -} - -mod opaque { - trait Trait {} - impl Trait for () {} - - mod to_reuse { - use super::Trait; - - pub fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - } - - trait ToReuse { - fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - } - - // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. - impl ToReuse for u8 { - reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type - } - impl ToReuse for u16 { - reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type - } -} - -mod recursive { - mod to_reuse1 { - pub mod to_reuse2 { - pub fn foo() {} - } - - pub reuse to_reuse2::foo; - } - - reuse to_reuse1::foo; - //~^ ERROR recursive delegation is not supported yet -} - -mod effects { - #[const_trait] - trait Trait { - fn foo(); - } - - reuse Trait::foo; - //~^ ERROR delegation to a function with effect parameter is not supported yet -} - -fn main() {} diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr deleted file mode 100644 index 14d6b374bd2..00000000000 --- a/tests/ui/delegation/not-supported.stderr +++ /dev/null @@ -1,204 +0,0 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:18:29 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse GenericTrait::bar; - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:20:29 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:31:39 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse <F as GenericTrait<T>>::bar { &self.0 } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:33:34 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::<T>::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:38:29 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse GenericTrait::bar { &F } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:40:29 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:45:22 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo; - | ^^^ - -error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/not-supported.rs:51:22 - | -LL | fn foo2<T>(&self, x: T) -> T { x } - | - expected 1 type parameter -... -LL | reuse Trait::foo2 { &self.0 } - | ^^^^ found 0 type parameters - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:54:29 - | -LL | fn foo3<'a: 'a>(_: &'a u32) {} - | --------------------------- callee defined here -... -LL | reuse <F as Trait>::foo3; - | ^^^^ - -error[E0195]: lifetime parameters or bounds on associated function `foo3` do not match the trait declaration - --> $DIR/not-supported.rs:54:29 - | -LL | fn foo3<'a: 'a>(_: &'a u32) {} - | -------- lifetimes in impl do not match this associated function in trait -... -LL | reuse <F as Trait>::foo3; - | ^^^^ lifetimes do not match associated function in trait - -error: delegation to a function with effect parameter is not supported yet - --> $DIR/not-supported.rs:112:18 - | -LL | fn foo(); - | --------- callee defined here -... -LL | reuse Trait::foo; - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:61:22 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo { &self.0 } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/not-supported.rs:51:22 - | -LL | fn foo2<T>(&self, x: T) -> T { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo2 { &self.0 } - | ^^^^ - -warning: this function depends on never type fallback being `()` - --> $DIR/not-supported.rs:79:9 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #123748 <https://github.com/rust-lang/rust/issues/123748> - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/not-supported.rs:79:28 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default - -error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/not-supported.rs:85:5: 85:24>::{synthetic#0}` - --> $DIR/not-supported.rs:86:25 - | -LL | reuse to_reuse::opaque_ret; - | ^^^^^^^^^^ - | -note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:86:25 - | -LL | reuse to_reuse::opaque_ret; - | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::<impl at $DIR/not-supported.rs:85:5: 85:24>::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:85:5: 85:24>` is well-formed - --> $DIR/not-supported.rs:85:5 - | -LL | impl ToReuse for u8 { - | ^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -warning: this function depends on never type fallback being `()` - --> $DIR/not-supported.rs:73:9 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #123748 <https://github.com/rust-lang/rust/issues/123748> - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/not-supported.rs:73:32 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - -error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/not-supported.rs:88:5: 88:25>::{synthetic#0}` - --> $DIR/not-supported.rs:89:24 - | -LL | reuse ToReuse::opaque_ret; - | ^^^^^^^^^^ - | -note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:89:24 - | -LL | reuse ToReuse::opaque_ret; - | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::<impl at $DIR/not-supported.rs:88:5: 88:25>::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:88:5: 88:25>` is well-formed - --> $DIR/not-supported.rs:88:5 - | -LL | impl ToReuse for u16 { - | ^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: recursive delegation is not supported yet - --> $DIR/not-supported.rs:102:22 - | -LL | pub reuse to_reuse2::foo; - | --- callee defined here -... -LL | reuse to_reuse1::foo; - | ^^^ - -error: aborting due to 17 previous errors; 2 warnings emitted - -Some errors have detailed explanations: E0049, E0195, E0391. -For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs new file mode 100644 index 00000000000..e57effff48d --- /dev/null +++ b/tests/ui/delegation/unsupported.rs @@ -0,0 +1,57 @@ +#![feature(const_trait_impl)] +#![feature(c_variadic)] +#![feature(effects)] +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod opaque { + trait Trait {} + impl Trait for () {} + + mod to_reuse { + use super::Trait; + + pub fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + } + + trait ToReuse { + fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + } + + // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. + impl ToReuse for u8 { + reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type + } + impl ToReuse for u16 { + reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type + } +} + +mod recursive { + mod to_reuse1 { + pub mod to_reuse2 { + pub fn foo() {} + } + + pub reuse to_reuse2::foo; + } + + reuse to_reuse1::foo; + //~^ ERROR recursive delegation is not supported yet +} + +mod effects { + #[const_trait] + trait Trait { + fn foo(); + } + + reuse Trait::foo; + //~^ ERROR delegation to a function with effect parameter is not supported yet +} + +fn main() {} diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr new file mode 100644 index 00000000000..03ded300bb4 --- /dev/null +++ b/tests/ui/delegation/unsupported.stderr @@ -0,0 +1,95 @@ +error: using `#![feature(effects)]` without enabling next trait solver globally + | + = note: the next trait solver must be enabled globally for the effects feature to work correctly + = help: use `-Znext-solver` to enable + +warning: this function depends on never type fallback being `()` + --> $DIR/unsupported.rs:20:9 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/unsupported.rs:20:28 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}` + --> $DIR/unsupported.rs:27:25 + | +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/unsupported.rs:27:25 + | +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>` is well-formed + --> $DIR/unsupported.rs:26:5 + | +LL | impl ToReuse for u8 { + | ^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +warning: this function depends on never type fallback being `()` + --> $DIR/unsupported.rs:14:9 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/unsupported.rs:14:32 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ + +error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>::{synthetic#0}` + --> $DIR/unsupported.rs:30:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/unsupported.rs:30:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>` is well-formed + --> $DIR/unsupported.rs:29:5 + | +LL | impl ToReuse for u16 { + | ^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: recursive delegation is not supported yet + --> $DIR/unsupported.rs:43:22 + | +LL | pub reuse to_reuse2::foo; + | --- callee defined here +... +LL | reuse to_reuse1::foo; + | ^^^ + +error: delegation to a function with effect parameter is not supported yet + --> $DIR/unsupported.rs:53:18 + | +LL | fn foo(); + | --------- callee defined here +... +LL | reuse Trait::foo; + | ^^^ + +error: aborting due to 5 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/error-codes/e0119/issue-23563.stderr b/tests/ui/error-codes/e0119/issue-23563.stderr index 86737742f74..a308769af13 100644 --- a/tests/ui/error-codes/e0119/issue-23563.stderr +++ b/tests/ui/error-codes/e0119/issue-23563.stderr @@ -1,4 +1,4 @@ -error[E0119]: conflicting implementations of trait `LolFrom<&[_]>` for type `LocalType<_>` +error[E0119]: conflicting implementations of trait `LolFrom<&[u8]>` for type `LocalType<u8>` --> $DIR/issue-23563.rs:13:1 | LL | impl<'a, T> LolFrom<&'a [T]> for LocalType<T> { diff --git a/tests/ui/feature-gates/feature-gate-with_negative_coherence.stderr b/tests/ui/feature-gates/feature-gate-with_negative_coherence.stderr index ba076568088..b32f54aaecf 100644 --- a/tests/ui/feature-gates/feature-gate-with_negative_coherence.stderr +++ b/tests/ui/feature-gates/feature-gate-with_negative_coherence.stderr @@ -6,6 +6,8 @@ LL | impl<T: std::ops::DerefMut> Foo for T { } LL | LL | impl<T> Foo for &T { } | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + | + = note: downstream crates may implement trait `std::ops::DerefMut` for type `&_` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs index beda719ac20..9a44fd2e64a 100644 --- a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs @@ -3,9 +3,9 @@ //@ check-pass // The new trait solver does not return region constraints if the goal -// is still ambiguous. This causes the following test to fail with ambiguity, -// even though `(): LeakCheckFailure<'!a, V>` would return `'!a: 'static` -// which would have caused a leak check failure. +// is still ambiguous. However, the `'!a = 'static` constraint from +// `(): LeakCheckFailure<'!a, V>` is also returned via the canonical +// var values, causing this test to compile. trait Ambig {} impl Ambig for u32 {} diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs index 8df24702811..69882450961 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.rs +++ b/tests/ui/higher-ranked/structually-relate-aliases.rs @@ -11,7 +11,6 @@ type Assoc<'a, T> = <T as ToUnit<'a>>::Unit; impl<T> Overlap<T> for T {} impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {} -//~^ ERROR 13:17: 13:49: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277] -//~| ERROR 13:36: 13:48: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277] +//~^ ERROR conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` fn main() {} diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index 7de30efae1c..4ecd5829bc3 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -1,27 +1,18 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } -error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied - --> $DIR/structually-relate-aliases.rs:13:36 - | -LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {} - | ^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T` - | -help: consider restricting type parameter `T` - | -LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {} - | ++++++++++++++++++++ - -error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied - --> $DIR/structually-relate-aliases.rs:13:17 + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } +error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` + --> $DIR/structually-relate-aliases.rs:13:1 | +LL | impl<T> Overlap<T> for T {} + | ------------------------ first implementation here +LL | LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T` - | -help: consider restricting type parameter `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a (), _)` | -LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {} - | ++++++++++++++++++++ + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/auto-trait-coherence.old.stderr b/tests/ui/impl-trait/auto-trait-coherence.old.stderr index 3f979d1a50b..cd91bfcb48d 100644 --- a/tests/ui/impl-trait/auto-trait-coherence.old.stderr +++ b/tests/ui/impl-trait/auto-trait-coherence.old.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<_>` --> $DIR/auto-trait-coherence.rs:24:1 | LL | impl<T: Send> AnotherTrait for T {} | -------------------------------- first implementation here ... LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<_>` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/auto-trait-coherence.rs b/tests/ui/impl-trait/auto-trait-coherence.rs index e3036fd0fe2..0d7fef21cc9 100644 --- a/tests/ui/impl-trait/auto-trait-coherence.rs +++ b/tests/ui/impl-trait/auto-trait-coherence.rs @@ -1,6 +1,3 @@ -//@ revisions: old next -//@[next] compile-flags: -Znext-solver - // Tests that type alias impls traits do not leak auto-traits for // the purposes of coherence checking #![feature(type_alias_impl_trait)] @@ -22,8 +19,7 @@ impl<T: Send> AnotherTrait for T {} // (We treat opaque types as "foreign types" that could grow more impls // in the future.) impl AnotherTrait for D<OpaqueType> { - //[old]~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` - //[next]~^^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<_>` + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<_>` } fn main() {} diff --git a/tests/ui/impl-trait/auto-trait-coherence.stderr b/tests/ui/impl-trait/auto-trait-coherence.stderr new file mode 100644 index 00000000000..e0f4c857717 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-coherence.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<_>` + --> $DIR/auto-trait-coherence.rs:21:1 + | +LL | impl<T: Send> AnotherTrait for T {} + | -------------------------------- first implementation here +... +LL | impl AnotherTrait for D<OpaqueType> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<_>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.rs b/tests/ui/impl-trait/coherence-treats-tait-ambig.rs index df47208bf36..e8c1fcdd213 100644 --- a/tests/ui/impl-trait/coherence-treats-tait-ambig.rs +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.rs @@ -5,7 +5,7 @@ type T = impl Sized; struct Foo; impl Into<T> for Foo { -//~^ ERROR conflicting implementations of trait `Into<T>` for type `Foo` +//~^ ERROR conflicting implementations of trait `Into<_>` for type `Foo` fn into(self) -> T { Foo } diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.stderr b/tests/ui/impl-trait/coherence-treats-tait-ambig.stderr index faaad276927..618bef1f271 100644 --- a/tests/ui/impl-trait/coherence-treats-tait-ambig.stderr +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.stderr @@ -1,4 +1,4 @@ -error[E0119]: conflicting implementations of trait `Into<T>` for type `Foo` +error[E0119]: conflicting implementations of trait `Into<_>` for type `Foo` --> $DIR/coherence-treats-tait-ambig.rs:7:1 | LL | impl Into<T> for Foo { diff --git a/tests/ui/impl-trait/negative-reasoning.rs b/tests/ui/impl-trait/negative-reasoning.rs index 70e24a3a9d0..0474dc0beda 100644 --- a/tests/ui/impl-trait/negative-reasoning.rs +++ b/tests/ui/impl-trait/negative-reasoning.rs @@ -17,7 +17,7 @@ impl<T: std::fmt::Debug> AnotherTrait for T {} // This is in error, because we cannot assume that `OpaqueType: !Debug` impl AnotherTrait for D<OpaqueType> { - //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<_>` } fn main() {} diff --git a/tests/ui/impl-trait/negative-reasoning.stderr b/tests/ui/impl-trait/negative-reasoning.stderr index 3cb4be16fc3..631784c817b 100644 --- a/tests/ui/impl-trait/negative-reasoning.stderr +++ b/tests/ui/impl-trait/negative-reasoning.stderr @@ -1,13 +1,11 @@ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<_>` --> $DIR/negative-reasoning.rs:19:1 | LL | impl<T: std::fmt::Debug> AnotherTrait for T {} | ------------------------------------------- first implementation here ... LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` - | - = note: upstream crates may add a new impl of trait `std::marker::FnPtr` for type `OpaqueType` in future versions + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<_>` error: aborting due to 1 previous error diff --git a/tests/ui/impl-unused-tps.rs b/tests/ui/impl-unused-tps.rs index 3eb9daedf76..a5836db3c8e 100644 --- a/tests/ui/impl-unused-tps.rs +++ b/tests/ui/impl-unused-tps.rs @@ -1,34 +1,35 @@ -//~ ERROR overflow evaluating the requirement `([isize; 0], _): Sized - trait Foo<A> { - fn get(&self, A: &A) { } + fn get(&self, A: &A) {} } trait Bar { type Out; } -impl<T> Foo<T> for [isize;0] { +impl<T> Foo<T> for [isize; 0] { // OK, T is used in `Foo<T>`. } -impl<T,U> Foo<T> for [isize;1] { +impl<T, U> Foo<T> for [isize; 1] { //~^ ERROR the type parameter `U` is not constrained } -impl<T,U> Foo<T> for [isize;2] where T : Bar<Out=U> { +impl<T, U> Foo<T> for [isize; 2] +where + T: Bar<Out = U>, +{ // OK, `U` is now constrained by the output type parameter. } -impl<T:Bar<Out=U>,U> Foo<T> for [isize;3] { +impl<T: Bar<Out = U>, U> Foo<T> for [isize; 3] { // OK, same as above but written differently. } -impl<T,U> Foo<T> for U { +impl<T, U> Foo<T> for U { //~^ ERROR conflicting implementations of trait `Foo<_>` for type `[isize; 0]` } -impl<T,U> Bar for T { +impl<T, U> Bar for T { //~^ ERROR the type parameter `U` is not constrained type Out = U; @@ -36,28 +37,33 @@ impl<T,U> Bar for T { // Using `U` in an associated type within the impl is not good enough! } -impl<T,U> Bar for T - where T : Bar<Out=U> +impl<T, U> Bar for T +where + T: Bar<Out = U>, { - //~^^^ ERROR the type parameter `U` is not constrained - + //~^^^^ ERROR the type parameter `U` is not constrained by the impl trait, self type, or predicates + //~| ERROR conflicting implementations of trait `Bar` // This crafty self-referential attempt is still no good. } -impl<T,U,V> Foo<T> for T - where (T,U): Bar<Out=V> +impl<T, U, V> Foo<T> for T +where + (T, U): Bar<Out = V>, { - //~^^^ ERROR the type parameter `U` is not constrained - //~| ERROR the type parameter `V` is not constrained + //~^^^^ ERROR the type parameter `U` is not constrained + //~| ERROR the type parameter `V` is not constrained + //~| ERROR conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]` // Here, `V` is bound by an output type parameter, but the inputs // are not themselves constrained. } -impl<T,U,V> Foo<(T,U)> for T - where (T,U): Bar<Out=V> +impl<T, U, V> Foo<(T, U)> for T +where + (T, U): Bar<Out = V>, { + //~^^^^ ERROR conflicting implementations of trait `Foo<([isize; 0], _)>` for type `[isize; 0]` // As above, but both T and U ARE constrained. } -fn main() { } +fn main() {} diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/impl-unused-tps.stderr index af427cb5f3e..da4589dee82 100644 --- a/tests/ui/impl-unused-tps.stderr +++ b/tests/ui/impl-unused-tps.stderr @@ -1,56 +1,76 @@ error[E0119]: conflicting implementations of trait `Foo<_>` for type `[isize; 0]` - --> $DIR/impl-unused-tps.rs:27:1 + --> $DIR/impl-unused-tps.rs:28:1 | -LL | impl<T> Foo<T> for [isize;0] { - | ---------------------------- first implementation here +LL | impl<T> Foo<T> for [isize; 0] { + | ----------------------------- first implementation here ... -LL | impl<T,U> Foo<T> for U { - | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]` +LL | impl<T, U> Foo<T> for U { + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]` -error[E0275]: overflow evaluating the requirement `([isize; 0], _): Sized` +error[E0119]: conflicting implementations of trait `Bar` + --> $DIR/impl-unused-tps.rs:40:1 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`impl_unused_tps`) -note: required for `([isize; 0], _)` to implement `Bar` - --> $DIR/impl-unused-tps.rs:31:11 +LL | impl<T, U> Bar for T { + | -------------------- first implementation here +... +LL | / impl<T, U> Bar for T +LL | | where +LL | | T: Bar<Out = U>, + | |____________________^ conflicting implementation + +error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]` + --> $DIR/impl-unused-tps.rs:49:1 + | +LL | impl<T> Foo<T> for [isize; 0] { + | ----------------------------- first implementation here +... +LL | / impl<T, U, V> Foo<T> for T +LL | | where +LL | | (T, U): Bar<Out = V>, + | |_________________________^ conflicting implementation for `[isize; 0]` + +error[E0119]: conflicting implementations of trait `Foo<([isize; 0], _)>` for type `[isize; 0]` + --> $DIR/impl-unused-tps.rs:61:1 | -LL | impl<T,U> Bar for T { - | - ^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: 126 redundant requirements hidden - = note: required for `([isize; 0], _)` to implement `Bar` +LL | impl<T> Foo<T> for [isize; 0] { + | ----------------------------- first implementation here +... +LL | / impl<T, U, V> Foo<(T, U)> for T +LL | | where +LL | | (T, U): Bar<Out = V>, + | |_________________________^ conflicting implementation for `[isize; 0]` error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:15:8 + --> $DIR/impl-unused-tps.rs:13:9 | -LL | impl<T,U> Foo<T> for [isize;1] { - | ^ unconstrained type parameter +LL | impl<T, U> Foo<T> for [isize; 1] { + | ^ unconstrained type parameter error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:31:8 + --> $DIR/impl-unused-tps.rs:32:9 | -LL | impl<T,U> Bar for T { - | ^ unconstrained type parameter +LL | impl<T, U> Bar for T { + | ^ unconstrained type parameter error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:39:8 + --> $DIR/impl-unused-tps.rs:40:9 | -LL | impl<T,U> Bar for T - | ^ unconstrained type parameter +LL | impl<T, U> Bar for T + | ^ unconstrained type parameter error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:47:8 + --> $DIR/impl-unused-tps.rs:49:9 | -LL | impl<T,U,V> Foo<T> for T - | ^ unconstrained type parameter +LL | impl<T, U, V> Foo<T> for T + | ^ unconstrained type parameter error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:47:10 + --> $DIR/impl-unused-tps.rs:49:12 | -LL | impl<T,U,V> Foo<T> for T - | ^ unconstrained type parameter +LL | impl<T, U, V> Foo<T> for T + | ^ unconstrained type parameter -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0119, E0207, E0275. +Some errors have detailed explanations: E0119, E0207. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-2.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-2.rs new file mode 100644 index 00000000000..ca8b8b7e4d9 --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-2.rs @@ -0,0 +1,13 @@ +//@ check-pass +//@ known-bug: #25860 + +static UNIT: &'static &'static () = &&(); + +fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T, _: &()) -> &'a T { v } + +fn bad<'a, T>(x: &'a T) -> &'static T { + let f: fn(_, &'a T, &()) -> &'static T = foo; + f(UNIT, x, &()) +} + +fn main() {} diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.rs new file mode 100644 index 00000000000..226a6fa3016 --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.rs @@ -0,0 +1,13 @@ +// Regression test for #129021. + +static UNIT: &'static &'static () = &&(); + +fn foo<'a: 'a, 'b: 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v } + +fn bad<'a, T>(x: &'a T) -> &'static T { + let f: fn(_, &'a T) -> &'static T = foo; + //~^ ERROR lifetime may not live long enough + f(UNIT, x) +} + +fn main() {} diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.stderr b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.stderr new file mode 100644 index 00000000000..84d2a6d2b6a --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-early-bound.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-on-nested-references-plus-variance-early-bound.rs:8:12 + | +LL | fn bad<'a, T>(x: &'a T) -> &'static T { + | -- lifetime `'a` defined here +LL | let f: fn(_, &'a T) -> &'static T = foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.rs new file mode 100644 index 00000000000..f3068990189 --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.rs @@ -0,0 +1,19 @@ +// Regression test for #129021. + +trait ToArg<T> { + type Arg; +} +impl<T, U> ToArg<T> for U { + type Arg = T; +} + +fn extend_inner<'a, 'b>(x: &'a str) -> <&'b &'a () as ToArg<&'b str>>::Arg { x } +fn extend<'a, 'b>(x: &'a str) -> &'b str { + (extend_inner as fn(_) -> _)(x) + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let y = extend(&String::from("Hello World")); + println!("{}", y); +} diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.stderr b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.stderr new file mode 100644 index 00000000000..4cdb959786a --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance-unnormalized.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-on-nested-references-plus-variance-unnormalized.rs:12:5 + | +LL | fn extend<'a, 'b>(x: &'a str) -> &'b str { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | (extend_inner as fn(_) -> _)(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 1 previous error + diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs index f3401f34eec..6de81cba728 100644 --- a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.rs @@ -1,8 +1,4 @@ -//@ check-pass -//@ known-bug: #25860 - -// Should fail. The combination of variance and implied bounds for nested -// references allows us to infer a longer lifetime than we can prove. +// Regression test for #129021. static UNIT: &'static &'static () = &&(); @@ -10,6 +6,7 @@ fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v } fn bad<'a, T>(x: &'a T) -> &'static T { let f: fn(_, &'a T) -> &'static T = foo; + //~^ ERROR lifetime may not live long enough f(UNIT, x) } diff --git a/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.stderr b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.stderr new file mode 100644 index 00000000000..c96fa92937b --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-on-nested-references-plus-variance.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-on-nested-references-plus-variance.rs:8:12 + | +LL | fn bad<'a, T>(x: &'a T) -> &'static T { + | -- lifetime `'a` defined here +LL | let f: fn(_, &'a T) -> &'static T = foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/issues/issue-48728.rs b/tests/ui/issues/issue-48728.rs index 7ef05f4277b..8ad9289c65c 100644 --- a/tests/ui/issues/issue-48728.rs +++ b/tests/ui/issues/issue-48728.rs @@ -1,12 +1,8 @@ // Regression test for #48728, an ICE that occurred computing // coherence "help" information. -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver -//@[next] check-pass - -#[derive(Clone)] //[current]~ ERROR conflicting implementations of trait `Clone` +//@ check-pass +#[derive(Clone)] struct Node<T: ?Sized>(Box<T>); impl<T: Clone + ?Sized> Clone for Node<[T]> { diff --git a/tests/ui/lexer/prefixed-lifetime.rs b/tests/ui/lexer/prefixed-lifetime.rs new file mode 100644 index 00000000000..6191b97d576 --- /dev/null +++ b/tests/ui/lexer/prefixed-lifetime.rs @@ -0,0 +1,10 @@ +//@ edition: 2021 + +macro_rules! w { + ($($tt:tt)*) => {}; +} + +w!('foo#lifetime); +//~^ ERROR prefix `'foo` is unknown + +fn main() {} diff --git a/tests/ui/lexer/prefixed-lifetime.stderr b/tests/ui/lexer/prefixed-lifetime.stderr new file mode 100644 index 00000000000..39e8b5a2a57 --- /dev/null +++ b/tests/ui/lexer/prefixed-lifetime.stderr @@ -0,0 +1,14 @@ +error: prefix `'foo` is unknown + --> $DIR/prefixed-lifetime.rs:7:4 + | +LL | w!('foo#lifetime); + | ^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | w!('foo #lifetime); + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/raw/gen-lt.e2024.stderr b/tests/ui/lifetimes/raw/gen-lt.e2024.stderr new file mode 100644 index 00000000000..232453df8ef --- /dev/null +++ b/tests/ui/lifetimes/raw/gen-lt.e2024.stderr @@ -0,0 +1,8 @@ +error: lifetimes cannot use keyword names + --> $DIR/gen-lt.rs:11:11 + | +LL | fn gen_lt<'gen>() {} + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/raw/gen-lt.rs b/tests/ui/lifetimes/raw/gen-lt.rs new file mode 100644 index 00000000000..4f3ede5b4a2 --- /dev/null +++ b/tests/ui/lifetimes/raw/gen-lt.rs @@ -0,0 +1,14 @@ +//@ revisions: e2021 e2024 + +//@[e2021] edition:2021 +//@[e2024] edition:2024 +//@[e2024] compile-flags: -Zunstable-options + +//@[e2021] check-pass + +fn raw_gen_lt<'r#gen>() {} + +fn gen_lt<'gen>() {} +//[e2024]~^ ERROR lifetimes cannot use keyword names + +fn main() {} diff --git a/tests/ui/lifetimes/raw/lifetimes-eq.rs b/tests/ui/lifetimes/raw/lifetimes-eq.rs new file mode 100644 index 00000000000..dddafb829ba --- /dev/null +++ b/tests/ui/lifetimes/raw/lifetimes-eq.rs @@ -0,0 +1,8 @@ +//@ edition: 2021 +//@ check-pass + +// Test that `'r#a` is `'a`. + +fn test<'r#a>(x: &'a ()) {} + +fn main() {} diff --git a/tests/ui/lifetimes/raw/macro-lt.rs b/tests/ui/lifetimes/raw/macro-lt.rs new file mode 100644 index 00000000000..d1167b00467 --- /dev/null +++ b/tests/ui/lifetimes/raw/macro-lt.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ edition: 2021 + +macro_rules! lifetime { + ($lt:lifetime) => { + fn hello<$lt>() {} + } +} + +lifetime!('r#struct); + +fn main() {} diff --git a/tests/ui/lifetimes/raw/multiple-prefixes.rs b/tests/ui/lifetimes/raw/multiple-prefixes.rs new file mode 100644 index 00000000000..f335373d8a7 --- /dev/null +++ b/tests/ui/lifetimes/raw/multiple-prefixes.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 + +fn test(x: &'r#r#r ()) {} +//~^ ERROR expected type, found `#` + +fn main() {} diff --git a/tests/ui/lifetimes/raw/multiple-prefixes.stderr b/tests/ui/lifetimes/raw/multiple-prefixes.stderr new file mode 100644 index 00000000000..8d5479e0a4f --- /dev/null +++ b/tests/ui/lifetimes/raw/multiple-prefixes.stderr @@ -0,0 +1,8 @@ +error: expected type, found `#` + --> $DIR/multiple-prefixes.rs:3:17 + | +LL | fn test(x: &'r#r#r ()) {} + | ^ expected type + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/raw/prim-lt.rs b/tests/ui/lifetimes/raw/prim-lt.rs new file mode 100644 index 00000000000..ca45efb65fd --- /dev/null +++ b/tests/ui/lifetimes/raw/prim-lt.rs @@ -0,0 +1,8 @@ +//@ check-pass +//@ edition: 2021 + +// Checks a primitive name can be defined as a lifetime. + +fn foo<'r#i32>() {} + +fn main() {} diff --git a/tests/ui/lifetimes/raw/simple.rs b/tests/ui/lifetimes/raw/simple.rs new file mode 100644 index 00000000000..6f70a272203 --- /dev/null +++ b/tests/ui/lifetimes/raw/simple.rs @@ -0,0 +1,21 @@ +//@ check-pass +//@ edition: 2021 + +fn foo<'r#struct>() {} + +fn hr<T>() where for<'r#struct> T: Into<&'r#struct ()> {} + +trait Foo<'r#struct> {} + +trait Bar<'r#struct> { + fn method(&'r#struct self) {} + fn method2(self: &'r#struct Self) {} +} + +fn labeled() { + 'r#struct: loop { + break 'r#struct; + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/raw/static-lt.rs b/tests/ui/lifetimes/raw/static-lt.rs new file mode 100644 index 00000000000..1fec7097dab --- /dev/null +++ b/tests/ui/lifetimes/raw/static-lt.rs @@ -0,0 +1,8 @@ +//@ check-pass +//@ edition: 2021 + +// Makes sure that `'r#static` is `'static` + +const FOO: &'r#static str = "hello, world"; + +fn main() {} diff --git a/tests/ui/lifetimes/raw/three-tokens.rs b/tests/ui/lifetimes/raw/three-tokens.rs new file mode 100644 index 00000000000..2ae54ebbcb5 --- /dev/null +++ b/tests/ui/lifetimes/raw/three-tokens.rs @@ -0,0 +1,12 @@ +//@ edition: 2015 +//@ check-pass +// Ensure that we parse `'r#lt` as three tokens in edition 2015. + +macro_rules! ed2015 { + ('r # lt) => {}; + ($lt:lifetime) => { compile_error!() }; +} + +ed2015!('r#lt); + +fn main() {} diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr index 8c5426a60cb..2d8c6e99643 100644 --- a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr +++ b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr @@ -9,6 +9,10 @@ note: the lint level is defined here | LL | #![deny(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { + | +++++++ error: aborting due to 1 previous error diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr index c465aab1a03..3c01375d501 100644 --- a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr +++ b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr @@ -9,6 +9,10 @@ note: the lint level is defined here | LL | #[warn(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | fn bar(x: &'static u8) -> &'static u8 { + | +++++++ error: elided lifetime has a name --> $DIR/not-tied-to-crate.rs:11:31 @@ -21,6 +25,10 @@ note: the lint level is defined here | LL | #[deny(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | fn baz(x: &'static u8) -> &'static u8 { + | +++++++ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/lint/elided-named-lifetimes/static.stderr b/tests/ui/lint/elided-named-lifetimes/static.stderr index d2e9776cb4f..fa2a2d3460f 100644 --- a/tests/ui/lint/elided-named-lifetimes/static.stderr +++ b/tests/ui/lint/elided-named-lifetimes/static.stderr @@ -9,24 +9,43 @@ note: the lint level is defined here | LL | #![deny(elided_named_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider specifying it explicitly + | +LL | fn ampersand(x: &'static u8) -> &'static u8 { + | +++++++ error: elided lifetime has a name --> $DIR/static.rs:23:32 | LL | fn brackets(x: &'static u8) -> Brackets { | ^^^^^^^^ this elided lifetime gets resolved as `'static` + | +help: consider specifying it explicitly + | +LL | fn brackets(x: &'static u8) -> Brackets<'static> { + | +++++++++ error: elided lifetime has a name --> $DIR/static.rs:30:34 | LL | fn comma(x: &'static u8) -> Comma<u8> { | ^ this elided lifetime gets resolved as `'static` + | +help: consider specifying it explicitly + | +LL | fn comma(x: &'static u8) -> Comma<'static, u8> { + | ++++++++ error: elided lifetime has a name --> $DIR/static.rs:35:35 | LL | fn underscore(x: &'static u8) -> &'_ u8 { | ^^ this elided lifetime gets resolved as `'static` + | +help: consider specifying it explicitly + | +LL | fn underscore(x: &'static u8) -> &'static u8 { + | ~~~~~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/parser/extern-crate-unexpected-token.stderr b/tests/ui/parser/extern-crate-unexpected-token.stderr index f83bb3e3e35..951b0274b0d 100644 --- a/tests/ui/parser/extern-crate-unexpected-token.stderr +++ b/tests/ui/parser/extern-crate-unexpected-token.stderr @@ -3,6 +3,11 @@ error: expected one of `crate` or `{`, found `crte` | LL | extern crte foo; | ^^^^ expected one of `crate` or `{` + | +help: there is a keyword `crate` with a similar name + | +LL | extern crate foo; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr index 79c574ead61..00f372bc008 100644 --- a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr +++ b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr @@ -8,10 +8,16 @@ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:4:17 | LL | fn foo(&mur Self) {} - | -----^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `<identifier>: <type>` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn foo(&mut Self) {} + | ~~~ +help: declare the type after the parameter binding + | +LL | fn foo(<identifier>: <type>) {} + | ~~~~~~~~~~~~~~~~~~~~ error: unexpected lifetime `'static` in pattern --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:13 @@ -35,16 +41,27 @@ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:25 | LL | fn bar(&'static mur Self) {} - | -------------^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `<identifier>: <type>` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn bar(&'static mut Self) {} + | ~~~ +help: declare the type after the parameter binding + | +LL | fn bar(<identifier>: <type>) {} + | ~~~~~~~~~~~~~~~~~~~~ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:14:17 | LL | fn baz(&mur Self @ _) {} | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn baz(&mut Self @ _) {} + | ~~~ error[E0533]: expected unit struct, found self constructor `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:4:17 diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.rs b/tests/ui/parser/misspelled-keywords/assoc-type.rs new file mode 100644 index 00000000000..a6b694a2abe --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/assoc-type.rs @@ -0,0 +1,6 @@ +trait Animal { + Type Result = u8; + //~^ ERROR expected one of +} + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.stderr b/tests/ui/parser/misspelled-keywords/assoc-type.stderr new file mode 100644 index 00000000000..677da53e340 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/assoc-type.stderr @@ -0,0 +1,18 @@ +error: expected one of `!` or `::`, found `Result` + --> $DIR/assoc-type.rs:2:10 + | +LL | trait Animal { + | - while parsing this item list starting here +LL | Type Result = u8; + | ^^^^^^ expected one of `!` or `::` +LL | +LL | } + | - the item list ends here + | +help: write keyword `type` in lowercase + | +LL | type Result = u8; + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/async-move.rs b/tests/ui/parser/misspelled-keywords/async-move.rs new file mode 100644 index 00000000000..702a905e918 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/async-move.rs @@ -0,0 +1,6 @@ +//@ edition: 2018 + +fn main() { + async Move {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr new file mode 100644 index 00000000000..4be4b56e505 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/async-move.stderr @@ -0,0 +1,13 @@ +error: expected one of `move`, `|`, or `||`, found `Move` + --> $DIR/async-move.rs:4:11 + | +LL | async Move {} + | ^^^^ expected one of `move`, `|`, or `||` + | +help: write keyword `move` in lowercase + | +LL | async move {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/const-fn.rs b/tests/ui/parser/misspelled-keywords/const-fn.rs new file mode 100644 index 00000000000..c4174b6a2ef --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-fn.rs @@ -0,0 +1,5 @@ +cnst fn code() {} +//~^ ERROR expected one of + +fn main() { +} diff --git a/tests/ui/parser/misspelled-keywords/const-fn.stderr b/tests/ui/parser/misspelled-keywords/const-fn.stderr new file mode 100644 index 00000000000..5646b26143c --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-fn.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found keyword `fn` + --> $DIR/const-fn.rs:1:6 + | +LL | cnst fn code() {} + | ^^ expected one of `!` or `::` + | +help: there is a keyword `const` with a similar name + | +LL | const fn code() {} + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/const-generics.rs b/tests/ui/parser/misspelled-keywords/const-generics.rs new file mode 100644 index 00000000000..2df64a87e27 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-generics.rs @@ -0,0 +1,4 @@ +fn foo<consta N: usize>(_arr: [i32; N]) {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/const-generics.stderr b/tests/ui/parser/misspelled-keywords/const-generics.stderr new file mode 100644 index 00000000000..fd59999ab63 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const-generics.stderr @@ -0,0 +1,13 @@ +error: expected one of `,`, `:`, `=`, or `>`, found `N` + --> $DIR/const-generics.rs:1:15 + | +LL | fn foo<consta N: usize>(_arr: [i32; N]) {} + | ^ expected one of `,`, `:`, `=`, or `>` + | +help: there is a keyword `const` with a similar name + | +LL | fn foo<const N: usize>(_arr: [i32; N]) {} + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/const.rs b/tests/ui/parser/misspelled-keywords/const.rs new file mode 100644 index 00000000000..b481408cb62 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const.rs @@ -0,0 +1,4 @@ +cons A: u8 = 10; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/const.stderr b/tests/ui/parser/misspelled-keywords/const.stderr new file mode 100644 index 00000000000..35e4d731db7 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/const.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `A` + --> $DIR/const.rs:1:6 + | +LL | cons A: u8 = 10; + | ^ expected one of `!` or `::` + | +help: there is a keyword `const` with a similar name + | +LL | const A: u8 = 10; + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/for-loop.rs b/tests/ui/parser/misspelled-keywords/for-loop.rs new file mode 100644 index 00000000000..6aba581cf17 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/for-loop.rs @@ -0,0 +1,4 @@ +fn main() { + form i in 1..10 {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/for-loop.stderr b/tests/ui/parser/misspelled-keywords/for-loop.stderr new file mode 100644 index 00000000000..d2236ab074d --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/for-loop.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `i` + --> $DIR/for-loop.rs:2:10 + | +LL | form i in 1..10 {} + | ^ expected one of 8 possible tokens + | +help: there is a keyword `for` with a similar name + | +LL | for i in 1..10 {} + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/hrdt.rs b/tests/ui/parser/misspelled-keywords/hrdt.rs new file mode 100644 index 00000000000..9ca9e1bfbee --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/hrdt.rs @@ -0,0 +1,16 @@ +struct Closure<F> { + data: (u8, u16), + func: F, +} + +impl<F> Closure<F> + Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, +//~^ ERROR expected one of +{ + fn call(&self) -> &u8 { + (self.func)(&self.data) + } +} + + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/hrdt.stderr b/tests/ui/parser/misspelled-keywords/hrdt.stderr new file mode 100644 index 00000000000..5393a730506 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/hrdt.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found keyword `for` + --> $DIR/hrdt.rs:7:11 + | +LL | Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, + | ^^^ expected one of 7 possible tokens + | +help: write keyword `where` in lowercase (notice the capitalization difference) + | +LL | where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-block.rs b/tests/ui/parser/misspelled-keywords/impl-block.rs new file mode 100644 index 00000000000..dc2570c22c5 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-block.rs @@ -0,0 +1,6 @@ +struct Human; + +ipml Human {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-block.stderr b/tests/ui/parser/misspelled-keywords/impl-block.stderr new file mode 100644 index 00000000000..d86ae326ce2 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-block.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `Human` + --> $DIR/impl-block.rs:3:6 + | +LL | ipml Human {} + | ^^^^^ expected one of `!` or `::` + | +help: there is a keyword `impl` with a similar name + | +LL | impl Human {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-return.rs b/tests/ui/parser/misspelled-keywords/impl-return.rs new file mode 100644 index 00000000000..c9d1973179e --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-return.rs @@ -0,0 +1,4 @@ +fn code() -> Impl Display {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-return.stderr b/tests/ui/parser/misspelled-keywords/impl-return.stderr new file mode 100644 index 00000000000..883f5cea73e --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-return.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Display` + --> $DIR/impl-return.rs:1:19 + | +LL | fn code() -> Impl Display {} + | ^^^^^^^ expected one of 7 possible tokens + | +help: write keyword `impl` in lowercase (notice the capitalization difference) + | +LL | fn code() -> impl Display {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-trait-for.rs b/tests/ui/parser/misspelled-keywords/impl-trait-for.rs new file mode 100644 index 00000000000..c6f3fcda5ad --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait-for.rs @@ -0,0 +1,6 @@ +struct Human; + +impl Debug form Human {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr b/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr new file mode 100644 index 00000000000..8dd5a4645f3 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Human` + --> $DIR/impl-trait-for.rs:3:17 + | +LL | impl Debug form Human {} + | ^^^^^ expected one of 7 possible tokens + | +help: there is a keyword `for` with a similar name + | +LL | impl Debug for Human {} + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/impl-trait.rs b/tests/ui/parser/misspelled-keywords/impl-trait.rs new file mode 100644 index 00000000000..99380b8ac0e --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait.rs @@ -0,0 +1,4 @@ +fn code<T: impll Debug>() -> u8 {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/impl-trait.stderr b/tests/ui/parser/misspelled-keywords/impl-trait.stderr new file mode 100644 index 00000000000..15a8f99b8b1 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/impl-trait.stderr @@ -0,0 +1,17 @@ +error: expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`, found `Debug` + --> $DIR/impl-trait.rs:1:18 + | +LL | fn code<T: impll Debug>() -> u8 {} + | ^^^^^ expected one of 7 possible tokens + | +help: there is a keyword `impl` with a similar name + | +LL | fn code<T: impl Debug>() -> u8 {} + | ~~~~ +help: you might have meant to end the type parameters here + | +LL | fn code<T: impll> Debug>() -> u8 {} + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/let-else.rs b/tests/ui/parser/misspelled-keywords/let-else.rs new file mode 100644 index 00000000000..0d5a03e3e43 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-else.rs @@ -0,0 +1,4 @@ +fn main() { + let Some(a) = Some(10) elze {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/let-else.stderr b/tests/ui/parser/misspelled-keywords/let-else.stderr new file mode 100644 index 00000000000..6f41a0d99db --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-else.stderr @@ -0,0 +1,13 @@ +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `elze` + --> $DIR/let-else.rs:2:28 + | +LL | let Some(a) = Some(10) elze {} + | ^^^^ expected one of `.`, `;`, `?`, `else`, or an operator + | +help: there is a keyword `else` with a similar name + | +LL | let Some(a) = Some(10) else {} + | ~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/let-mut.rs b/tests/ui/parser/misspelled-keywords/let-mut.rs new file mode 100644 index 00000000000..83228fe8c66 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-mut.rs @@ -0,0 +1,4 @@ +fn main() { + let muta a = 10; + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/let-mut.stderr b/tests/ui/parser/misspelled-keywords/let-mut.stderr new file mode 100644 index 00000000000..766d2a04909 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let-mut.stderr @@ -0,0 +1,13 @@ +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `a` + --> $DIR/let-mut.rs:2:14 + | +LL | let muta a = 10; + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | let mut a = 10; + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/let.rs b/tests/ui/parser/misspelled-keywords/let.rs new file mode 100644 index 00000000000..461c3e518db --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let.rs @@ -0,0 +1,9 @@ +fn main() { + Let a = 10; + //~^ ERROR expected one of +} + +fn code() { + lett a = 10; + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/let.stderr b/tests/ui/parser/misspelled-keywords/let.stderr new file mode 100644 index 00000000000..c2dcdef541d --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/let.stderr @@ -0,0 +1,24 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/let.rs:2:9 + | +LL | Let a = 10; + | ^ expected one of 8 possible tokens + | +help: write keyword `let` in lowercase + | +LL | let a = 10; + | ~~~ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/let.rs:7:10 + | +LL | lett a = 10; + | ^ expected one of 8 possible tokens + | +help: there is a keyword `let` with a similar name + | +LL | let a = 10; + | ~~~ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/misspelled-keywords/match.rs b/tests/ui/parser/misspelled-keywords/match.rs new file mode 100644 index 00000000000..a31840a2d71 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/match.rs @@ -0,0 +1,5 @@ +fn main() { + let a = 10; + matche a {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/match.stderr b/tests/ui/parser/misspelled-keywords/match.stderr new file mode 100644 index 00000000000..90780ebd38e --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/match.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/match.rs:3:12 + | +LL | matche a {} + | ^ expected one of 8 possible tokens + | +help: there is a keyword `match` with a similar name + | +LL | match a {} + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/mod.rs b/tests/ui/parser/misspelled-keywords/mod.rs new file mode 100644 index 00000000000..24f0101bc5a --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/mod.rs @@ -0,0 +1,4 @@ +mode parser; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/mod.stderr b/tests/ui/parser/misspelled-keywords/mod.stderr new file mode 100644 index 00000000000..6daeb4e5a15 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/mod.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `parser` + --> $DIR/mod.rs:1:6 + | +LL | mode parser; + | ^^^^^^ expected one of `!` or `::` + | +help: there is a keyword `mod` with a similar name + | +LL | mod parser; + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/pub-fn.rs b/tests/ui/parser/misspelled-keywords/pub-fn.rs new file mode 100644 index 00000000000..50d7129ce51 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/pub-fn.rs @@ -0,0 +1,5 @@ +puB fn code() {} +//~^ ERROR expected one of + +fn main() { +} diff --git a/tests/ui/parser/misspelled-keywords/pub-fn.stderr b/tests/ui/parser/misspelled-keywords/pub-fn.stderr new file mode 100644 index 00000000000..82ca7105a49 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/pub-fn.stderr @@ -0,0 +1,13 @@ +error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB` + --> $DIR/pub-fn.rs:1:1 + | +LL | puB fn code() {} + | ^^^ expected one of 21 possible tokens + | +help: write keyword `pub` in lowercase + | +LL | pub fn code() {} + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/ref.rs b/tests/ui/parser/misspelled-keywords/ref.rs new file mode 100644 index 00000000000..76b367ae99b --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/ref.rs @@ -0,0 +1,9 @@ +fn main() { + let a = Some(vec![1, 2]); + match a { + Some(refe list) => println!("{list:?}"), + //~^ ERROR expected one of + //~| ERROR this pattern has 2 fields, + _ => println!("none"), + } +} diff --git a/tests/ui/parser/misspelled-keywords/ref.stderr b/tests/ui/parser/misspelled-keywords/ref.stderr new file mode 100644 index 00000000000..3a79b7bdb00 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/ref.stderr @@ -0,0 +1,27 @@ +error: expected one of `)`, `,`, `@`, or `|`, found `list` + --> $DIR/ref.rs:4:19 + | +LL | Some(refe list) => println!("{list:?}"), + | ^^^^ expected one of `)`, `,`, `@`, or `|` + | +help: there is a keyword `ref` with a similar name + | +LL | Some(ref list) => println!("{list:?}"), + | ~~~ +help: missing `,` + | +LL | Some(refe, list) => println!("{list:?}"), + | + + +error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field + --> $DIR/ref.rs:4:14 + | +LL | Some(refe list) => println!("{list:?}"), + | ^^^^ ^^^^ expected 1 field, found 2 + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: tuple variant has 1 field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0023`. diff --git a/tests/ui/parser/misspelled-keywords/return.rs b/tests/ui/parser/misspelled-keywords/return.rs new file mode 100644 index 00000000000..4bbe55d37da --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/return.rs @@ -0,0 +1,7 @@ +fn code() -> u8 { + let a = 10; + returnn a; + //~^ ERROR expected one of +} + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/return.stderr b/tests/ui/parser/misspelled-keywords/return.stderr new file mode 100644 index 00000000000..efa45f32299 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/return.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/return.rs:3:13 + | +LL | returnn a; + | ^ expected one of 8 possible tokens + | +help: there is a keyword `return` with a similar name + | +LL | return a; + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/static-mut.rs b/tests/ui/parser/misspelled-keywords/static-mut.rs new file mode 100644 index 00000000000..6509f62470a --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static-mut.rs @@ -0,0 +1,5 @@ +static muta a: u8 = 0; +//~^ ERROR expected one of +//~| ERROR missing type for + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/static-mut.stderr b/tests/ui/parser/misspelled-keywords/static-mut.stderr new file mode 100644 index 00000000000..3c25af548a3 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static-mut.stderr @@ -0,0 +1,24 @@ +error: expected one of `:`, `;`, or `=`, found `a` + --> $DIR/static-mut.rs:1:13 + | +LL | static muta a: u8 = 0; + | ^ expected one of `:`, `;`, or `=` + | +help: there is a keyword `mut` with a similar name + | +LL | static mut a: u8 = 0; + | ~~~ + +error: missing type for `static` item + --> $DIR/static-mut.rs:1:12 + | +LL | static muta a: u8 = 0; + | ^ + | +help: provide a type for the item + | +LL | static muta: <type> a: u8 = 0; + | ++++++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/misspelled-keywords/static.rs b/tests/ui/parser/misspelled-keywords/static.rs new file mode 100644 index 00000000000..240f4f52c8d --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static.rs @@ -0,0 +1,4 @@ +Static a = 0; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/static.stderr b/tests/ui/parser/misspelled-keywords/static.stderr new file mode 100644 index 00000000000..003aa3929bc --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/static.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `a` + --> $DIR/static.rs:1:8 + | +LL | Static a = 0; + | ^ expected one of `!` or `::` + | +help: write keyword `static` in lowercase (notice the capitalization difference) + | +LL | static a = 0; + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/struct.rs b/tests/ui/parser/misspelled-keywords/struct.rs new file mode 100644 index 00000000000..0f64dec6f56 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/struct.rs @@ -0,0 +1,4 @@ +Struct Foor { +//~^ ERROR expected one of + hello: String, +} diff --git a/tests/ui/parser/misspelled-keywords/struct.stderr b/tests/ui/parser/misspelled-keywords/struct.stderr new file mode 100644 index 00000000000..559182f9c8f --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/struct.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `Foor` + --> $DIR/struct.rs:1:8 + | +LL | Struct Foor { + | ^^^^ expected one of `!` or `::` + | +help: write keyword `struct` in lowercase (notice the capitalization difference) + | +LL | struct Foor { + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/unsafe-fn.rs b/tests/ui/parser/misspelled-keywords/unsafe-fn.rs new file mode 100644 index 00000000000..49a1322ad63 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/unsafe-fn.rs @@ -0,0 +1,4 @@ +unsafee fn code() {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr b/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr new file mode 100644 index 00000000000..b13281b0395 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found keyword `fn` + --> $DIR/unsafe-fn.rs:1:9 + | +LL | unsafee fn code() {} + | ^^ expected one of `!` or `::` + | +help: there is a keyword `unsafe` with a similar name + | +LL | unsafe fn code() {} + | ~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/use.rs b/tests/ui/parser/misspelled-keywords/use.rs new file mode 100644 index 00000000000..f4911654354 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/use.rs @@ -0,0 +1,4 @@ +usee a::b; +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/use.stderr b/tests/ui/parser/misspelled-keywords/use.stderr new file mode 100644 index 00000000000..db6dffdb613 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/use.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found `a` + --> $DIR/use.rs:1:6 + | +LL | usee a::b; + | ^ expected one of `!` or `::` + | +help: there is a keyword `use` with a similar name + | +LL | use a::b; + | ~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/where-clause.rs b/tests/ui/parser/misspelled-keywords/where-clause.rs new file mode 100644 index 00000000000..c03d04d5fee --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/where-clause.rs @@ -0,0 +1,8 @@ +fn code<T>() -> u8 +wheree +//~^ ERROR expected one of + T: Debug, +{ +} + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/where-clause.stderr b/tests/ui/parser/misspelled-keywords/where-clause.stderr new file mode 100644 index 00000000000..5143c30ca51 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/where-clause.stderr @@ -0,0 +1,15 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `wheree` + --> $DIR/where-clause.rs:2:1 + | +LL | fn code<T>() -> u8 + | - expected one of 7 possible tokens +LL | wheree + | ^^^^^^ unexpected token + | +help: there is a keyword `where` with a similar name + | +LL | where + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/while-loop.rs b/tests/ui/parser/misspelled-keywords/while-loop.rs new file mode 100644 index 00000000000..37d337f3f19 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-loop.rs @@ -0,0 +1,5 @@ +fn main() { + whilee a < b { + //~^ ERROR expected one of + } +} diff --git a/tests/ui/parser/misspelled-keywords/while-loop.stderr b/tests/ui/parser/misspelled-keywords/while-loop.stderr new file mode 100644 index 00000000000..7d150443f57 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-loop.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` + --> $DIR/while-loop.rs:2:12 + | +LL | whilee a < b { + | ^ expected one of 8 possible tokens + | +help: there is a keyword `while` with a similar name + | +LL | while a < b { + | ~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/misspelled-keywords/while-without-identifiers.rs b/tests/ui/parser/misspelled-keywords/while-without-identifiers.rs new file mode 100644 index 00000000000..203db8306af --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-without-identifiers.rs @@ -0,0 +1,4 @@ +fn main() { + whilee 2 > 1 {} + //~^ ERROR expected one of +} diff --git a/tests/ui/parser/misspelled-keywords/while-without-identifiers.stderr b/tests/ui/parser/misspelled-keywords/while-without-identifiers.stderr new file mode 100644 index 00000000000..121e3931314 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/while-without-identifiers.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `2` + --> $DIR/while-without-identifiers.rs:2:12 + | +LL | whilee 2 > 1 {} + | ^ expected one of 8 possible tokens + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr index b1074f77e00..ff552f663c7 100644 --- a/tests/ui/rust-2024/gen-kw.e2015.stderr +++ b/tests/ui/rust-2024/gen-kw.e2015.stderr @@ -31,5 +31,14 @@ LL | () => { mod test { fn gen() {} } } = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> -error: aborting due to 3 previous errors +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:25:9 + | +LL | fn test<'gen>() {} + | ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: aborting due to 4 previous errors diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr index b902cff7fdb..efa812069c3 100644 --- a/tests/ui/rust-2024/gen-kw.e2018.stderr +++ b/tests/ui/rust-2024/gen-kw.e2018.stderr @@ -31,5 +31,14 @@ LL | () => { mod test { fn gen() {} } } = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> -error: aborting due to 3 previous errors +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:25:9 + | +LL | fn test<'gen>() {} + | ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: aborting due to 4 previous errors diff --git a/tests/ui/rust-2024/gen-kw.rs b/tests/ui/rust-2024/gen-kw.rs index 04251cbcac4..5a658470c0a 100644 --- a/tests/ui/rust-2024/gen-kw.rs +++ b/tests/ui/rust-2024/gen-kw.rs @@ -22,4 +22,9 @@ macro_rules! t { //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! } +fn test<'gen>() {} +//~^ ERROR `gen` is a keyword in the 2024 edition +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! +//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + t!(); diff --git a/tests/crashes/118987-2.rs b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.rs index 4382a7bcb63..1691530fa0a 100644 --- a/tests/crashes/118987-2.rs +++ b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.rs @@ -1,4 +1,4 @@ -//@ known-bug: #118987 +// regression test for #118987 #![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Assoc { @@ -15,3 +15,5 @@ trait Foo {} impl Foo for <u8 as Assoc>::Output {} impl Foo for <u16 as Assoc>::Output {} +//~^ ERROR the trait bound `u16: Assoc` is not satisfied +fn main() {} diff --git a/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.stderr b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.stderr new file mode 100644 index 00000000000..a2fca2ef5b6 --- /dev/null +++ b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-impl-normalization-ambig-2.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `u16: Assoc` is not satisfied + --> $DIR/default-impl-normalization-ambig-2.rs:17:14 + | +LL | impl Foo for <u16 as Assoc>::Output {} + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Assoc` is not implemented for `u16` + | + = help: the trait `Assoc` is implemented for `u8` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/crashes/74299.rs b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.rs index 0e2ddce1c5b..af7cf332d5f 100644 --- a/tests/crashes/74299.rs +++ b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.rs @@ -1,5 +1,5 @@ -//@ known-bug: #74299 -#![feature(specialization)] +// regression test for #73299. +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait X { type U; @@ -18,6 +18,7 @@ trait Y { impl Y for <() as X>::U {} impl Y for <i32 as X>::U {} +//~^ ERROR conflicting implementations of trait `Y` for type `<() as X>::U` fn main() { ().f().g(); diff --git a/tests/ui/specialization/coherence/default-item-normalization-ambig-1.stderr b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.stderr new file mode 100644 index 00000000000..a15151cc9c4 --- /dev/null +++ b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-item-normalization-ambig-1.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0119]: conflicting implementations of trait `Y` for type `<() as X>::U` + --> $DIR/default-item-normalization-ambig-1.rs:20:1 + | +LL | impl Y for <() as X>::U {} + | ----------------------- first implementation here +LL | impl Y for <i32 as X>::U {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<() as X>::U` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/defaultimpl/specialization-no-default.rs b/tests/ui/specialization/defaultimpl/specialization-no-default.rs index 661724eef8a..ddc32337306 100644 --- a/tests/ui/specialization/defaultimpl/specialization-no-default.rs +++ b/tests/ui/specialization/defaultimpl/specialization-no-default.rs @@ -71,7 +71,8 @@ impl<T: Clone> Redundant for T { } default impl Redundant for i32 { - fn redundant(&self) {} //~ ERROR E0520 + fn redundant(&self) {} + //~^ ERROR `redundant` specializes an item from a parent `impl`, but that item is not marked `default` } fn main() {} diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.current.stderr b/tests/ui/specialization/specialization-default-items-drop-coherence.current.stderr new file mode 100644 index 00000000000..36df6bfd9fc --- /dev/null +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.current.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Overlap` for type `u32` + --> $DIR/specialization-default-items-drop-coherence.rs:26:1 + | +LL | impl Overlap for u32 { + | -------------------- first implementation here +... +LL | impl Overlap for <u32 as Default>::Id { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr b/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr index e9498a00317..36df6bfd9fc 100644 --- a/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Overlap` for type `u32` - --> $DIR/specialization-default-items-drop-coherence.rs:29:1 + --> $DIR/specialization-default-items-drop-coherence.rs:26:1 | LL | impl Overlap for u32 { | -------------------- first implementation here diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.rs b/tests/ui/specialization/specialization-default-items-drop-coherence.rs index 6dc01277639..b3c1f72777c 100644 --- a/tests/ui/specialization/specialization-default-items-drop-coherence.rs +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.rs @@ -1,8 +1,5 @@ -//@ revisions: classic coherence next +//@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[coherence] compile-flags: -Znext-solver=coherence -//@[classic] check-pass -//@[classic] known-bug: #105782 // Should fail. Default items completely drop candidates instead of ambiguity, // which is unsound during coherence, since coherence requires completeness. @@ -27,8 +24,7 @@ impl Overlap for u32 { } impl Overlap for <u32 as Default>::Id { - //[coherence]~^ ERROR conflicting implementations of trait `Overlap` for type `u32` - //[next]~^^ ERROR conflicting implementations of trait `Overlap` for type `u32` + //~^ ERROR conflicting implementations of trait `Overlap` for type `u32` type Assoc = Box<usize>; } diff --git a/tests/ui/specialization/specialization-overlap-projection.current.stderr b/tests/ui/specialization/specialization-overlap-projection.current.stderr index a69826fa96b..4e77cb17fbb 100644 --- a/tests/ui/specialization/specialization-overlap-projection.current.stderr +++ b/tests/ui/specialization/specialization-overlap-projection.current.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-overlap-projection.rs:10:12 + --> $DIR/specialization-overlap-projection.rs:4:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -8,5 +8,23 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +error[E0119]: conflicting implementations of trait `Foo` for type `u32` + --> $DIR/specialization-overlap-projection.rs:19:1 + | +LL | impl Foo for u32 {} + | ---------------- first implementation here +LL | impl Foo for <u8 as Assoc>::Output {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error[E0119]: conflicting implementations of trait `Foo` for type `u32` + --> $DIR/specialization-overlap-projection.rs:21:1 + | +LL | impl Foo for u32 {} + | ---------------- first implementation here +... +LL | impl Foo for <u16 as Assoc>::Output {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to 2 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-overlap-projection.next.stderr b/tests/ui/specialization/specialization-overlap-projection.next.stderr index 5b17696162e..4e77cb17fbb 100644 --- a/tests/ui/specialization/specialization-overlap-projection.next.stderr +++ b/tests/ui/specialization/specialization-overlap-projection.next.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-overlap-projection.rs:10:12 + --> $DIR/specialization-overlap-projection.rs:4:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default error[E0119]: conflicting implementations of trait `Foo` for type `u32` - --> $DIR/specialization-overlap-projection.rs:25:1 + --> $DIR/specialization-overlap-projection.rs:19:1 | LL | impl Foo for u32 {} | ---------------- first implementation here @@ -17,7 +17,7 @@ LL | impl Foo for <u8 as Assoc>::Output {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` error[E0119]: conflicting implementations of trait `Foo` for type `u32` - --> $DIR/specialization-overlap-projection.rs:27:1 + --> $DIR/specialization-overlap-projection.rs:21:1 | LL | impl Foo for u32 {} | ---------------- first implementation here diff --git a/tests/ui/specialization/specialization-overlap-projection.rs b/tests/ui/specialization/specialization-overlap-projection.rs index 16dccf82dcb..f7a2a792243 100644 --- a/tests/ui/specialization/specialization-overlap-projection.rs +++ b/tests/ui/specialization/specialization-overlap-projection.rs @@ -1,13 +1,8 @@ -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver -//@[current] check-pass - // Test that impls on projected self types can resolve overlap, even when the // projections involve specialization, so long as the associated type is // provided by the most specialized impl. - -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes trait Assoc { type Output; @@ -23,8 +18,8 @@ impl Assoc for u16 { type Output = u16; } trait Foo {} impl Foo for u32 {} impl Foo for <u8 as Assoc>::Output {} -//[next]~^ ERROR conflicting implementations of trait `Foo` for type `u32` +//~^ ERROR conflicting implementations of trait `Foo` for type `u32` impl Foo for <u16 as Assoc>::Output {} -//[next]~^ ERROR conflicting implementations of trait `Foo` for type `u32` +//~^ ERROR conflicting implementations of trait `Foo` for type `u32` fn main() {} diff --git a/tests/ui/specialization/specialization-overlap-projection.stderr b/tests/ui/specialization/specialization-overlap-projection.stderr new file mode 100644 index 00000000000..5f3cd9c66cf --- /dev/null +++ b/tests/ui/specialization/specialization-overlap-projection.stderr @@ -0,0 +1,30 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-overlap-projection.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0119]: conflicting implementations of trait `Foo` for type `u32` + --> $DIR/specialization-overlap-projection.rs:20:1 + | +LL | impl Foo for u32 {} + | ---------------- first implementation here +LL | impl Foo for <u8 as Assoc>::Output {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error[E0119]: conflicting implementations of trait `Foo` for type `u32` + --> $DIR/specialization-overlap-projection.rs:22:1 + | +LL | impl Foo for u32 {} + | ---------------- first implementation here +... +LL | impl Foo for <u16 as Assoc>::Output {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/crashes/124164.rs b/tests/ui/static/missing-type.rs index 8c9b4bddbe8..2569f47b7c3 100644 --- a/tests/crashes/124164.rs +++ b/tests/ui/static/missing-type.rs @@ -1,4 +1,5 @@ -//@ known-bug: #124164 +// reported as #124164 static S_COUNT: = std::sync::atomic::AtomicUsize::new(0); +//~^ ERROR: missing type for `static` item fn main() {} diff --git a/tests/ui/static/missing-type.stderr b/tests/ui/static/missing-type.stderr new file mode 100644 index 00000000000..6489ceb700a --- /dev/null +++ b/tests/ui/static/missing-type.stderr @@ -0,0 +1,8 @@ +error: missing type for `static` item + --> $DIR/missing-type.rs:2:16 + | +LL | static S_COUNT: = std::sync::atomic::AtomicUsize::new(0); + | ^ help: provide a type for the static variable: `AtomicUsize` + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/alias/issue-83613.rs b/tests/ui/traits/alias/issue-83613.rs index 2462e703a71..6f0012bf089 100644 --- a/tests/ui/traits/alias/issue-83613.rs +++ b/tests/ui/traits/alias/issue-83613.rs @@ -8,5 +8,5 @@ fn mk_opaque() -> OpaqueType { trait AnotherTrait {} impl<T: Send> AnotherTrait for T {} impl AnotherTrait for OpaqueType {} -//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `OpaqueType` +//~^ ERROR conflicting implementations of trait `AnotherTrait` fn main() {} diff --git a/tests/ui/traits/alias/issue-83613.stderr b/tests/ui/traits/alias/issue-83613.stderr index 847fda41776..47181c3f33e 100644 --- a/tests/ui/traits/alias/issue-83613.stderr +++ b/tests/ui/traits/alias/issue-83613.stderr @@ -1,10 +1,10 @@ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType` +error[E0119]: conflicting implementations of trait `AnotherTrait` --> $DIR/issue-83613.rs:10:1 | LL | impl<T: Send> AnotherTrait for T {} | -------------------------------- first implementation here LL | impl AnotherTrait for OpaqueType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error: aborting due to 1 previous error diff --git a/tests/ui/traits/issue-105231.rs b/tests/ui/traits/issue-105231.rs index 7338642beef..83c3158c106 100644 --- a/tests/ui/traits/issue-105231.rs +++ b/tests/ui/traits/issue-105231.rs @@ -1,4 +1,3 @@ -//~ ERROR overflow evaluating the requirement `A<A<A<A<A<A<A<...>>>>>>>: Send` struct A<T>(B<T>); //~^ ERROR recursive types `A` and `B` have infinite size //~| ERROR `T` is only used recursively @@ -7,5 +6,5 @@ struct B<T>(A<A<T>>); trait Foo {} impl<T> Foo for T where T: Send {} impl Foo for B<u8> {} - +//~^ ERROR conflicting implementations of trait `Foo` for type `B<u8>` fn main() {} diff --git a/tests/ui/traits/issue-105231.stderr b/tests/ui/traits/issue-105231.stderr index d3014a79ad6..e113f8382b2 100644 --- a/tests/ui/traits/issue-105231.stderr +++ b/tests/ui/traits/issue-105231.stderr @@ -1,5 +1,5 @@ error[E0072]: recursive types `A` and `B` have infinite size - --> $DIR/issue-105231.rs:2:1 + --> $DIR/issue-105231.rs:1:1 | LL | struct A<T>(B<T>); | ^^^^^^^^^^^ ---- recursive without indirection @@ -16,7 +16,7 @@ LL ~ struct B<T>(Box<A<A<T>>>); | error: type parameter `T` is only used recursively - --> $DIR/issue-105231.rs:2:15 + --> $DIR/issue-105231.rs:1:15 | LL | struct A<T>(B<T>); | - ^ @@ -27,7 +27,7 @@ LL | struct A<T>(B<T>); = note: all type parameters must be used in a non-recursive way in order to constrain their variance error: type parameter `T` is only used recursively - --> $DIR/issue-105231.rs:5:17 + --> $DIR/issue-105231.rs:4:17 | LL | struct B<T>(A<A<T>>); | - ^ @@ -37,16 +37,18 @@ LL | struct B<T>(A<A<T>>); = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = note: all type parameters must be used in a non-recursive way in order to constrain their variance -error[E0275]: overflow evaluating the requirement `A<A<A<A<A<A<A<...>>>>>>>: Send` +error[E0119]: conflicting implementations of trait `Foo` for type `B<u8>` + --> $DIR/issue-105231.rs:8:1 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_105231`) -note: required because it appears within the type `B<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<A<u8>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-105231.rs:5:8 +LL | impl<T> Foo for T where T: Send {} + | ------------------------------- first implementation here +LL | impl Foo for B<u8> {} + | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `B<u8>` | -LL | struct B<T>(A<A<T>>); - | ^ + = note: overflow evaluating the requirement `B<u8>: Send` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_105231`) error: aborting due to 4 previous errors -Some errors have detailed explanations: E0072, E0275. +Some errors have detailed explanations: E0072, E0119. For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs index d37943b929a..43443be88df 100644 --- a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs +++ b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs @@ -1,4 +1,3 @@ -//~ ERROR overflow // A regression test for #111729 checking that we correctly // track recursion depth for obligations returned by confirmation. use std::panic::RefUnwindSafe; @@ -18,6 +17,7 @@ impl<T: RefUnwindSafe> Database for T { type Storage = SalsaStorage; } impl Database for RootDatabase { + //~^ ERROR conflicting implementations of trait `Database` for type `RootDatabase` type Storage = SalsaStorage; } diff --git a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr index 2ab150fc0f6..1da7671b451 100644 --- a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr +++ b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr @@ -1,24 +1,12 @@ -error[E0275]: overflow evaluating the requirement `Runtime<RootDatabase>: RefUnwindSafe` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_via_builtin_auto_trait_impl`) -note: required because it appears within the type `RootDatabase` - --> $DIR/cycle-via-builtin-auto-trait-impl.rs:13:8 - | -LL | struct RootDatabase { - | ^^^^^^^^^^^^ -note: required for `RootDatabase` to implement `Database` - --> $DIR/cycle-via-builtin-auto-trait-impl.rs:17:24 +error[E0119]: conflicting implementations of trait `Database` for type `RootDatabase` + --> $DIR/cycle-via-builtin-auto-trait-impl.rs:19:1 | LL | impl<T: RefUnwindSafe> Database for T { - | ------------- ^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required because it appears within the type `Runtime<RootDatabase>` - --> $DIR/cycle-via-builtin-auto-trait-impl.rs:24:8 - | -LL | struct Runtime<DB: Database> { - | ^^^^^^^ + | ------------------------------------- first implementation here +... +LL | impl Database for RootDatabase { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `RootDatabase` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/crashes/124207.rs b/tests/ui/transmutability/malformed-program-gracefulness/coherence-bikeshed-intrinsic-from.rs index a11eedb140a..0cebc99cd41 100644 --- a/tests/crashes/124207.rs +++ b/tests/ui/transmutability/malformed-program-gracefulness/coherence-bikeshed-intrinsic-from.rs @@ -1,9 +1,11 @@ -//@ known-bug: #124207 #![feature(transmutability)] #![feature(type_alias_impl_trait)] trait OpaqueTrait {} type OpaqueType = impl OpaqueTrait; +//~^ ERROR unconstrained opaque type trait AnotherTrait {} impl<T: std::mem::TransmuteFrom<(), ()>> AnotherTrait for T {} +//~^ ERROR type provided when a constant was expected impl AnotherTrait for OpaqueType {} +//~^ ERROR conflicting implementations of trait `AnotherTrait` pub fn main() {} diff --git a/tests/ui/transmutability/malformed-program-gracefulness/coherence-bikeshed-intrinsic-from.stderr b/tests/ui/transmutability/malformed-program-gracefulness/coherence-bikeshed-intrinsic-from.stderr new file mode 100644 index 00000000000..2424541af23 --- /dev/null +++ b/tests/ui/transmutability/malformed-program-gracefulness/coherence-bikeshed-intrinsic-from.stderr @@ -0,0 +1,27 @@ +error: unconstrained opaque type + --> $DIR/coherence-bikeshed-intrinsic-from.rs:4:19 + | +LL | type OpaqueType = impl OpaqueTrait; + | ^^^^^^^^^^^^^^^^ + | + = note: `OpaqueType` must be used in combination with a concrete type within the same module + +error[E0747]: type provided when a constant was expected + --> $DIR/coherence-bikeshed-intrinsic-from.rs:7:37 + | +LL | impl<T: std::mem::TransmuteFrom<(), ()>> AnotherTrait for T {} + | ^^ + +error[E0119]: conflicting implementations of trait `AnotherTrait` + --> $DIR/coherence-bikeshed-intrinsic-from.rs:9:1 + | +LL | impl<T: std::mem::TransmuteFrom<(), ()>> AnotherTrait for T {} + | ----------------------------------------------------------- first implementation here +LL | +LL | impl AnotherTrait for OpaqueType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0119, E0747. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr b/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr index e35913be899..aaf75cc3db9 100644 --- a/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr +++ b/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr @@ -15,8 +15,6 @@ LL | impl Bop for Bar<()> {} ... LL | impl Bop for Barr {} | ^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>` - | - = note: upstream crates may add a new impl of trait `std::marker::FnPtr` for type `Barr` in future versions error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>` --> $DIR/impl_trait_for_same_tait.rs:30:1 diff --git a/tests/ui/type-alias-impl-trait/issue-104817.rs b/tests/ui/type-alias-impl-trait/issue-104817.rs index 4679d025fce..49146321614 100644 --- a/tests/ui/type-alias-impl-trait/issue-104817.rs +++ b/tests/ui/type-alias-impl-trait/issue-104817.rs @@ -14,6 +14,6 @@ fn mk_opaque() -> OpaqueType { trait AnotherTrait {} impl<T: Send> AnotherTrait for T {} impl AnotherTrait for OpaqueType {} -//[stock]~^ conflicting implementations of trait `AnotherTrait` for type `OpaqueType` +//[stock]~^ conflicting implementations of trait `AnotherTrait` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr b/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr index 41c5206d9e8..df5a6c320a8 100644 --- a/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr +++ b/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr @@ -1,10 +1,10 @@ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType` +error[E0119]: conflicting implementations of trait `AnotherTrait` --> $DIR/issue-104817.rs:16:1 | LL | impl<T: Send> AnotherTrait for T {} | -------------------------------- first implementation here LL | impl AnotherTrait for OpaqueType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error: aborting due to 1 previous error diff --git a/tests/crashes/126896.rs b/tests/ui/type-alias-impl-trait/taint.rs index 49c539d7acc..dfb947637c0 100644 --- a/tests/crashes/126896.rs +++ b/tests/ui/type-alias-impl-trait/taint.rs @@ -1,6 +1,7 @@ -//@ known-bug: rust-lang/rust#126896 //@ compile-flags: -Zvalidate-mir -Zinline-mir=yes +// reported as rust-lang/rust#126896 + #![feature(type_alias_impl_trait)] type Two<'a, 'b> = impl std::fmt::Debug; @@ -9,9 +10,8 @@ fn set(x: &mut isize) -> isize { } fn d(x: Two) { - let c1 = || set(x); + let c1 = || set(x); //~ ERROR: expected generic lifetime parameter, found `'_` c1; } -fn main() { -} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/taint.stderr b/tests/ui/type-alias-impl-trait/taint.stderr new file mode 100644 index 00000000000..17fcd4b7e93 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/taint.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/taint.rs:13:17 + | +LL | type Two<'a, 'b> = impl std::fmt::Debug; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let c1 = || set(x); + | ^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/triagebot.toml b/triagebot.toml index 1afcad7d131..f379f8cc7af 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -914,6 +914,7 @@ cc = ["@kobzol"] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ + "fmease", "jhpratt", "joboet", "jyn514", |
