From 511bf6e1c7a3c2bf00d9c6d62f397b90aab55581 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 13 Jan 2024 19:14:02 +0000 Subject: [PATCH 001/101] Add note to resolve error about generics from inside static/const --- compiler/rustc_resolve/messages.ftl | 4 ++ compiler/rustc_resolve/src/diagnostics.rs | 8 +++- compiler/rustc_resolve/src/errors.rs | 10 ++++ compiler/rustc_resolve/src/ident.rs | 30 ++++++++---- compiler/rustc_resolve/src/late.rs | 46 +++++++++++-------- compiler/rustc_resolve/src/lib.rs | 6 ++- tests/ui/inner-static-type-parameter.stderr | 2 + ...om-outer-item-in-const-item.default.stderr | 6 +++ ...m-in-const-item.generic_const_items.stderr | 6 +++ ...65025-extern-static-parent-generics.stderr | 2 + ...e-65035-static-with-parent-generics.stderr | 10 ++++ 11 files changed, 98 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 3f8df16e03f77..1947107235b2c 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -119,12 +119,16 @@ resolve_generic_params_from_outer_item = .refer_to_type_directly = refer to the type directly here instead .suggestion = try introducing a local generic parameter here +resolve_generic_params_from_outer_item_const = a `const` is a separate item from the item that contains it + resolve_generic_params_from_outer_item_const_param = const parameter from outer item resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl` resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here +resolve_generic_params_from_outer_item_static = a `static` is a separate item from the item that contains it + resolve_generic_params_from_outer_item_ty_param = type parameter from outer item diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0d744238eeb42..46da5b9d2e46d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -561,13 +561,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolution_error: ResolutionError<'a>, ) -> DiagnosticBuilder<'_> { match resolution_error { - ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => { + ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => { use errs::GenericParamsFromOuterItemLabel as Label; + let static_or_const = match def_kind { + DefKind::Static(_) => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static), + DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const), + _ => None, + }; let mut err = errs::GenericParamsFromOuterItem { span, label: None, refer_to_type_directly: None, sugg: None, + static_or_const, }; let sm = self.tcx.sess.source_map(); diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 1fdb193e571f1..bd00cab66b0aa 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -44,6 +44,16 @@ pub(crate) struct GenericParamsFromOuterItem { pub(crate) refer_to_type_directly: Option, #[subdiagnostic] pub(crate) sugg: Option, + #[subdiagnostic] + pub(crate) static_or_const: Option, +} + +#[derive(Subdiagnostic)] +pub(crate) enum GenericParamsFromOuterItemStaticOrConst { + #[note(resolve_generic_params_from_outer_item_static)] + Static, + #[note(resolve_generic_params_from_outer_item_const)] + Const, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 3a31addb10933..2770f3fa5a41c 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -10,9 +10,7 @@ use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use crate::late::{ - ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind, -}; +use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind}; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::BindingKey; use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; @@ -1090,7 +1088,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { | RibKind::ForwardGenericParamBan => { // Nothing to do. Continue. } - RibKind::Item(_) | RibKind::AssocItem => { + RibKind::Item(..) | RibKind::AssocItem => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -1155,7 +1153,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => { for rib in ribs { - let has_generic_params: HasGenericParams = match rib.kind { + let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal | RibKind::FnOrCoroutine | RibKind::Module(..) @@ -1213,7 +1211,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // This was an attempt to use a type parameter outside its scope. - RibKind::Item(has_generic_params) => has_generic_params, + RibKind::Item(has_generic_params, def_kind) => { + (has_generic_params, def_kind) + } RibKind::ConstParamTy => { if let Some(span) = finalize { self.report_error( @@ -1231,7 +1231,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(span) = finalize { self.report_error( span, - ResolutionError::GenericParamsFromOuterItem(res, has_generic_params), + ResolutionError::GenericParamsFromOuterItem( + res, + has_generic_params, + def_kind, + ), ); } return Res::Err; @@ -1239,7 +1243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Res::Def(DefKind::ConstParam, _) => { for rib in ribs { - let has_generic_params = match rib.kind { + let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal | RibKind::FnOrCoroutine | RibKind::Module(..) @@ -1276,7 +1280,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { continue; } - RibKind::Item(has_generic_params) => has_generic_params, + RibKind::Item(has_generic_params, def_kind) => { + (has_generic_params, def_kind) + } RibKind::ConstParamTy => { if let Some(span) = finalize { self.report_error( @@ -1295,7 +1301,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(span) = finalize { self.report_error( span, - ResolutionError::GenericParamsFromOuterItem(res, has_generic_params), + ResolutionError::GenericParamsFromOuterItem( + res, + has_generic_params, + def_kind, + ), ); } return Res::Err; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b9e603a499266..e54f8bafefc77 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -181,7 +181,7 @@ pub(crate) enum RibKind<'a> { FnOrCoroutine, /// We passed through an item scope. Disallow upvars. - Item(HasGenericParams), + Item(HasGenericParams, DefKind), /// We're in a constant item. Can't refer to dynamic stuff. /// @@ -221,7 +221,7 @@ impl RibKind<'_> { | RibKind::MacroDefinition(_) | RibKind::ConstParamTy | RibKind::InlineAsmSym => false, - RibKind::AssocItem | RibKind::Item(_) | RibKind::ForwardGenericParamBan => true, + RibKind::AssocItem | RibKind::Item(..) | RibKind::ForwardGenericParamBan => true, } } @@ -866,11 +866,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); + let def_kind = self.r.local_def_kind(foreign_item.id); match foreign_item.kind { ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Item, @@ -882,7 +883,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, ForeignItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Function, @@ -892,7 +893,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, ); } ForeignItemKind::Static(..) => { - self.with_static_rib(|this| { + self.with_static_rib(def_kind, |this| { visit::walk_foreign_item(this, foreign_item); }); } @@ -2268,10 +2269,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { debug!("resolve_adt"); + let kind = self.r.local_def_kind(item.id); self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2345,11 +2347,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let name = item.ident.name; debug!("(resolving item) resolving {} ({:?})", name, item.kind); + let def_kind = self.r.local_def_kind(item.id); match item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2362,7 +2365,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Function, @@ -2401,7 +2404,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2422,7 +2425,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2456,7 +2459,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { - self.with_static_rib(|this| { + self.with_static_rib(def_kind, |this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); }); @@ -2471,11 +2474,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { self.with_generic_param_rib( &generics.params, - RibKind::Item(if self.r.tcx.features().generic_const_items { - HasGenericParams::Yes(generics.span) - } else { - HasGenericParams::No - }), + RibKind::Item( + if self.r.tcx.features().generic_const_items { + HasGenericParams::Yes(generics.span) + } else { + HasGenericParams::No + }, + def_kind, + ), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::ConstItem, @@ -2560,7 +2566,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let mut add_bindings_for_ns = |ns| { let parent_rib = self.ribs[ns] .iter() - .rfind(|r| matches!(r.kind, RibKind::Item(_))) + .rfind(|r| matches!(r.kind, RibKind::Item(..))) .expect("associated item outside of an item"); seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); }; @@ -2695,8 +2701,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.label_ribs.pop(); } - fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) { - let kind = RibKind::Item(HasGenericParams::No); + fn with_static_rib(&mut self, def_kind: DefKind, f: impl FnOnce(&mut Self)) { + let kind = RibKind::Item(HasGenericParams::No, def_kind); self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) } @@ -2877,7 +2883,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span)), + RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)), LifetimeRibKind::Generics { span: generics.span, binder: item_id, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0adea65ee58ea..1ab350d3bd850 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -185,7 +185,7 @@ struct BindingError { #[derive(Debug)] enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer item. - GenericParamsFromOuterItem(Res, HasGenericParams), + GenericParamsFromOuterItem(Res, HasGenericParams, DefKind), /// Error E0403: the name is already used for a type or const parameter in this generic /// parameter list. NameAlreadyUsedInParameterList(Symbol, Span), @@ -1207,6 +1207,10 @@ impl<'tcx> Resolver<'_, 'tcx> { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } + fn local_def_kind(&self, node: NodeId) -> DefKind { + self.tcx.def_kind(self.local_def_id(node)) + } + /// Adds a definition with a parent definition. fn create_def( &mut self, diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/inner-static-type-parameter.stderr index ff6558e494b11..b4c435e98cebe 100644 --- a/tests/ui/inner-static-type-parameter.stderr +++ b/tests/ui/inner-static-type-parameter.stderr @@ -5,6 +5,8 @@ LL | fn foo() { | - type parameter from outer item LL | static a: Bar = Bar::What; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0392]: parameter `T` is never used --> $DIR/inner-static-type-parameter.rs:3:10 diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr index 4f8538292792c..fbb9ede8aa175 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr @@ -5,6 +5,8 @@ LL | fn outer() { // outer function | - type parameter from outer item LL | const K: u32 = T::C; | ^^^^ use of generic parameter from outer item + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 @@ -14,6 +16,8 @@ LL | impl Tr for T { // outer impl block LL | const C: u32 = { LL | const I: u32 = T::C; | ^^^^ use of generic parameter from outer item + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 @@ -22,6 +26,8 @@ LL | struct S(U32<{ // outer struct | - type parameter from outer item LL | const _: u32 = T::C; | ^^^^ use of generic parameter from outer item + | + = note: a `const` is a separate item from the item that contains it error: aborting due to 3 previous errors diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr index 1cb55842bc665..60aa94038c3ad 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr @@ -7,6 +7,8 @@ LL | const K: u32 = T::C; | - ^^^^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 @@ -18,6 +20,8 @@ LL | const I: u32 = T::C; | - ^^^^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` + | + = note: a `const` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 @@ -28,6 +32,8 @@ LL | const _: u32 = T::C; | - ^^^^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` + | + = note: a `const` is a separate item from the item that contains it error: aborting due to 3 previous errors diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr index 363bb55647827..ca32147d19765 100644 --- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr +++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr @@ -6,6 +6,8 @@ LL | unsafe fn foo() { LL | extern "C" { LL | static baz: *const A; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr index f1fe1a6002c93..98ffb4567f164 100644 --- a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr +++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr @@ -6,6 +6,8 @@ LL | fn f() { LL | extern "C" { LL | static a: *const T; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:9:22 @@ -14,6 +16,8 @@ LL | fn g() { | - type parameter from outer item LL | static a: *const T = Default::default(); | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:15:24 @@ -23,6 +27,8 @@ LL | fn h() { LL | extern "C" { LL | static a: [u8; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:21:20 @@ -31,6 +37,8 @@ LL | fn i() { | - const parameter from outer item LL | static a: [u8; N] = [0; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error[E0401]: can't use generic parameters from outer item --> $DIR/issue-65035-static-with-parent-generics.rs:21:29 @@ -39,6 +47,8 @@ LL | fn i() { | - const parameter from outer item LL | static a: [u8; N] = [0; N]; | ^ use of generic parameter from outer item + | + = note: a `static` is a separate item from the item that contains it error: aborting due to 5 previous errors From 2cfc81766c37eb0f6696d50f9207876293fa7732 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 13 Jan 2024 19:24:52 +0000 Subject: [PATCH 002/101] Special case 'generic param from outer item' message for `Self` --- compiler/rustc_resolve/messages.ftl | 10 ++++++++-- compiler/rustc_resolve/src/diagnostics.rs | 2 ++ compiler/rustc_resolve/src/errors.rs | 1 + tests/ui/error-codes/E0401.stderr | 4 ++-- tests/ui/resolve/issue-12796.rs | 2 +- tests/ui/resolve/issue-12796.stderr | 4 ++-- tests/ui/resolve/use-self-in-inner-fn.rs | 4 ++-- tests/ui/resolve/use-self-in-inner-fn.stderr | 4 ++-- 8 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 1947107235b2c..69675b57e31a1 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -114,8 +114,14 @@ resolve_forward_declared_generic_param = .label = defaulted generic parameters cannot be forward declared resolve_generic_params_from_outer_item = - can't use generic parameters from outer item - .label = use of generic parameter from outer item + can't use {$is_self -> + [true] `Self` + *[false] generic parameters + } from outer item + .label = use of {$is_self -> + [true] `Self` + *[false] generic parameter + } from outer item .refer_to_type_directly = refer to the type directly here instead .suggestion = try introducing a local generic parameter here diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 46da5b9d2e46d..da31382112a0b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -568,12 +568,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const), _ => None, }; + let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }); let mut err = errs::GenericParamsFromOuterItem { span, label: None, refer_to_type_directly: None, sugg: None, static_or_const, + is_self, }; let sm = self.tcx.sess.source_map(); diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index bd00cab66b0aa..da89df84c8ae5 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -46,6 +46,7 @@ pub(crate) struct GenericParamsFromOuterItem { pub(crate) sugg: Option, #[subdiagnostic] pub(crate) static_or_const: Option, + pub(crate) is_self: bool, } #[derive(Subdiagnostic)] diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr index d27fade487fe2..754867061c7f8 100644 --- a/tests/ui/error-codes/E0401.stderr +++ b/tests/ui/error-codes/E0401.stderr @@ -20,7 +20,7 @@ LL | fn baz $DIR/E0401.rs:24:25 | LL | impl Iterator for A { @@ -29,7 +29,7 @@ LL | impl Iterator for A { LL | fn helper(sel: &Self) -> u8 { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | refer to the type directly here instead error[E0283]: type annotations needed diff --git a/tests/ui/resolve/issue-12796.rs b/tests/ui/resolve/issue-12796.rs index de3e73437f080..e5dcf9643453b 100644 --- a/tests/ui/resolve/issue-12796.rs +++ b/tests/ui/resolve/issue-12796.rs @@ -1,7 +1,7 @@ trait Trait { fn outer(&self) { fn inner(_: &Self) { - //~^ ERROR can't use generic parameters from outer item + //~^ ERROR can't use `Self` from outer item } } } diff --git a/tests/ui/resolve/issue-12796.stderr b/tests/ui/resolve/issue-12796.stderr index 6809fd50f7475..2305971303a71 100644 --- a/tests/ui/resolve/issue-12796.stderr +++ b/tests/ui/resolve/issue-12796.stderr @@ -1,10 +1,10 @@ -error[E0401]: can't use generic parameters from outer item +error[E0401]: can't use `Self` from outer item --> $DIR/issue-12796.rs:3:22 | LL | fn inner(_: &Self) { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | can't use `Self` here error: aborting due to 1 previous error diff --git a/tests/ui/resolve/use-self-in-inner-fn.rs b/tests/ui/resolve/use-self-in-inner-fn.rs index f4dfa4c40ab24..62f9dc5664ffe 100644 --- a/tests/ui/resolve/use-self-in-inner-fn.rs +++ b/tests/ui/resolve/use-self-in-inner-fn.rs @@ -4,8 +4,8 @@ impl A { //~^ NOTE `Self` type implicitly declared here, by this `impl` fn banana(&mut self) { fn peach(this: &Self) { - //~^ ERROR can't use generic parameters from outer item - //~| NOTE use of generic parameter from outer item + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item //~| NOTE refer to the type directly here instead } } diff --git a/tests/ui/resolve/use-self-in-inner-fn.stderr b/tests/ui/resolve/use-self-in-inner-fn.stderr index 165e100bf2f5c..9c388df8bc20c 100644 --- a/tests/ui/resolve/use-self-in-inner-fn.stderr +++ b/tests/ui/resolve/use-self-in-inner-fn.stderr @@ -1,4 +1,4 @@ -error[E0401]: can't use generic parameters from outer item +error[E0401]: can't use `Self` from outer item --> $DIR/use-self-in-inner-fn.rs:6:25 | LL | impl A { @@ -7,7 +7,7 @@ LL | impl A { LL | fn peach(this: &Self) { | ^^^^ | | - | use of generic parameter from outer item + | use of `Self` from outer item | refer to the type directly here instead error: aborting due to 1 previous error From 06a41687b160cbb4cbf8fce0b3ad3a2e352e8338 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 14 Dec 2023 22:07:53 +0800 Subject: [PATCH 003/101] Add unstable `-Z direct-access-external-data` cmdline flag for `rustc` The new flag has been described in the Major Change Proposal at https://github.com/rust-lang/compiler-team/issues/707 --- compiler/rustc_codegen_llvm/src/mono_item.rs | 25 +++++++++++-------- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ compiler/rustc_session/src/session.rs | 7 ++++++ compiler/rustc_target/src/spec/mod.rs | 11 ++++++++ .../targets/loongarch64_unknown_linux_gnu.rs | 1 + .../direct-access-external-data.md | 16 ++++++++++++ tests/codegen/direct-access-external-data.rs | 21 ++++++++++++++++ 8 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md create mode 100644 tests/codegen/direct-access-external-data.rs diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index f796ce0990f12..f763071936837 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -123,6 +123,17 @@ impl CodegenCx<'_, '_> { return false; } + // Match clang by only supporting COFF and ELF for now. + if self.tcx.sess.target.is_like_osx { + return false; + } + + // With pie relocation model calls of functions defined in the translation + // unit can use copy relocations. + if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration { + return true; + } + // Thread-local variables generally don't support copy relocations. let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); @@ -130,18 +141,12 @@ impl CodegenCx<'_, '_> { return false; } - // Match clang by only supporting COFF and ELF for now. - if self.tcx.sess.target.is_like_osx { - return false; + // Respect the direct-access-external-data to override default behavior if present. + if let Some(direct) = self.tcx.sess.direct_access_external_data() { + return direct; } // Static relocation model should force copy relocations everywhere. - if self.tcx.sess.relocation_model() == RelocModel::Static { - return true; - } - - // With pie relocation model calls of functions defined in the translation - // unit can use copy relocations. - self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration + self.tcx.sess.relocation_model() == RelocModel::Static } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 588139a303c52..948db6a6ea101 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -748,6 +748,7 @@ fn test_unstable_options_tracking_hash() { tracked!(debug_macros, true); tracked!(default_hidden_visibility, Some(true)); tracked!(dep_info_omit_d_target, true); + tracked!(direct_access_external_data, Some(true)); tracked!(dual_proc_macros, true); tracked!(dwarf_version, Some(5)); tracked!(emit_thin_lto, false); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c97b18ebd66ad..ff8c5f4b3568e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1553,6 +1553,8 @@ options! { dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), + direct_access_external_data: Option = (None, parse_opt_bool, [TRACKED], + "Direct or use GOT indirect to reference external data symbols"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 720599f609544..392485e2238c5 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -793,6 +793,13 @@ impl Session { self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model) } + pub fn direct_access_external_data(&self) -> Option { + self.opts + .unstable_opts + .direct_access_external_data + .or(self.target.direct_access_external_data) + } + pub fn split_debuginfo(&self) -> SplitDebuginfo { self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo) } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8e26327196a1a..7979be7b5d6e8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1885,6 +1885,8 @@ pub struct TargetOptions { /// passed, and cannot be disabled even via `-C`. Corresponds to `llc /// -mattr=$features`. pub features: StaticCow, + /// Direct or use GOT indirect to reference external data symbols + pub direct_access_external_data: Option, /// Whether dynamic linking is available on this target. Defaults to false. pub dynamic_linking: bool, /// Whether dynamic linking can export TLS globals. Defaults to true. @@ -2279,6 +2281,7 @@ impl Default for TargetOptions { asm_args: cvs![], cpu: "generic".into(), features: "".into(), + direct_access_external_data: None, dynamic_linking: false, dll_tls_export: true, only_cdylib: false, @@ -2575,6 +2578,12 @@ impl Target { base.$key_name = s as u32; } } ); + ($key_name:ident, Option) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) { + base.$key_name = Some(s); + } + } ); ($key_name:ident, Option) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) { @@ -3003,6 +3012,7 @@ impl Target { key!(cpu); key!(features); key!(dynamic_linking, bool); + key!(direct_access_external_data, Option); key!(dll_tls_export, bool); key!(only_cdylib, bool); key!(executables, bool); @@ -3257,6 +3267,7 @@ impl ToJson for Target { target_option_val!(cpu); target_option_val!(features); target_option_val!(dynamic_linking); + target_option_val!(direct_access_external_data); target_option_val!(dll_tls_export); target_option_val!(only_cdylib); target_option_val!(executables); diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index 0f05e7c475a83..234270c999b2a 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { features: "+f,+d".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), + direct_access_external_data: Some(false), ..base::linux_gnu::opts() }, } diff --git a/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md b/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md new file mode 100644 index 0000000000000..c72df43796038 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md @@ -0,0 +1,16 @@ +# `direct_access_external_data` + +The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/707 + +------------------------ + +Option `-Z direct-access-external-data` controls how to access symbols of +external data. + +Supported values for this option are: + +- `yes` - Don't use GOT indirection to reference external data symbols. +- `no` - Use GOT indirection to reference external data symbols. + +If the option is not explicitly specified, different targets have different +default values. diff --git a/tests/codegen/direct-access-external-data.rs b/tests/codegen/direct-access-external-data.rs new file mode 100644 index 0000000000000..ec4bfc33518db --- /dev/null +++ b/tests/codegen/direct-access-external-data.rs @@ -0,0 +1,21 @@ +// only-loongarch64-unknown-linux-gnu + +// revisions: DEFAULT DIRECT INDIRECT +// [DEFAULT] compile-flags: -C relocation-model=static +// [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes +// [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no + +#![crate_type = "rlib"] + +// DEFAULT: @VAR = external {{.*}} global i32 +// DIRECT: @VAR = external dso_local {{.*}} global i32 +// INDIRECT: @VAR = external {{.*}} global i32 + +extern "C" { + static VAR: i32; +} + +#[no_mangle] +pub fn get() -> i32 { + unsafe { VAR } +} From c36798357d353a8df1bf430ea3261741cfc51121 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 28 Jan 2024 11:13:02 +0800 Subject: [PATCH 004/101] Suggest name value cfg when only value is used for check-cfg --- .../rustc_lint/src/context/diagnostics.rs | 50 +++++++++++++++---- .../cfg-value-for-cfg-name-multiple.rs | 12 +++++ .../cfg-value-for-cfg-name-multiple.stderr | 21 ++++++++ tests/ui/check-cfg/cfg-value-for-cfg-name.rs | 18 +++++++ .../check-cfg/cfg-value-for-cfg-name.stderr | 22 ++++++++ 5 files changed, 113 insertions(+), 10 deletions(-) create mode 100644 tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs create mode 100644 tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr create mode 100644 tests/ui/check-cfg/cfg-value-for-cfg-name.rs create mode 100644 tests/ui/check-cfg/cfg-value-for-cfg-name.stderr diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 312874db3f54e..31205f2b2fd97 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -187,6 +187,23 @@ pub(super) fn builtin( BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => { let possibilities: Vec = sess.parse_sess.check_config.expecteds.keys().copied().collect(); + + let mut names_possibilities: Vec<_> = if value.is_none() { + // We later sort and display all the possibilities, so the order here does not matter. + #[allow(rustc::potential_query_instability)] + sess.parse_sess + .check_config + .expecteds + .iter() + .filter_map(|(k, v)| match v { + ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k), + _ => None, + }) + .collect() + } else { + Vec::new() + }; + let is_from_cargo = std::env::var_os("CARGO").is_some(); let mut is_feature_cfg = name == sym::feature; @@ -261,17 +278,30 @@ pub(super) fn builtin( } is_feature_cfg |= best_match == sym::feature; - } else if !possibilities.is_empty() { - let mut possibilities = - possibilities.iter().map(Symbol::as_str).collect::>(); - possibilities.sort(); - let possibilities = possibilities.join("`, `"); + } else { + if !names_possibilities.is_empty() { + names_possibilities.sort(); + for cfg_name in names_possibilities.iter() { + db.span_suggestion( + name_span, + "found config with similar value", + format!("{cfg_name} = \"{name}\""), + Applicability::MaybeIncorrect, + ); + } + } + if !possibilities.is_empty() { + let mut possibilities = + possibilities.iter().map(Symbol::as_str).collect::>(); + possibilities.sort(); + let possibilities = possibilities.join("`, `"); - // The list of expected names can be long (even by default) and - // so the diagnostic produced can take a lot of space. To avoid - // cloging the user output we only want to print that diagnostic - // once. - db.help_once(format!("expected names are: `{possibilities}`")); + // The list of expected names can be long (even by default) and + // so the diagnostic produced can take a lot of space. To avoid + // cloging the user output we only want to print that diagnostic + // once. + db.help_once(format!("expected names are: `{possibilities}`")); + } } let inst = if let Some((value, _value_span)) = value { diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs new file mode 100644 index 0000000000000..edde6244ed1a9 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs @@ -0,0 +1,12 @@ +// #120427 +// This test checks that when a single cfg has a value for user's specified name +// +// check-pass +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg(foo,values("my_value")) --check-cfg=cfg(bar,values("my_value")) + +#[cfg(my_value)] +//~^ WARNING unexpected `cfg` condition name: `my_value` +fn x() {} + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr new file mode 100644 index 0000000000000..b88ee71a156a2 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr @@ -0,0 +1,21 @@ +warning: unexpected `cfg` condition name: `my_value` + --> $DIR/cfg-value-for-cfg-name-multiple.rs:8:7 + | +LL | #[cfg(my_value)] + | ^^^^^^^^ + | + = help: expected names are: `bar`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: to expect this configuration use `--check-cfg=cfg(my_value)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: found config with similar value + | +LL | #[cfg(foo = "my_value")] + | ~~~~~~~~~~~~~~~~ +help: found config with similar value + | +LL | #[cfg(bar = "my_value")] + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs new file mode 100644 index 0000000000000..7a0c345b7ca76 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs @@ -0,0 +1,18 @@ +// #120427 +// This test checks that when a single cfg has a value for user's specified name +// suggest to use `#[cfg(target_os = "linux")]` instead of `#[cfg(linux)]` +// +// check-pass +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg() + +#[cfg(linux)] +//~^ WARNING unexpected `cfg` condition name: `linux` +fn x() {} + +// will not suggest if the cfg has a value +#[cfg(linux = "os-name")] +//~^ WARNING unexpected `cfg` condition name: `linux` +fn y() {} + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr new file mode 100644 index 0000000000000..c044755142419 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr @@ -0,0 +1,22 @@ +warning: unexpected `cfg` condition name: `linux` + --> $DIR/cfg-value-for-cfg-name.rs:9:7 + | +LL | #[cfg(linux)] + | ^^^^^ help: found config with similar value: `target_os = "linux"` + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: to expect this configuration use `--check-cfg=cfg(linux)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `linux` + --> $DIR/cfg-value-for-cfg-name.rs:14:7 + | +LL | #[cfg(linux = "os-name")] + | ^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(linux, values("os-name"))` + = note: see for more information about checking conditional configuration + +warning: 2 warnings emitted + From f38489e957a1f169be4071947a4426885793f03b Mon Sep 17 00:00:00 2001 From: Jarl Evanson Date: Sun, 28 Jan 2024 13:47:52 -0600 Subject: [PATCH 005/101] Enable `remove_storage_markers` MIR-opt test --- tests/mir-opt/remove_storage_markers.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/remove_storage_markers.rs b/tests/mir-opt/remove_storage_markers.rs index 6666ff3b7263b..74e399b6c0eed 100644 --- a/tests/mir-opt/remove_storage_markers.rs +++ b/tests/mir-opt/remove_storage_markers.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: RemoveStorageMarkers @@ -8,6 +7,10 @@ // EMIT_MIR remove_storage_markers.main.RemoveStorageMarkers.diff fn main() { + // CHECK-LABLE: fn main( + + // CHECK-NOT: StorageDead + // CHECK-NOT: StorageLive let mut sum = 0; for i in 0..10 { sum += i; From d1edc9d0dbd4ce9f1d71eba2ae4116efea8a6f2f Mon Sep 17 00:00:00 2001 From: Jarl Evanson Date: Sun, 28 Jan 2024 13:50:20 -0600 Subject: [PATCH 006/101] Enable `simplify` MIR-opt test --- tests/mir-opt/simplify_if.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/simplify_if.rs b/tests/mir-opt/simplify_if.rs index 19b5806f72094..f600c05958198 100644 --- a/tests/mir-opt/simplify_if.rs +++ b/tests/mir-opt/simplify_if.rs @@ -1,10 +1,13 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #[inline(never)] fn noop() {} // EMIT_MIR simplify_if.main.SimplifyConstCondition-after-const-prop.diff fn main() { + // CHECK-LABEL: fn main( + + // CHECK: bb0: { + // CHECK-NEXT: return; if false { noop(); } From 103159809aa83e00111f3b35be7281b8165681bc Mon Sep 17 00:00:00 2001 From: Jarl Evanson Date: Sun, 28 Jan 2024 16:04:07 -0600 Subject: [PATCH 007/101] Enable `lifetimes` SROA MIR-opt test --- tests/mir-opt/sroa/lifetimes.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/sroa/lifetimes.rs b/tests/mir-opt/sroa/lifetimes.rs index cc5c0c9bbcdb5..ea04fac15710e 100644 --- a/tests/mir-opt/sroa/lifetimes.rs +++ b/tests/mir-opt/sroa/lifetimes.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: ScalarReplacementOfAggregates // compile-flags: -Cpanic=abort // no-prefer-dynamic @@ -16,6 +15,10 @@ struct Foo { // EMIT_MIR lifetimes.foo.ScalarReplacementOfAggregates.diff fn foo() { + // CHECK-LABEL: fn foo( + + // CHECK-NOT: [foo:_.*]: Foo + // CHECK-NOT: Box let foo: Foo = Foo { x: Ok(Box::new(5_u32)), y: 7_u32, From 7a2b66319ee219e757b6661549f460d8548dcbed Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 24 Jan 2024 11:04:55 +0000 Subject: [PATCH 008/101] interning doesn't check alignment anymroe, because it doesn't do any more projections. --- compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 6a92ed9717de5..8499de20498ff 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,5 +1,3 @@ -use std::mem; - use either::{Left, Right}; use rustc_hir::def::DefKind; @@ -75,9 +73,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( None => InternKind::Constant, } }; - let check_alignment = mem::replace(&mut ecx.machine.check_alignment, CheckAlignment::No); // interning doesn't need to respect alignment intern_const_alloc_recursive(ecx, intern_kind, &ret)?; - ecx.machine.check_alignment = check_alignment; debug!("eval_body_using_ecx done: {:?}", ret); Ok(ret) From b6d0225cafcf7d2421ad943647ed6ef4b8eb7bb4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 24 Jan 2024 11:05:14 +0000 Subject: [PATCH 009/101] prefer instrumentation over entry/exit tracing statements --- compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 8499de20498ff..a2d0f1c5583f3 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -22,12 +22,13 @@ use crate::interpret::{ }; // Returns a pointer to where the result lives +#[instrument(level = "trace", skip(ecx, body), ret)] fn eval_body_using_ecx<'mir, 'tcx>( ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, cid: GlobalId<'tcx>, body: &'mir mir::Body<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); + trace!(?ecx.param_env); let tcx = *ecx.tcx; assert!( cid.promoted.is_some() @@ -75,7 +76,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( }; intern_const_alloc_recursive(ecx, intern_kind, &ret)?; - debug!("eval_body_using_ecx done: {:?}", ret); Ok(ret) } From a73c44889a6402f13d25fd5b973765ff62fb9885 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 24 Jan 2024 11:32:38 +0000 Subject: [PATCH 010/101] Prefer external iteration now that we don't actually recurse anymore --- .../rustc_const_eval/src/interpret/intern.rs | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 751fbfacaad00..48920ba384ada 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -41,13 +41,12 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine< /// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be* /// already mutable (as a sanity check). /// -/// `recursive_alloc` is called for all recursively encountered allocations. +/// Returns an iterator over all relocations referred to by this allocation. fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>( ecx: &'rt mut InterpCx<'mir, 'tcx, M>, alloc_id: AllocId, mutability: Mutability, - mut recursive_alloc: impl FnMut(&InterpCx<'mir, 'tcx, M>, CtfeProvenance), -) -> Result<(), ()> { +) -> Result + 'tcx, ()> { trace!("intern_shallow {:?}", alloc_id); // remove allocation let Some((_kind, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) else { @@ -65,14 +64,10 @@ fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>( assert_eq!(alloc.mutability, Mutability::Mut); } } - // record child allocations - for &(_, prov) in alloc.provenance().ptrs().iter() { - recursive_alloc(ecx, prov); - } // link the alloc id to the actual allocation let alloc = ecx.tcx.mk_const_alloc(alloc); ecx.tcx.set_alloc_id_memory(alloc_id, alloc); - Ok(()) + Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov)) } /// How a constant value should be interned. @@ -128,7 +123,7 @@ pub fn intern_const_alloc_recursive< } }; - // Initialize recursive interning. + // Intern the base allocation, and initialize todo list for recursive interning. let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id(); let mut todo = vec![(base_alloc_id, base_mutability)]; // We need to distinguish "has just been interned" from "was already in `tcx`", @@ -154,7 +149,10 @@ pub fn intern_const_alloc_recursive< continue; } just_interned.insert(alloc_id); - intern_shallow(ecx, alloc_id, mutability, |ecx, prov| { + let provs = intern_shallow(ecx, alloc_id, mutability).map_err(|()| { + ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) + })?; + for prov in provs { let alloc_id = prov.alloc_id(); if intern_kind != InternKind::Promoted && inner_mutability == Mutability::Not @@ -169,7 +167,7 @@ pub fn intern_const_alloc_recursive< // during interning is to justify why we intern the *new* allocations immutably, // so we can completely ignore existing allocations. We also don't need to add // this to the todo list, since after all it is already interned. - return; + continue; } // Found a mutable pointer inside a const where inner allocations should be // immutable. We exclude promoteds from this, since things like `&mut []` and @@ -189,10 +187,7 @@ pub fn intern_const_alloc_recursive< // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. todo.push((alloc_id, inner_mutability)); - }) - .map_err(|()| { - ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - })?; + } } if found_bad_mutable_pointer { return Err(ecx @@ -220,13 +215,13 @@ pub fn intern_const_alloc_for_constprop< return Ok(()); } // Move allocation to `tcx`. - intern_shallow(ecx, alloc_id, Mutability::Not, |_ecx, _| { + for _ in intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))? { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance") - }) - .map_err(|()| err_ub!(DeadLocal).into()) + } + Ok(()) } impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> @@ -247,15 +242,14 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> let dest = self.allocate(layout, MemoryKind::Stack)?; f(self, &dest.clone().into())?; let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance - intern_shallow(self, alloc_id, Mutability::Not, |ecx, prov| { + for prov in intern_shallow(self, alloc_id, Mutability::Not).unwrap() { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. - if !ecx.tcx.try_get_global_alloc(prov.alloc_id()).is_some() { + if !self.tcx.try_get_global_alloc(prov.alloc_id()).is_some() { panic!("`intern_with_temp_alloc` with nested allocations"); } - }) - .unwrap(); + } Ok(alloc_id) } } From a57a00ebf69722de2944d37de10946cf3aa6fe15 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 24 Jan 2024 11:46:57 +0000 Subject: [PATCH 011/101] separately intern the outermost alloc from the rest --- .../rustc_const_eval/src/interpret/intern.rs | 80 +++++++++---------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 48920ba384ada..7621d038855f5 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -125,10 +125,11 @@ pub fn intern_const_alloc_recursive< // Intern the base allocation, and initialize todo list for recursive interning. let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id(); - let mut todo = vec![(base_alloc_id, base_mutability)]; + let mut todo: Vec<_> = + intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().map(|prov| prov).collect(); // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. - let mut just_interned = FxHashSet::default(); + let mut just_interned: FxHashSet<_> = std::iter::once(base_alloc_id).collect(); // Whether we encountered a bad mutable pointer. // We want to first report "dangling" and then "mutable", so we need to delay reporting these // errors. @@ -142,52 +143,49 @@ pub fn intern_const_alloc_recursive< // raw pointers, so we cannot rely on validation to catch them -- and since interning runs // before validation, and interning doesn't know the type of anything, this means we can't show // better errors. Maybe we should consider doing validation before interning in the future. - while let Some((alloc_id, mutability)) = todo.pop() { + while let Some(prov) = todo.pop() { + let alloc_id = prov.alloc_id(); + if intern_kind != InternKind::Promoted + && inner_mutability == Mutability::Not + && !prov.immutable() + { + if ecx.tcx.try_get_global_alloc(alloc_id).is_some() + && !just_interned.contains(&alloc_id) + { + // This is a pointer to some memory from another constant. We encounter mutable + // pointers to such memory since we do not always track immutability through + // these "global" pointers. Allowing them is harmless; the point of these checks + // during interning is to justify why we intern the *new* allocations immutably, + // so we can completely ignore existing allocations. We also don't need to add + // this to the todo list, since after all it is already interned. + continue; + } + // Found a mutable pointer inside a const where inner allocations should be + // immutable. We exclude promoteds from this, since things like `&mut []` and + // `&None::>` lead to promotion that can produce mutable pointers. We rely + // on the promotion analysis not screwing up to ensure that it is sound to intern + // promoteds as immutable. + found_bad_mutable_pointer = true; + } if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { // Already interned. debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id)); continue; } just_interned.insert(alloc_id); - let provs = intern_shallow(ecx, alloc_id, mutability).map_err(|()| { + // We always intern with `inner_mutability`, and furthermore we ensured above that if + // that is "immutable", then there are *no* mutable pointers anywhere in the newly + // interned memory -- justifying that we can indeed intern immutably. However this also + // means we can *not* easily intern immutably here if `prov.immutable()` is true and + // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and + // we'd have to somehow check that they are *all* immutable before deciding that this + // allocation can be made immutable. In the future we could consider analyzing all + // pointers before deciding which allocations can be made immutable; but for now we are + // okay with losing some potential for immutability here. This can anyway only affect + // `static mut`. + todo.extend(intern_shallow(ecx, alloc_id, inner_mutability).map_err(|()| { ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - })?; - for prov in provs { - let alloc_id = prov.alloc_id(); - if intern_kind != InternKind::Promoted - && inner_mutability == Mutability::Not - && !prov.immutable() - { - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() - && !just_interned.contains(&alloc_id) - { - // This is a pointer to some memory from another constant. We encounter mutable - // pointers to such memory since we do not always track immutability through - // these "global" pointers. Allowing them is harmless; the point of these checks - // during interning is to justify why we intern the *new* allocations immutably, - // so we can completely ignore existing allocations. We also don't need to add - // this to the todo list, since after all it is already interned. - continue; - } - // Found a mutable pointer inside a const where inner allocations should be - // immutable. We exclude promoteds from this, since things like `&mut []` and - // `&None::>` lead to promotion that can produce mutable pointers. We rely - // on the promotion analysis not screwing up to ensure that it is sound to intern - // promoteds as immutable. - found_bad_mutable_pointer = true; - } - // We always intern with `inner_mutability`, and furthermore we ensured above that if - // that is "immutable", then there are *no* mutable pointers anywhere in the newly - // interned memory -- justifying that we can indeed intern immutably. However this also - // means we can *not* easily intern immutably here if `prov.immutable()` is true and - // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and - // we'd have to somehow check that they are *all* immutable before deciding that this - // allocation can be made immutable. In the future we could consider analyzing all - // pointers before deciding which allocations can be made immutable; but for now we are - // okay with losing some potential for immutability here. This can anyway only affect - // `static mut`. - todo.push((alloc_id, inner_mutability)); - } + })?); } if found_bad_mutable_pointer { return Err(ecx From 5d46b982c539ef3a227bd5557ec8a1648dfc5a5c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 25 Jan 2024 10:38:17 +0000 Subject: [PATCH 012/101] Document base vs nested alloc interning --- compiler/rustc_const_eval/src/interpret/intern.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 7621d038855f5..c3a53f90e60a0 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -125,6 +125,9 @@ pub fn intern_const_alloc_recursive< // Intern the base allocation, and initialize todo list for recursive interning. let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id(); + // First we intern the base allocation, as it requires a different mutability. + // This gives us the initial set of nested allocations, which will then all be processed + // recursively in the loop below. let mut todo: Vec<_> = intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().map(|prov| prov).collect(); // We need to distinguish "has just been interned" from "was already in `tcx`", From 0213c87e12460e8f7101f96cc5daf4c3d20d6b9f Mon Sep 17 00:00:00 2001 From: Yukang Date: Tue, 30 Jan 2024 10:18:52 +0800 Subject: [PATCH 013/101] limit the names_possiblilities to less than 3 Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- compiler/rustc_lint/src/context/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 31205f2b2fd97..07efc98f1fbe5 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -279,7 +279,7 @@ pub(super) fn builtin( is_feature_cfg |= best_match == sym::feature; } else { - if !names_possibilities.is_empty() { + if !names_possibilities.is_empty() && names_possibilities.len() <= 3 { names_possibilities.sort(); for cfg_name in names_possibilities.iter() { db.span_suggestion( From ca243e750118ae679c7c3413f21e5e772bf694da Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 30 Jan 2024 16:54:40 +0800 Subject: [PATCH 014/101] add testcase for more than 3 cfg names --- .../check-cfg/cfg-value-for-cfg-name-duplicate.rs | 12 ++++++++++++ .../cfg-value-for-cfg-name-duplicate.stderr | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs create mode 100644 tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs new file mode 100644 index 0000000000000..a6e68e1b7101c --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs @@ -0,0 +1,12 @@ +// #120427 +// This test checks we won't suggest more than 3 span suggestions for cfg names +// +// check-pass +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg(foo,values("value")) --check-cfg=cfg(bar,values("value")) --check-cfg=cfg(bee,values("value")) --check-cfg=cfg(cow,values("value")) + +#[cfg(value)] +//~^ WARNING unexpected `cfg` condition name: `value` +fn x() {} + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr new file mode 100644 index 0000000000000..82d471d715b83 --- /dev/null +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr @@ -0,0 +1,13 @@ +warning: unexpected `cfg` condition name: `value` + --> $DIR/cfg-value-for-cfg-name-duplicate.rs:8:7 + | +LL | #[cfg(value)] + | ^^^^^ + | + = help: expected names are: `bar`, `bee`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: to expect this configuration use `--check-cfg=cfg(value)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + From d34b0fa495bfbc3bd7de14a691822706074fcbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Jan 2024 18:57:58 +0000 Subject: [PATCH 015/101] Add test for method on unbounded type parameter receiver --- .../traits/method-on-unbounded-type-param.rs | 15 ++++ .../method-on-unbounded-type-param.stderr | 83 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 tests/ui/traits/method-on-unbounded-type-param.rs create mode 100644 tests/ui/traits/method-on-unbounded-type-param.stderr diff --git a/tests/ui/traits/method-on-unbounded-type-param.rs b/tests/ui/traits/method-on-unbounded-type-param.rs new file mode 100644 index 0000000000000..8505eb41e98bb --- /dev/null +++ b/tests/ui/traits/method-on-unbounded-type-param.rs @@ -0,0 +1,15 @@ +fn f(a: T, b: T) -> std::cmp::Ordering { + a.cmp(&b) //~ ERROR E0599 +} +fn g(a: T, b: T) -> std::cmp::Ordering { + (&a).cmp(&b) //~ ERROR E0599 +} +fn h(a: &T, b: T) -> std::cmp::Ordering { + a.cmp(&b) //~ ERROR E0599 +} +trait T {} +impl T for X {} +fn main() { + let x: Box = Box::new(0); + x.cmp(&x); //~ ERROR E0599 +} diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr new file mode 100644 index 0000000000000..0b650995de5c5 --- /dev/null +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -0,0 +1,83 @@ +error[E0599]: `T` is not an iterator + --> $DIR/method-on-unbounded-type-param.rs:2:7 + | +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | - method `cmp` not found for this type parameter +LL | a.cmp(&b) + | ^^^ `T` is not an iterator + | + = note: the following trait bounds were not satisfied: + `T: Iterator` + which is required by `&mut T: Iterator` +help: consider restricting the type parameter to satisfy the trait bound + | +LL | fn f(a: T, b: T) -> std::cmp::Ordering where T: Iterator { + | +++++++++++++++++ + +error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied + --> $DIR/method-on-unbounded-type-param.rs:5:10 + | +LL | (&a).cmp(&b) + | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `T: Ord` + which is required by `&T: Ord` + `&T: Iterator` + which is required by `&mut &T: Iterator` + `T: Iterator` + which is required by `&mut T: Iterator` +help: consider restricting the type parameters to satisfy the trait bounds + | +LL | fn g(a: T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord { + | +++++++++++++++++++++++++ + +error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied + --> $DIR/method-on-unbounded-type-param.rs:8:7 + | +LL | a.cmp(&b) + | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `T: Ord` + which is required by `&T: Ord` + `&T: Iterator` + which is required by `&mut &T: Iterator` + `T: Iterator` + which is required by `&mut T: Iterator` +help: consider restricting the type parameters to satisfy the trait bounds + | +LL | fn h(a: &T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord { + | +++++++++++++++++++++++++ + +error[E0599]: the method `cmp` exists for struct `Box`, but its trait bounds were not satisfied + --> $DIR/method-on-unbounded-type-param.rs:14:7 + | +LL | trait T {} + | ------- + | | + | doesn't satisfy `dyn T: Iterator` + | doesn't satisfy `dyn T: Ord` +... +LL | x.cmp(&x); + | ^^^ method cannot be called on `Box` due to unsatisfied trait bounds + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: doesn't satisfy `Box: Iterator` + | + = note: doesn't satisfy `Box: Ord` + | + = note: the following trait bounds were not satisfied: + `dyn T: Iterator` + which is required by `Box: Iterator` + `dyn T: Ord` + which is required by `Box: Ord` + `Box: Iterator` + which is required by `&mut Box: Iterator` + `dyn T: Iterator` + which is required by `&mut dyn T: Iterator` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. From 20b1c2aafca8d8861d193d3476ffc8d09c0479e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Jan 2024 19:02:05 +0000 Subject: [PATCH 016/101] Account for unbounded type param receiver in suggestions When encountering ```rust fn f(a: T, b: T) -> std::cmp::Ordering { a.cmp(&b) //~ ERROR E0599 } ``` output ``` error[E0599]: no method named `cmp` found for type parameter `T` in the current scope --> $DIR/method-on-unbounded-type-param.rs:2:7 | LL | fn f(a: T, b: T) -> std::cmp::Ordering { | - method `cmp` not found for this type parameter LL | a.cmp(&b) | ^^^ method cannot be called on `T` due to unsatisfied trait bounds | = help: items from traits can only be used if the type parameter is bounded by the trait help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | LL | fn f(a: T, b: T) -> std::cmp::Ordering { | +++++ LL | fn f(a: T, b: T) -> std::cmp::Ordering { | ++++++++++ ``` Fix #120186. --- .../rustc_hir_typeck/src/method/suggest.rs | 41 ++++++++++++------- .../method-on-unbounded-type-param.stderr | 16 ++++---- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 6c9501e93fa11..de42f011cf42a 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -554,6 +554,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement" )); } + } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) { + // We special case the situation where we are looking for `_` in + // `::method` because otherwise the machinery will look for blanket + // implementations that have unsatisfied trait bounds to suggest, leading us to claim + // things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord` + // have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so + // that `impl Ord for T` can apply", which is not what we want. We have a type + // parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict + // `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling + // `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates` + // suggestions. } else if !unsatisfied_predicates.is_empty() { let mut type_params = FxIndexMap::default(); @@ -1325,7 +1336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); - return Some(err); + Some(err) } fn note_candidates_on_method_error( @@ -2918,19 +2929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - unsatisfied_predicates.iter().all(|(p, _, _)| { - match p.kind().skip_binder() { - // Hide traits if they are present in predicates as they can be fixed without - // having to implement them. - ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { - t.def_id() == info.def_id - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { - p.projection_ty.def_id == info.def_id - } - _ => false, - } - }) && (type_is_local || info.def_id.is_local()) + (type_is_local || info.def_id.is_local()) && !self.tcx.trait_is_auto(info.def_id) && self .associated_value(info.def_id, item_name) @@ -2978,6 +2977,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item.visibility(self.tcx).is_public() || info.def_id.is_local() }) .is_some() + && (matches!(rcvr_ty.kind(), ty::Param(_)) + || unsatisfied_predicates.iter().all(|(p, _, _)| { + match p.kind().skip_binder() { + // Hide traits if they are present in predicates as they can be fixed without + // having to implement them. + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { + t.def_id() == info.def_id + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { + p.projection_ty.def_id == info.def_id + } + _ => false, + } + })) }) .collect::>(); for span in &arbitrary_rcvr { diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index 0b650995de5c5..f12b4d6cabdaf 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -1,18 +1,18 @@ -error[E0599]: `T` is not an iterator +error[E0599]: no method named `cmp` found for type parameter `T` in the current scope --> $DIR/method-on-unbounded-type-param.rs:2:7 | LL | fn f(a: T, b: T) -> std::cmp::Ordering { | - method `cmp` not found for this type parameter LL | a.cmp(&b) - | ^^^ `T` is not an iterator + | ^^^ method cannot be called on `T` due to unsatisfied trait bounds | - = note: the following trait bounds were not satisfied: - `T: Iterator` - which is required by `&mut T: Iterator` -help: consider restricting the type parameter to satisfy the trait bound + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | -LL | fn f(a: T, b: T) -> std::cmp::Ordering where T: Iterator { - | +++++++++++++++++ +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | +++++ +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | ++++++++++ error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:5:10 From 9ccc77036a144cc0d172c28e48c330d544ae5471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 30 Jan 2024 19:13:11 +0000 Subject: [PATCH 017/101] fix rebase --- .../method-on-unbounded-type-param.stderr | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index f12b4d6cabdaf..245c25bbc6f67 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -53,20 +53,11 @@ LL | fn h(a: &T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord { error[E0599]: the method `cmp` exists for struct `Box`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:14:7 | -LL | trait T {} - | ------- - | | - | doesn't satisfy `dyn T: Iterator` - | doesn't satisfy `dyn T: Ord` +LL | trait T {} + | ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord` ... -LL | x.cmp(&x); - | ^^^ method cannot be called on `Box` due to unsatisfied trait bounds - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL - | - = note: doesn't satisfy `Box: Iterator` - | - = note: doesn't satisfy `Box: Ord` +LL | x.cmp(&x); + | ^^^ method cannot be called on `Box` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `dyn T: Iterator` From 5c414094ac8d41038819dd982403f4e3de05d93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 30 Jan 2024 18:10:12 +0000 Subject: [PATCH 018/101] Account for non-overlapping unmet trait bounds in suggestion When a method not found on a type parameter could have been provided by any of multiple traits, suggest each trait individually, instead of a single suggestion to restrict the type parameter with *all* of them. Before: ``` error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:5:10 | LL | (&a).cmp(&b) | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `T: Ord` which is required by `&T: Ord` `&T: Iterator` which is required by `&mut &T: Iterator` `T: Iterator` which is required by `&mut T: Iterator` help: consider restricting the type parameters to satisfy the trait bounds | LL | fn g(a: T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord { | +++++++++++++++++++++++++ ``` After: ``` error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:5:10 | LL | (&a).cmp(&b) | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `T: Ord` which is required by `&T: Ord` `&T: Iterator` which is required by `&mut &T: Iterator` `T: Iterator` which is required by `&mut T: Iterator` = help: items from traits can only be used if the type parameter is bounded by the trait help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | LL | fn g(a: T, b: T) -> std::cmp::Ordering { | +++++ LL | fn g(a: T, b: T) -> std::cmp::Ordering { | ++++++++++ ``` Fix #108428. --- .../rustc_hir_typeck/src/method/suggest.rs | 58 +++++++------------ .../box/unit/unique-object-noncopyable.stderr | 3 + tests/ui/box/unit/unique-pinned-nocopy.stderr | 3 - .../derives/derive-assoc-type-not-impl.stderr | 3 - ...method-unsatisfied-assoc-type-predicate.rs | 2 +- ...od-unsatisfied-assoc-type-predicate.stderr | 6 ++ .../trait-bounds/issue-30786.stderr | 12 ++++ tests/ui/methods/method-call-err-msg.stderr | 5 +- .../method-on-unbounded-type-param.stderr | 22 +++++-- 9 files changed, 62 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index de42f011cf42a..f7aa5209e94a7 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -540,6 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut bound_spans: SortedMap> = Default::default(); let mut restrict_type_params = false; + let mut suggested_derive = false; let mut unsatisfied_bounds = false; if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) { let msg = "consider using `len` instead"; @@ -927,20 +928,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .enumerate() .collect::>(); - for ((span, add_where_or_comma), obligations) in type_params.into_iter() { - restrict_type_params = true; - // #74886: Sort here so that the output is always the same. - let obligations = obligations.into_sorted_stable_ord(); - err.span_suggestion_verbose( - span, - format!( - "consider restricting the type parameter{s} to satisfy the \ - trait bound{s}", - s = pluralize!(obligations.len()) - ), - format!("{} {}", add_where_or_comma, obligations.join(", ")), - Applicability::MaybeIncorrect, - ); + if !matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) { + for ((span, add_where_or_comma), obligations) in type_params.into_iter() { + restrict_type_params = true; + // #74886: Sort here so that the output is always the same. + let obligations = obligations.into_sorted_stable_ord(); + err.span_suggestion_verbose( + span, + format!( + "consider restricting the type parameter{s} to satisfy the trait \ + bound{s}", + s = pluralize!(obligations.len()) + ), + format!("{} {}", add_where_or_comma, obligations.join(", ")), + Applicability::MaybeIncorrect, + ); + } } bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically. @@ -988,7 +991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the following trait bounds were not satisfied:\n{bound_list}" )); } - self.suggest_derive(&mut err, unsatisfied_predicates); + suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates); unsatisfied_bounds = true; } @@ -1211,7 +1214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params { + if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive { } else { self.suggest_traits_to_import( &mut err, @@ -1221,7 +1224,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args.map(|args| args.len() + 1), source, no_match_data.out_of_scope_traits.clone(), - unsatisfied_predicates, static_candidates, unsatisfied_bounds, expected.only_has_type(self), @@ -2481,7 +2483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Option>, Option>, )], - ) { + ) -> bool { let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates); derives.sort(); derives.dedup(); @@ -2506,6 +2508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } + !derives_grouped.is_empty() } fn note_derefed_ty_has_method( @@ -2708,11 +2711,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inputs_len: Option, source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec, - unsatisfied_predicates: &[( - ty::Predicate<'tcx>, - Option>, - Option>, - )], static_candidates: &[CandidateSource], unsatisfied_bounds: bool, return_type: Option>, @@ -2977,20 +2975,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item.visibility(self.tcx).is_public() || info.def_id.is_local() }) .is_some() - && (matches!(rcvr_ty.kind(), ty::Param(_)) - || unsatisfied_predicates.iter().all(|(p, _, _)| { - match p.kind().skip_binder() { - // Hide traits if they are present in predicates as they can be fixed without - // having to implement them. - ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { - t.def_id() == info.def_id - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { - p.projection_ty.def_id == info.def_id - } - _ => false, - } - })) }) .collect::>(); for span in &arbitrary_rcvr { diff --git a/tests/ui/box/unit/unique-object-noncopyable.stderr b/tests/ui/box/unit/unique-object-noncopyable.stderr index 49547872d1a7b..8ea6edb48a7fc 100644 --- a/tests/ui/box/unit/unique-object-noncopyable.stderr +++ b/tests/ui/box/unit/unique-object-noncopyable.stderr @@ -12,6 +12,9 @@ LL | let _z = y.clone(); which is required by `Box: Clone` `dyn Foo: Clone` which is required by `Box: Clone` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `clone`, perhaps you need to implement it: + candidate #1: `Clone` error: aborting due to 1 previous error diff --git a/tests/ui/box/unit/unique-pinned-nocopy.stderr b/tests/ui/box/unit/unique-pinned-nocopy.stderr index d2bf72249c451..69428604b197f 100644 --- a/tests/ui/box/unit/unique-pinned-nocopy.stderr +++ b/tests/ui/box/unit/unique-pinned-nocopy.stderr @@ -10,9 +10,6 @@ LL | let _j = i.clone(); = note: the following trait bounds were not satisfied: `R: Clone` which is required by `Box: Clone` - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `Clone` help: consider annotating `R` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/derives/derive-assoc-type-not-impl.stderr b/tests/ui/derives/derive-assoc-type-not-impl.stderr index 61268ffc7f852..13ba80243a5eb 100644 --- a/tests/ui/derives/derive-assoc-type-not-impl.stderr +++ b/tests/ui/derives/derive-assoc-type-not-impl.stderr @@ -15,9 +15,6 @@ note: trait bound `NotClone: Clone` was not satisfied | LL | #[derive(Clone)] | ^^^^^ unsatisfied trait bound introduced in this `derive` macro - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `Clone` help: consider annotating `NotClone` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs index add4d58f86a0d..92ce4a0970f36 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs @@ -5,7 +5,7 @@ trait X { type Y; } -trait M { +trait M { //~ NOTE fn f(&self) {} } diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr index 1dd463f996ce6..61512dd46582d 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr @@ -14,6 +14,12 @@ LL | impl = i32>> M for T {} | ^^^^^^^^^^^^ - - | | | unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `M` defines an item `f`, perhaps you need to implement it + --> $DIR/method-unsatisfied-assoc-type-predicate.rs:8:1 + | +LL | trait M { + | ^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr index 73870703cfbac..699a4ecc42bb9 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr @@ -15,6 +15,12 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `filterx`, perhaps you need to implement it + --> $DIR/issue-30786.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:132:24 @@ -33,6 +39,12 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `countx`, perhaps you need to implement it + --> $DIR/issue-30786.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index f431085745405..6df49e432a13a 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -63,8 +63,9 @@ LL | | .take() note: the trait `Iterator` must be implemented --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `take`, perhaps you need to implement it: - candidate #1: `Iterator` + = note: the following traits define an item `take`, perhaps you need to implement one of them: + candidate #1: `std::io::Read` + candidate #2: `Iterator` error[E0061]: this method takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index 245c25bbc6f67..0d8bd8ee964e7 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -27,10 +27,13 @@ LL | (&a).cmp(&b) which is required by `&mut &T: Iterator` `T: Iterator` which is required by `&mut T: Iterator` -help: consider restricting the type parameters to satisfy the trait bounds + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | -LL | fn g(a: T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord { - | +++++++++++++++++++++++++ +LL | fn g(a: T, b: T) -> std::cmp::Ordering { + | +++++ +LL | fn g(a: T, b: T) -> std::cmp::Ordering { + | ++++++++++ error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:8:7 @@ -45,10 +48,13 @@ LL | a.cmp(&b) which is required by `&mut &T: Iterator` `T: Iterator` which is required by `&mut T: Iterator` -help: consider restricting the type parameters to satisfy the trait bounds + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | -LL | fn h(a: &T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord { - | +++++++++++++++++++++++++ +LL | fn h(a: &T, b: T) -> std::cmp::Ordering { + | +++++ +LL | fn h(a: &T, b: T) -> std::cmp::Ordering { + | ++++++++++ error[E0599]: the method `cmp` exists for struct `Box`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:14:7 @@ -68,6 +74,10 @@ LL | x.cmp(&x); which is required by `&mut Box: Iterator` `dyn T: Iterator` which is required by `&mut dyn T: Iterator` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `cmp`, perhaps you need to implement one of them: + candidate #1: `Ord` + candidate #2: `Iterator` error: aborting due to 4 previous errors From 73313158988c20b57a341502b4099629b6867755 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 30 Jan 2024 20:55:56 +0000 Subject: [PATCH 019/101] Remove `ffi_returns_twice` feature --- compiler/rustc_codegen_gcc/src/attributes.rs | 3 --- compiler/rustc_codegen_llvm/src/attributes.rs | 3 --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 - .../rustc_codegen_ssa/src/codegen_attrs.rs | 3 --- .../src/error_codes/E0724.md | 7 ++++-- compiler/rustc_feature/src/builtin_attrs.rs | 3 --- compiler/rustc_feature/src/removed.rs | 3 +++ compiler/rustc_feature/src/unstable.rs | 2 -- .../rustc_llvm/llvm-wrapper/LLVMWrapper.h | 1 - .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 -- .../src/middle/codegen_fn_attrs.rs | 23 ++++++++----------- compiler/rustc_passes/messages.ftl | 3 --- compiler/rustc_passes/src/check_attr.rs | 10 -------- compiler/rustc_passes/src/errors.rs | 7 ------ src/tools/tidy/src/ui_tests.rs | 2 +- tests/codegen/cffi/ffi-returns-twice.rs | 11 --------- .../feature-gate-ffi_returns_twice.rs | 6 ----- .../feature-gate-ffi_returns_twice.stderr | 13 ----------- tests/ui/ffi_returns_twice.rs | 15 ------------ tests/ui/ffi_returns_twice.stderr | 21 ----------------- 20 files changed, 19 insertions(+), 120 deletions(-) delete mode 100644 tests/codegen/cffi/ffi-returns-twice.rs delete mode 100644 tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs delete mode 100644 tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr delete mode 100644 tests/ui/ffi_returns_twice.rs delete mode 100644 tests/ui/ffi_returns_twice.stderr diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index 9f361d3688695..142f86b003ddb 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -62,9 +62,6 @@ pub fn from_fn_attrs<'gcc, 'tcx>( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { func.add_attribute(FnAttribute::Cold); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) { - func.add_attribute(FnAttribute::ReturnsTwice); - } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) { func.add_attribute(FnAttribute::Pure); } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 0a7ea5994312e..07c83f1aa089a 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -356,9 +356,6 @@ pub fn from_fn_attrs<'ll, 'tcx>( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { to_add.push(AttributeKind::Cold.create_attr(cx.llcx)); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) { - to_add.push(AttributeKind::ReturnsTwice.create_attr(cx.llcx)); - } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) { to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx)); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ee73c6b4756f0..5c06c62b11a3c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -185,7 +185,6 @@ pub enum AttributeKind { SanitizeMemory = 22, NonLazyBind = 23, OptimizeNone = 24, - ReturnsTwice = 25, ReadNone = 26, SanitizeHWAddress = 28, WillReturn = 29, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 47b1b0801193a..b387d0b2258b0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -103,9 +103,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { match name { sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR, - sym::ffi_returns_twice => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE - } sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE, sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST, sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, diff --git a/compiler/rustc_error_codes/src/error_codes/E0724.md b/compiler/rustc_error_codes/src/error_codes/E0724.md index 70578acbe0d5f..bcefd0a74798b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0724.md +++ b/compiler/rustc_error_codes/src/error_codes/E0724.md @@ -1,9 +1,12 @@ +#### Note: this error code is no longer emitted by the compiler. + + `#[ffi_returns_twice]` was used on something other than a foreign function declaration. Erroneous code example: -```compile_fail,E0724 +```compile_fail #![feature(ffi_returns_twice)] #![crate_type = "lib"] @@ -15,7 +18,7 @@ pub fn foo() {} For example, we might correct the previous example by declaring the function inside of an `extern` block. -``` +```compile_fail #![feature(ffi_returns_twice)] extern "C" { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 68b6f69854dd6..019cc1c847e91 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -440,9 +440,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(optimize), ), - gated!( - ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice) - ), gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)), gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)), gated!( diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 67ee53d8ae53f..dc97898736808 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -95,6 +95,9 @@ declare_features! ( /// Allows `#[doc(include = "some-file")]`. (removed, external_doc, "1.54.0", Some(44732), Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")), + /// Allows using `#[ffi_returns_twice]` on foreign functions. + (removed, ffi_returns_twice, "CURRENT_RUSTC_VERSION", Some(58314), + Some("being investigated by the ffi-unwind project group")), /// Allows generators to be cloned. (removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")), /// Allows defining generators. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e66a66e23dc4f..0efc031df0aa6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -467,8 +467,6 @@ declare_features! ( (unstable, ffi_const, "1.45.0", Some(58328)), /// Allows the use of `#[ffi_pure]` on foreign functions. (unstable, ffi_pure, "1.45.0", Some(58329)), - /// Allows using `#[ffi_returns_twice]` on foreign functions. - (unstable, ffi_returns_twice, "1.34.0", Some(58314)), /// Allows using `#[repr(align(...))]` on function items (unstable, fn_align, "1.53.0", Some(82232)), /// Support delegating implementation of functions to other already implemented functions. diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 5bfffc5d9117b..6d578c97f3fe1 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -76,7 +76,6 @@ enum LLVMRustAttribute { SanitizeMemory = 22, NonLazyBind = 23, OptimizeNone = 24, - ReturnsTwice = 25, ReadNone = 26, SanitizeHWAddress = 28, WillReturn = 29, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 0df7b7eed11f9..a2dfebec59441 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -250,8 +250,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::NonLazyBind; case OptimizeNone: return Attribute::OptimizeNone; - case ReturnsTwice: - return Attribute::ReturnsTwice; case ReadNone: return Attribute::ReadNone; case SanitizeHWAddress: diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index e11c9371118cb..7d6d39a2a8a39 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -74,35 +74,32 @@ bitflags! { /// `#[used]`: indicates that LLVM can't eliminate this function (but the /// linker can!). const USED = 1 << 9; - /// `#[ffi_returns_twice]`, indicates that an extern function can return - /// multiple times - const FFI_RETURNS_TWICE = 1 << 10; /// `#[track_caller]`: allow access to the caller location - const TRACK_CALLER = 1 << 11; + const TRACK_CALLER = 1 << 10; /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function /// declaration. - const FFI_PURE = 1 << 12; + const FFI_PURE = 1 << 11; /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. - const FFI_CONST = 1 << 13; + const FFI_CONST = 1 << 12; /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a /// function as an entry function from Non-Secure code. - const CMSE_NONSECURE_ENTRY = 1 << 14; + const CMSE_NONSECURE_ENTRY = 1 << 13; /// `#[coverage(off)]`: indicates that the function should be ignored by /// the MIR `InstrumentCoverage` pass and not added to the coverage map /// during codegen. - const NO_COVERAGE = 1 << 15; + const NO_COVERAGE = 1 << 14; /// `#[used(linker)]`: /// indicates that neither LLVM nor the linker will eliminate this function. - const USED_LINKER = 1 << 16; + const USED_LINKER = 1 << 15; /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory. - const DEALLOCATOR = 1 << 17; + const DEALLOCATOR = 1 << 16; /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory. - const REALLOCATOR = 1 << 18; + const REALLOCATOR = 1 << 17; /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory. - const ALLOCATOR_ZEROED = 1 << 19; + const ALLOCATOR_ZEROED = 1 << 18; /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function. - const NO_BUILTINS = 1 << 20; + const NO_BUILTINS = 1 << 19; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d41cc724408a4..648ef9d51deaa 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -323,9 +323,6 @@ passes_ffi_const_invalid_target = passes_ffi_pure_invalid_target = `#[ffi_pure]` may only be used on foreign functions -passes_ffi_returns_twice_invalid_target = - `#[ffi_returns_twice]` may only be used on foreign functions - passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. .label = only adts, extern types and traits are supported diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8f27d01794cc6..51725285bd7ac 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -190,7 +190,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target), sym::ffi_const => self.check_ffi_const(attr.span, target), - sym::ffi_returns_twice => self.check_ffi_returns_twice(attr.span, target), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -1307,15 +1306,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_ffi_returns_twice(&self, attr_span: Span, target: Target) -> bool { - if target == Target::ForeignFn { - true - } else { - self.dcx().emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span }); - false - } - } - /// Warns against some misuses of `#[must_use]` fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool { if !matches!( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 77bfe57e3706f..6a499a98681e6 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -390,13 +390,6 @@ pub struct FfiConstInvalidTarget { pub attr_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_ffi_returns_twice_invalid_target, code = E0724)] -pub struct FfiReturnsTwiceInvalidTarget { - #[primary_span] - pub attr_span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_must_use_async)] pub struct MustUseAsync { diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 451276b5ac157..094694274269f 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -14,7 +14,7 @@ use std::path::{Path, PathBuf}; // #73494. const ENTRY_LIMIT: usize = 900; const ISSUES_ENTRY_LIMIT: usize = 1807; -const ROOT_ENTRY_LIMIT: usize = 870; +const ROOT_ENTRY_LIMIT: usize = 868; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/codegen/cffi/ffi-returns-twice.rs b/tests/codegen/cffi/ffi-returns-twice.rs deleted file mode 100644 index 0fbe03f0bb6f1..0000000000000 --- a/tests/codegen/cffi/ffi-returns-twice.rs +++ /dev/null @@ -1,11 +0,0 @@ -// compile-flags: -C no-prepopulate-passes -#![crate_type = "lib"] -#![feature(ffi_returns_twice)] - -pub fn bar() { unsafe { foo() } } - -extern "C" { - // CHECK: declare{{( dso_local)?}} void @foo(){{.*}}[[ATTRS:#[0-9]+]] - // CHECK: attributes [[ATTRS]] = { {{.*}}returns_twice{{.*}} } - #[ffi_returns_twice] pub fn foo(); -} diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs deleted file mode 100644 index f354534356c21..0000000000000 --- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![crate_type = "lib"] - -extern "C" { - #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature - pub fn foo(); -} diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr deleted file mode 100644 index 8d19874c36a0c..0000000000000 --- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature - --> $DIR/feature-gate-ffi_returns_twice.rs:4:5 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #58314 for more information - = help: add `#![feature(ffi_returns_twice)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/ffi_returns_twice.rs b/tests/ui/ffi_returns_twice.rs deleted file mode 100644 index 8195d0e486369..0000000000000 --- a/tests/ui/ffi_returns_twice.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(ffi_returns_twice)] -#![crate_type = "lib"] - -#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions -pub fn foo() {} - -#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions -macro_rules! bar { - () => () -} - -extern "C" { - #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions - static INT: i32; -} diff --git a/tests/ui/ffi_returns_twice.stderr b/tests/ui/ffi_returns_twice.stderr deleted file mode 100644 index 0abe7613f1493..0000000000000 --- a/tests/ui/ffi_returns_twice.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions - --> $DIR/ffi_returns_twice.rs:4:1 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions - --> $DIR/ffi_returns_twice.rs:7:1 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions - --> $DIR/ffi_returns_twice.rs:13:5 - | -LL | #[ffi_returns_twice] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0724`. From f622e832d41171578b6987d0b25b3a84d6d1c81c Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 24 Jan 2024 15:57:43 -0800 Subject: [PATCH 020/101] Actually abort in panic-abort-tests --- Cargo.lock | 1 + library/test/Cargo.toml | 1 + library/test/src/helpers/exit_code.rs | 20 --------------- library/test/src/helpers/mod.rs | 1 - library/test/src/lib.rs | 15 ++--------- library/test/src/test_result.rs | 36 +++++++++++++++++++++------ 6 files changed, 33 insertions(+), 41 deletions(-) delete mode 100644 library/test/src/helpers/exit_code.rs diff --git a/Cargo.lock b/Cargo.lock index 74f96983b3149..24054e8592e2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5332,6 +5332,7 @@ version = "0.0.0" dependencies = [ "core", "getopts", + "libc", "panic_abort", "panic_unwind", "std", diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 92c535501bf9c..4c42e3bae563e 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -9,3 +9,4 @@ std = { path = "../std" } core = { path = "../core" } panic_unwind = { path = "../panic_unwind" } panic_abort = { path = "../panic_abort" } +libc = { version = "0.2.150", default-features = false } diff --git a/library/test/src/helpers/exit_code.rs b/library/test/src/helpers/exit_code.rs deleted file mode 100644 index f762f88819da5..0000000000000 --- a/library/test/src/helpers/exit_code.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Helper module to detect subprocess exit code. - -use std::process::ExitStatus; - -#[cfg(not(unix))] -pub fn get_exit_code(status: ExitStatus) -> Result { - status.code().ok_or_else(|| "received no exit code from child process".into()) -} - -#[cfg(unix)] -pub fn get_exit_code(status: ExitStatus) -> Result { - use std::os::unix::process::ExitStatusExt; - match status.code() { - Some(code) => Ok(code), - None => match status.signal() { - Some(signal) => Err(format!("child process exited with signal {signal}")), - None => Err("child process exited with unknown signal".into()), - }, - } -} diff --git a/library/test/src/helpers/mod.rs b/library/test/src/helpers/mod.rs index 6f366a911e8cd..3c79b90b16754 100644 --- a/library/test/src/helpers/mod.rs +++ b/library/test/src/helpers/mod.rs @@ -2,6 +2,5 @@ //! but used in `libtest`. pub mod concurrency; -pub mod exit_code; pub mod metrics; pub mod shuffle; diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 5969d6b772c34..da110f9924861 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -85,7 +85,6 @@ mod tests; use core::any::Any; use event::{CompletedTest, TestEvent}; use helpers::concurrency::get_concurrency; -use helpers::exit_code::get_exit_code; use helpers::shuffle::{get_shuffle_seed, shuffle_tests}; use options::RunStrategy; use test_result::*; @@ -712,17 +711,7 @@ fn spawn_test_subprocess( formatters::write_stderr_delimiter(&mut test_output, &desc.name); test_output.extend_from_slice(&stderr); - let result = match (|| -> Result { - let exit_code = get_exit_code(status)?; - Ok(get_result_from_exit_code(&desc, exit_code, &time_opts, &exec_time)) - })() { - Ok(r) => r, - Err(e) => { - write!(&mut test_output, "Unexpected error: {e}").unwrap(); - TrFailed - } - }; - + let result = get_result_from_exit_code(&desc, status, &time_opts, &exec_time); (result, test_output, exec_time) })(); @@ -751,7 +740,7 @@ fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) - if let TrOk = test_result { process::exit(test_result::TR_OK); } else { - process::exit(test_result::TR_FAILED); + process::abort(); } }); let record_result2 = record_result.clone(); diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index 1da238e3e8c0f..bb32c70d66311 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -1,4 +1,8 @@ use std::any::Any; +use std::process::ExitStatus; + +#[cfg(unix)] +use std::os::unix::process::ExitStatusExt; use super::bench::BenchSamples; use super::options::ShouldPanic; @@ -7,11 +11,15 @@ use super::types::TestDesc; pub use self::TestResult::*; -// Return codes for secondary process. +// Return code for secondary process. // Start somewhere other than 0 so we know the return code means what we think // it means. pub const TR_OK: i32 = 50; -pub const TR_FAILED: i32 = 51; + +// On Windows we use __fastfail to abort, which is documented to use this +// exception code. +#[cfg(windows)] +const STATUS_ABORTED: i32 = 0xC0000409u32 as i32; #[derive(Debug, Clone, PartialEq)] pub enum TestResult { @@ -81,14 +89,28 @@ pub fn calc_result<'a>( /// Creates a `TestResult` depending on the exit code of test subprocess. pub fn get_result_from_exit_code( desc: &TestDesc, - code: i32, + status: ExitStatus, time_opts: &Option, exec_time: &Option, ) -> TestResult { - let result = match code { - TR_OK => TestResult::TrOk, - TR_FAILED => TestResult::TrFailed, - _ => TestResult::TrFailedMsg(format!("got unexpected return code {code}")), + let result = match status.code() { + Some(TR_OK) => TestResult::TrOk, + #[cfg(windows)] + Some(STATUS_ABORTED) => TestResult::TrFailed, + #[cfg(unix)] + None => match status.signal() { + Some(libc::SIGABRT) => TestResult::TrFailed, + Some(signal) => { + TestResult::TrFailedMsg(format!("child process exited with signal {signal}")) + } + None => unreachable!("status.code() returned None but status.signal() was None"), + }, + #[cfg(not(unix))] + None => TestResult::TrFailedMsg(format!("unknown return code")), + #[cfg(any(windows, unix))] + Some(code) => TestResult::TrFailedMsg(format!("got unexpected return code {code}")), + #[cfg(not(any(windows, unix)))] + Some(_) => TestResult::TrFailed, }; // If test is already failed (or allowed to fail), do not change the result. From 3cc601ac7e43752e0514c6e1cb2415e781c8e666 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 31 Jan 2024 13:36:37 +0000 Subject: [PATCH 021/101] Switch OwnedStore handle count to AtomicU32 --- library/proc_macro/src/bridge/client.rs | 9 +++++---- library/proc_macro/src/bridge/handle.rs | 10 +++++----- library/proc_macro/src/bridge/mod.rs | 1 - 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 52a08cad9110f..9255c3abc8a02 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -3,6 +3,7 @@ use super::*; use std::marker::PhantomData; +use std::sync::atomic::AtomicU32; macro_rules! define_handles { ( @@ -12,8 +13,8 @@ macro_rules! define_handles { #[repr(C)] #[allow(non_snake_case)] pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* + $($oty: AtomicU32,)* + $($ity: AtomicU32,)* } impl HandleCounters { @@ -21,8 +22,8 @@ macro_rules! define_handles { // a wrapper `fn` pointer, once `const fn` can reference `static`s. extern "C" fn get() -> &'static Self { static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* + $($oty: AtomicU32::new(1),)* + $($ity: AtomicU32::new(1),)* }; &COUNTERS } diff --git a/library/proc_macro/src/bridge/handle.rs b/library/proc_macro/src/bridge/handle.rs index 00954107b7769..b3a763069974f 100644 --- a/library/proc_macro/src/bridge/handle.rs +++ b/library/proc_macro/src/bridge/handle.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use std::hash::Hash; use std::num::NonZeroU32; use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; use super::fxhash::FxHashMap; @@ -13,12 +13,12 @@ pub(super) type Handle = NonZeroU32; /// A store that associates values of type `T` with numeric handles. A value can /// be looked up using its handle. pub(super) struct OwnedStore { - counter: &'static AtomicUsize, + counter: &'static AtomicU32, data: BTreeMap, } impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { + pub(super) fn new(counter: &'static AtomicU32) -> Self { // Ensure the handle counter isn't 0, which would panic later, // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. assert_ne!(counter.load(Ordering::SeqCst), 0); @@ -30,7 +30,7 @@ impl OwnedStore { impl OwnedStore { pub(super) fn alloc(&mut self, x: T) -> Handle { let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); + let handle = Handle::new(counter).expect("`proc_macro` handle counter overflowed"); assert!(self.data.insert(handle, x).is_none()); handle } @@ -60,7 +60,7 @@ pub(super) struct InternedStore { } impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { + pub(super) fn new(counter: &'static AtomicU32) -> Self { InternedStore { owned: OwnedStore::new(counter), interner: FxHashMap::default() } } diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 75bf3329786a4..55e24b6491c79 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -16,7 +16,6 @@ use std::mem; use std::ops::Bound; use std::ops::Range; use std::panic; -use std::sync::atomic::AtomicUsize; use std::sync::Once; use std::thread; From be77cf86bae2b8a9c94eb93092d1b05230b17e8c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 25 Jan 2024 03:37:24 +0100 Subject: [PATCH 022/101] Use a `Vec` instead of a slice in `DeconstructedPat` --- compiler/rustc_pattern_analysis/src/lib.rs | 8 +-- compiler/rustc_pattern_analysis/src/pat.rs | 32 ++++++----- .../rustc_pattern_analysis/src/pat_column.rs | 4 +- compiler/rustc_pattern_analysis/src/rustc.rs | 57 ++++++++----------- .../rustc_pattern_analysis/src/usefulness.rs | 4 +- 5 files changed, 51 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 3d0eb117d174f..cef2fe1621500 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -119,7 +119,7 @@ pub trait TypeCx: Sized + fmt::Debug { /// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`. fn write_variant_name( f: &mut fmt::Formatter<'_>, - pat: &crate::pat::DeconstructedPat<'_, Self>, + pat: &crate::pat::DeconstructedPat, ) -> fmt::Result; /// Raise a bug. @@ -130,9 +130,9 @@ pub trait TypeCx: Sized + fmt::Debug { /// The default implementation does nothing. fn lint_overlapping_range_endpoints( &self, - _pat: &DeconstructedPat<'_, Self>, + _pat: &DeconstructedPat, _overlaps_on: IntRange, - _overlaps_with: &[&DeconstructedPat<'_, Self>], + _overlaps_with: &[&DeconstructedPat], ) { } } @@ -140,7 +140,7 @@ pub trait TypeCx: Sized + fmt::Debug { /// The arm of a match expression. #[derive(Debug)] pub struct MatchArm<'p, Cx: TypeCx> { - pub pat: &'p DeconstructedPat<'p, Cx>, + pub pat: &'p DeconstructedPat, pub has_guard: bool, pub arm_data: Cx::ArmData, } diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index c94d8b9353589..0b239b5a36238 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -6,7 +6,7 @@ use std::fmt; use smallvec::{smallvec, SmallVec}; use crate::constructor::{Constructor, Slice, SliceKind}; -use crate::{Captures, TypeCx}; +use crate::TypeCx; use self::Constructor::*; @@ -21,9 +21,9 @@ use self::Constructor::*; /// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't /// observe that it is uninhabited. In that case that field is not included in `fields`. Care must /// be taken when converting to/from `thir::Pat`. -pub struct DeconstructedPat<'p, Cx: TypeCx> { +pub struct DeconstructedPat { ctor: Constructor, - fields: &'p [DeconstructedPat<'p, Cx>], + fields: Vec>, ty: Cx::Ty, /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not /// correspond to a user-supplied pattern. @@ -32,14 +32,20 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> { useful: Cell, } -impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { +impl DeconstructedPat { pub fn wildcard(ty: Cx::Ty) -> Self { - DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) } + DeconstructedPat { + ctor: Wildcard, + fields: Vec::new(), + ty, + data: None, + useful: Cell::new(false), + } } pub fn new( ctor: Constructor, - fields: &'p [DeconstructedPat<'p, Cx>], + fields: Vec>, ty: Cx::Ty, data: Cx::PatData, ) -> Self { @@ -62,17 +68,17 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { self.data.as_ref() } - pub fn iter_fields(&self) -> impl Iterator> + Captures<'_> { + pub fn iter_fields<'a>(&'a self) -> impl Iterator> { self.fields.iter() } /// Specialize this pattern with a constructor. /// `other_ctor` can be different from `self.ctor`, but must be covered by it. - pub(crate) fn specialize( - &self, + pub(crate) fn specialize<'a>( + &'a self, other_ctor: &Constructor, ctor_arity: usize, - ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> { + ) -> SmallVec<[PatOrWild<'a, Cx>; 2]> { let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect(); match (&self.ctor, other_ctor) { // Return a wildcard for each field of `other_ctor`. @@ -139,7 +145,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { } /// This is best effort and not good enough for a `Display` impl. -impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> { +impl fmt::Debug for DeconstructedPat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let pat = self; let mut first = true; @@ -221,7 +227,7 @@ pub(crate) enum PatOrWild<'p, Cx: TypeCx> { /// A non-user-provided wildcard, created during specialization. Wild, /// A user-provided pattern. - Pat(&'p DeconstructedPat<'p, Cx>), + Pat(&'p DeconstructedPat), } impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> { @@ -236,7 +242,7 @@ impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> { impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {} impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> { - pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> { + pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat> { match self { PatOrWild::Wild => None, PatOrWild::Pat(pat) => Some(pat), diff --git a/compiler/rustc_pattern_analysis/src/pat_column.rs b/compiler/rustc_pattern_analysis/src/pat_column.rs index 3cacfc491b981..d5db4bf4a342e 100644 --- a/compiler/rustc_pattern_analysis/src/pat_column.rs +++ b/compiler/rustc_pattern_analysis/src/pat_column.rs @@ -13,7 +13,7 @@ use crate::{Captures, MatchArm, TypeCx}; #[derive(Debug)] pub struct PatternColumn<'p, Cx: TypeCx> { /// This must not contain an or-pattern. `expand_and_push` takes care to expand them. - patterns: Vec<&'p DeconstructedPat<'p, Cx>>, + patterns: Vec<&'p DeconstructedPat>, } impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> { @@ -41,7 +41,7 @@ impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> { pub fn head_ty(&self) -> Option<&Cx::Ty> { self.patterns.first().map(|pat| pat.ty()) } - pub fn iter<'a>(&'a self) -> impl Iterator> + Captures<'a> { + pub fn iter<'a>(&'a self) -> impl Iterator> + Captures<'a> { self.patterns.iter().copied() } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ec37e20211860..431b7f4a31265 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,4 +1,3 @@ -use smallvec::SmallVec; use std::fmt; use std::iter::once; @@ -27,8 +26,7 @@ use crate::constructor::Constructor::*; pub type Constructor<'p, 'tcx> = crate::constructor::Constructor>; pub type ConstructorSet<'p, 'tcx> = crate::constructor::ConstructorSet>; -pub type DeconstructedPat<'p, 'tcx> = - crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>; +pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat>; pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>; pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>; pub type UsefulnessReport<'p, 'tcx> = @@ -458,21 +456,20 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { /// Note: the input patterns must have been lowered through /// `rustc_mir_build::thir::pattern::check_match::MatchVisitor::lower_pattern`. pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { - let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat)); let cx = self; let ty = cx.reveal_opaque_ty(pat.ty); let ctor; - let fields: &[_]; + let mut fields: Vec<_>; match &pat.kind { PatKind::AscribeUserType { subpattern, .. } | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; - fields = &[]; + fields = vec![]; } PatKind::Deref { subpattern } => { - fields = singleton(self.lower_pat(subpattern)); + fields = vec![self.lower_pat(subpattern)]; ctor = match ty.kind() { // This is a box pattern. ty::Adt(adt, ..) if adt.is_box() => Struct, @@ -484,15 +481,14 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { match ty.kind() { ty::Tuple(fs) => { ctor = Struct; - let mut wilds: SmallVec<[_; 2]> = fs + fields = fs .iter() .map(|ty| cx.reveal_opaque_ty(ty)) .map(|ty| DeconstructedPat::wildcard(ty)) .collect(); for pat in subpatterns { - wilds[pat.field.index()] = self.lower_pat(&pat.pattern); + fields[pat.field.index()] = self.lower_pat(&pat.pattern); } - fields = cx.pattern_arena.alloc_from_iter(wilds); } ty::Adt(adt, args) if adt.is_box() => { // The only legal patterns of type `Box` (outside `std`) are `_` and box @@ -514,7 +510,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { DeconstructedPat::wildcard(self.reveal_opaque_ty(args.type_at(0))) }; ctor = Struct; - fields = singleton(pat); + fields = vec![pat]; } ty::Adt(adt, _) => { ctor = match pat.kind { @@ -534,14 +530,12 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { ty }, ); - let mut wilds: SmallVec<[_; 2]> = - tys.map(|ty| DeconstructedPat::wildcard(ty)).collect(); + fields = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect(); for pat in subpatterns { if let Some(i) = field_id_to_id[pat.field.index()] { - wilds[i] = self.lower_pat(&pat.pattern); + fields[i] = self.lower_pat(&pat.pattern); } } - fields = cx.pattern_arena.alloc_from_iter(wilds); } _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), } @@ -553,7 +547,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { Some(b) => Bool(b), None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { @@ -569,7 +563,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Float(ty::FloatTy::F32) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { @@ -580,7 +574,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Float(ty::FloatTy::F64) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { @@ -591,7 +585,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } None => Opaque(OpaqueId::new()), }; - fields = &[]; + fields = vec![]; } ty::Ref(_, t, _) if t.is_str() => { // We want a `&str` constant to behave like a `Deref` pattern, to be compatible @@ -602,16 +596,16 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { // subfields. // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); - let subpattern = DeconstructedPat::new(Str(*value), &[], ty, pat); + let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), ty, pat); ctor = Ref; - fields = singleton(subpattern) + fields = vec![subpattern] } // All constants that can be structurally matched have already been expanded // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are // opaque. _ => { ctor = Opaque(OpaqueId::new()); - fields = &[]; + fields = vec![]; } } } @@ -648,7 +642,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } _ => bug!("invalid type for range pattern: {}", ty.inner()), }; - fields = &[]; + fields = vec![]; } PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { let array_len = match ty.kind() { @@ -664,25 +658,22 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { SliceKind::FixedLen(prefix.len() + suffix.len()) }; ctor = Slice(Slice::new(array_len, kind)); - fields = cx.pattern_arena.alloc_from_iter( - prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)), - ) + fields = prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)).collect(); } PatKind::Or { .. } => { ctor = Or; let pats = expand_or_pat(pat); - fields = - cx.pattern_arena.alloc_from_iter(pats.into_iter().map(|p| self.lower_pat(p))) + fields = pats.into_iter().map(|p| self.lower_pat(p)).collect(); } PatKind::Never => { // FIXME(never_patterns): handle `!` in exhaustiveness. This is a sane default // in the meantime. ctor = Wildcard; - fields = &[]; + fields = vec![]; } PatKind::Error(_) => { ctor = Opaque(OpaqueId::new()); - fields = &[]; + fields = vec![]; } } DeconstructedPat::new(ctor, fields, ty, pat) @@ -887,7 +878,7 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { fn write_variant_name( f: &mut fmt::Formatter<'_>, - pat: &crate::pat::DeconstructedPat<'_, Self>, + pat: &crate::pat::DeconstructedPat, ) -> fmt::Result { if let ty::Adt(adt, _) = pat.ty().kind() { if adt.is_box() { @@ -906,9 +897,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { fn lint_overlapping_range_endpoints( &self, - pat: &crate::pat::DeconstructedPat<'_, Self>, + pat: &crate::pat::DeconstructedPat, overlaps_on: IntRange, - overlaps_with: &[&crate::pat::DeconstructedPat<'_, Self>], + overlaps_with: &[&crate::pat::DeconstructedPat], ) { let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty()); let overlaps: Vec<_> = overlaps_with diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 3d45d032a9934..28600d6309781 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -848,7 +848,7 @@ impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> { } impl<'p, Cx: TypeCx> PatStack<'p, Cx> { - fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self { + fn from_pattern(pat: &'p DeconstructedPat) -> Self { PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true } } @@ -1585,7 +1585,7 @@ pub enum Usefulness<'p, Cx: TypeCx> { /// The arm is useful. This additionally carries a set of or-pattern branches that have been /// found to be redundant despite the overall arm being useful. Used only in the presence of /// or-patterns, otherwise it stays empty. - Useful(Vec<&'p DeconstructedPat<'p, Cx>>), + Useful(Vec<&'p DeconstructedPat>), /// The arm is redundant and can be removed without changing the behavior of the match /// expression. Redundant, From f65fe3ba59286710324abb9860667f1ecf805df9 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 25 Jan 2024 04:35:09 +0100 Subject: [PATCH 023/101] Remove `pattern_arena` from `RustcMatchCheckCtxt` --- .../rustc_mir_build/src/thir/pattern/check_match.rs | 3 +-- compiler/rustc_pattern_analysis/src/errors.rs | 5 ++++- compiler/rustc_pattern_analysis/src/rustc.rs | 12 +++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index caf7f4227dbf8..1156e8be13e74 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -291,7 +291,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { err = err.and(check_never_pattern(cx, pat)); }); err?; - Ok(cx.pattern_arena.alloc(cx.lower_pat(pat))) + Ok(self.pattern_arena.alloc(cx.lower_pat(pat))) } } @@ -388,7 +388,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { typeck_results: self.typeck_results, param_env: self.param_env, module: self.tcx.parent_module(self.lint_level).to_def_id(), - pattern_arena: self.pattern_arena, dropless_arena: self.dropless_arena, match_lint_level: self.lint_level, whole_match_span, diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 88770b0c43b37..bdb6cf19eac4e 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -23,7 +23,10 @@ impl<'tcx> Uncovered<'tcx> { span: Span, cx: &RustcMatchCheckCtxt<'p, 'tcx>, witnesses: Vec>, - ) -> Self { + ) -> Self + where + 'tcx: 'p, + { let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()); Self { span, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 431b7f4a31265..5334857343f91 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,7 +1,7 @@ use std::fmt; use std::iter::once; -use rustc_arena::{DroplessArena, TypedArena}; +use rustc_arena::DroplessArena; use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_index::{Idx, IndexVec}; @@ -62,7 +62,7 @@ impl<'tcx> RevealedTy<'tcx> { } #[derive(Clone)] -pub struct RustcMatchCheckCtxt<'p, 'tcx> { +pub struct RustcMatchCheckCtxt<'p, 'tcx: 'p> { pub tcx: TyCtxt<'tcx>, pub typeck_results: &'tcx ty::TypeckResults<'tcx>, /// The module in which the match occurs. This is necessary for @@ -72,8 +72,6 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> { /// outside its module and should not be matchable with an empty match statement. pub module: DefId, pub param_env: ty::ParamEnv<'tcx>, - /// To allocate lowered patterns - pub pattern_arena: &'p TypedArena>, /// To allocate the result of `self.ctor_sub_tys()` pub dropless_arena: &'p DroplessArena, /// Lint level at the match. @@ -89,13 +87,13 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> { pub known_valid_scrutinee: bool, } -impl<'p, 'tcx> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> { +impl<'p, 'tcx: 'p> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RustcMatchCheckCtxt").finish() } } -impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { +impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> { /// Type inference occasionally gives us opaque types in places where corresponding patterns /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited /// types, we use the corresponding concrete type if possible. @@ -844,7 +842,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } } -impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { +impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { type Ty = RevealedTy<'tcx>; type Error = ErrorGuaranteed; type VariantIdx = VariantIdx; From 2e212b79e09bce189a787a5b0c05ee5318e3c574 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 25 Jan 2024 13:35:40 +1100 Subject: [PATCH 024/101] coverage: Split out counter increment sites from BCB node/edge counters This makes it possible for two nodes/edges in the coverage graph to share the same counter, without causing the instrumentor to inject unwanted duplicate counter-increment statements. --- .../src/coverage/counters.rs | 70 ++++++++------- .../rustc_mir_transform/src/coverage/mod.rs | 89 +++++++++---------- 2 files changed, 79 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 8c11dea5d4ee6..9a1d8bae6b410 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -1,4 +1,5 @@ -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::WithNumNodes; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; @@ -38,19 +39,27 @@ impl Debug for BcbCounter { } } +#[derive(Debug)] +pub(super) enum CounterIncrementSite { + Node { bcb: BasicCoverageBlock }, + Edge { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock }, +} + /// Generates and stores coverage counter and coverage expression information /// associated with nodes/edges in the BCB graph. pub(super) struct CoverageCounters { - next_counter_id: CounterId, + /// List of places where a counter-increment statement should be injected + /// into MIR, each with its corresponding counter ID. + counter_increment_sites: IndexVec, /// Coverage counters/expressions that are associated with individual BCBs. bcb_counters: IndexVec>, /// Coverage counters/expressions that are associated with the control-flow /// edge between two BCBs. /// - /// The iteration order of this map can affect the precise contents of MIR, - /// so we use `FxIndexMap` to avoid query stability hazards. - bcb_edge_counters: FxIndexMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, + /// We currently don't iterate over this map, but if we do in the future, + /// switch it back to `FxIndexMap` to avoid query stability hazards. + bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, /// Tracks which BCBs have a counter associated with some incoming edge. /// Only used by assertions, to verify that BCBs with incoming edge /// counters do not have their own physical counters (expressions are allowed). @@ -71,9 +80,9 @@ impl CoverageCounters { let num_bcbs = basic_coverage_blocks.num_nodes(); let mut this = Self { - next_counter_id: CounterId::START, + counter_increment_sites: IndexVec::new(), bcb_counters: IndexVec::from_elem_n(None, num_bcbs), - bcb_edge_counters: FxIndexMap::default(), + bcb_edge_counters: FxHashMap::default(), bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs), expressions: IndexVec::new(), }; @@ -84,8 +93,8 @@ impl CoverageCounters { this } - fn make_counter(&mut self) -> BcbCounter { - let id = self.next_counter(); + fn make_counter(&mut self, site: CounterIncrementSite) -> BcbCounter { + let id = self.counter_increment_sites.push(site); BcbCounter::Counter { id } } @@ -103,15 +112,8 @@ impl CoverageCounters { self.make_expression(lhs, Op::Add, rhs) } - /// Counter IDs start from one and go up. - fn next_counter(&mut self) -> CounterId { - let next = self.next_counter_id; - self.next_counter_id = self.next_counter_id + 1; - next - } - pub(super) fn num_counters(&self) -> usize { - self.next_counter_id.as_usize() + self.counter_increment_sites.len() } #[cfg(test)] @@ -171,22 +173,26 @@ impl CoverageCounters { self.bcb_counters[bcb] } - pub(super) fn bcb_node_counters( + /// Returns an iterator over all the nodes/edges in the coverage graph that + /// should have a counter-increment statement injected into MIR, along with + /// each site's corresponding counter ID. + pub(super) fn counter_increment_sites( &self, - ) -> impl Iterator { - self.bcb_counters - .iter_enumerated() - .filter_map(|(bcb, counter_kind)| Some((bcb, counter_kind.as_ref()?))) + ) -> impl Iterator { + self.counter_increment_sites.iter_enumerated() } - /// For each edge in the BCB graph that has an associated counter, yields - /// that edge's *from* and *to* nodes, and its counter. - pub(super) fn bcb_edge_counters( + /// Returns an iterator over the subset of BCB nodes that have been associated + /// with a counter *expression*, along with the ID of that expression. + pub(super) fn bcb_nodes_with_coverage_expressions( &self, - ) -> impl Iterator { - self.bcb_edge_counters - .iter() - .map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind)) + ) -> impl Iterator + Captures<'_> { + self.bcb_counters.iter_enumerated().filter_map(|(bcb, &counter_kind)| match counter_kind { + // Yield the BCB along with its associated expression ID. + Some(BcbCounter::Expression { id }) => Some((bcb, id)), + // This BCB is associated with a counter or nothing, so skip it. + Some(BcbCounter::Counter { .. }) | None => None, + }) } pub(super) fn into_expressions(self) -> IndexVec { @@ -339,7 +345,8 @@ impl<'a> MakeBcbCounters<'a> { // program results in a tight infinite loop, but it should still compile. let one_path_to_target = !self.basic_coverage_blocks.bcb_has_multiple_in_edges(bcb); if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { - let counter_kind = self.coverage_counters.make_counter(); + let counter_kind = + self.coverage_counters.make_counter(CounterIncrementSite::Node { bcb }); if one_path_to_target { debug!("{bcb:?} gets a new counter: {counter_kind:?}"); } else { @@ -401,7 +408,8 @@ impl<'a> MakeBcbCounters<'a> { } // Make a new counter to count this edge. - let counter_kind = self.coverage_counters.make_counter(); + let counter_kind = + self.coverage_counters.make_counter(CounterIncrementSite::Edge { from_bcb, to_bcb }); debug!("Edge {from_bcb:?}->{to_bcb:?} gets a new counter: {counter_kind:?}"); self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind) } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 5fb72fcf0cf3e..ef40af3716c1f 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -7,7 +7,7 @@ mod spans; #[cfg(test)] mod tests; -use self::counters::{BcbCounter, CoverageCounters}; +use self::counters::{CounterIncrementSite, CoverageCounters}; use self::graph::{BasicCoverageBlock, CoverageGraph}; use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans}; @@ -155,61 +155,52 @@ fn inject_coverage_statements<'tcx>( bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, coverage_counters: &CoverageCounters, ) { - // Process the counters associated with BCB nodes. - for (bcb, counter_kind) in coverage_counters.bcb_node_counters() { - let do_inject = match counter_kind { - // Counter-increment statements always need to be injected. - BcbCounter::Counter { .. } => true, - // The only purpose of expression-used statements is to detect - // when a mapping is unreachable, so we only inject them for - // expressions with one or more mappings. - BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb), - }; - if do_inject { - inject_statement( - mir_body, - make_mir_coverage_kind(counter_kind), - basic_coverage_blocks[bcb].leader_bb(), - ); - } - } - - // Process the counters associated with BCB edges. - for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() { - let do_inject = match counter_kind { - // Counter-increment statements always need to be injected. - BcbCounter::Counter { .. } => true, - // BCB-edge expressions never have mappings, so they never need - // a corresponding statement. - BcbCounter::Expression { .. } => false, + // Inject counter-increment statements into MIR. + for (id, counter_increment_site) in coverage_counters.counter_increment_sites() { + // Determine the block to inject a counter-increment statement into. + // For BCB nodes this is just their first block, but for edges we need + // to create a new block between the two BCBs, and inject into that. + let target_bb = match *counter_increment_site { + CounterIncrementSite::Node { bcb } => basic_coverage_blocks[bcb].leader_bb(), + CounterIncrementSite::Edge { from_bcb, to_bcb } => { + // Create a new block between the last block of `from_bcb` and + // the first block of `to_bcb`. + let from_bb = basic_coverage_blocks[from_bcb].last_bb(); + let to_bb = basic_coverage_blocks[to_bcb].leader_bb(); + + let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb); + debug!( + "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ + requires a new MIR BasicBlock {new_bb:?} for counter increment {id:?}", + ); + new_bb + } }; - if !do_inject { - continue; - } - - // We need to inject a coverage statement into a new BB between the - // last BB of `from_bcb` and the first BB of `to_bcb`. - let from_bb = basic_coverage_blocks[from_bcb].last_bb(); - let to_bb = basic_coverage_blocks[to_bcb].leader_bb(); - let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb); - debug!( - "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ - requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}", - ); - - // Inject a counter into the newly-created BB. - inject_statement(mir_body, make_mir_coverage_kind(counter_kind), new_bb); + inject_statement(mir_body, CoverageKind::CounterIncrement { id }, target_bb); } -} -fn make_mir_coverage_kind(counter_kind: &BcbCounter) -> CoverageKind { - match *counter_kind { - BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id }, - BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id }, + // For each counter expression that is directly associated with at least one + // span, we inject an "expression-used" statement, so that coverage codegen + // can check whether the injected statement survived MIR optimization. + // (BCB edges can't have spans, so we only need to process BCB nodes here.) + // + // See the code in `rustc_codegen_llvm::coverageinfo::map_data` that deals + // with "expressions seen" and "zero terms". + for (bcb, expression_id) in coverage_counters + .bcb_nodes_with_coverage_expressions() + .filter(|&(bcb, _)| bcb_has_coverage_spans(bcb)) + { + inject_statement( + mir_body, + CoverageKind::ExpressionUsed { id: expression_id }, + basic_coverage_blocks[bcb].leader_bb(), + ); } } +/// Given two basic blocks that have a control-flow edge between them, creates +/// and returns a new block that sits between those blocks. fn inject_edge_counter_basic_block( mir_body: &mut mir::Body<'_>, from_bb: BasicBlock, From 48f664b5027f5912edbbfc240f90ed439be73280 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 1 Feb 2024 16:49:23 -0800 Subject: [PATCH 025/101] Ignore test-panic-abort tests on Android Until #120567 is fixed. --- tests/ui/test-attrs/test-panic-abort-nocapture.rs | 1 + tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr | 4 ++-- tests/ui/test-attrs/test-panic-abort.rs | 1 + tests/ui/test-attrs/test-panic-abort.run.stdout | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index af530cc1a0b8f..c7415818e10f5 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -6,6 +6,7 @@ // exec-env:RUST_BACKTRACE=0 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// ignore-android #120567 // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support // ignore-sgx no subprocess support diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 6997833834df6..16001b3eecd4d 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:33:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:27:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 08e5242af66f9..d80e2435614dc 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -6,6 +6,7 @@ // exec-env:RUST_BACKTRACE=0 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// ignore-android #120567 // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support // ignore-sgx no subprocess support diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index 0e27f6fb655b0..f5d14e77da963 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -17,7 +17,7 @@ hello, world testing123 ---- it_fails stderr ---- testing321 -thread 'main' panicked at $DIR/test-panic-abort.rs:38:5: +thread 'main' panicked at $DIR/test-panic-abort.rs:39:5: assertion `left == right` failed left: 2 right: 5 From 0e16885abd6997897a28627d1ff514c106261a7f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jan 2024 21:48:54 +0000 Subject: [PATCH 026/101] Use deeply_normalize_with_skipped_universes in when processing type outlives --- compiler/rustc_trait_selection/src/regions.rs | 3 ++- .../traits/next-solver/normalize-region-obligations.rs | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index e8929f114e165..e5a7b27446b4a 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -24,12 +24,13 @@ impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { let ty = self.resolve_vars_if_possible(ty); if self.next_trait_solver() { - crate::solve::deeply_normalize( + crate::solve::deeply_normalize_with_skipped_universes( self.at( &ObligationCause::dummy_with_span(origin.span()), outlives_env.param_env, ), ty, + vec![None; ty.outer_exclusive_binder().as_usize()], ) .map_err(|_| ty) } else { diff --git a/tests/ui/traits/next-solver/normalize-region-obligations.rs b/tests/ui/traits/next-solver/normalize-region-obligations.rs index 13c86b630f60e..d189e4893a320 100644 --- a/tests/ui/traits/next-solver/normalize-region-obligations.rs +++ b/tests/ui/traits/next-solver/normalize-region-obligations.rs @@ -1,4 +1,4 @@ -// revisions: normalize_param_env normalize_obligation +// revisions: normalize_param_env normalize_obligation hrtb // check-pass // compile-flags: -Znext-solver @@ -7,16 +7,23 @@ trait Foo { type Gat<'a> where ::Assoc: 'a; #[cfg(normalize_obligation)] type Gat<'a> where Self: 'a; + #[cfg(hrtb)] + type Gat<'b> where for<'a> >::Assoc: 'b; } trait Mirror { type Assoc: ?Sized; } impl Mirror for T { type Assoc = T; } +trait MirrorRegion<'a> { type Assoc: ?Sized; } +impl<'a, T> MirrorRegion<'a> for T { type Assoc = T; } + impl Foo for T { #[cfg(normalize_param_env)] type Gat<'a> = i32 where T: 'a; #[cfg(normalize_obligation)] type Gat<'a> = i32 where ::Assoc: 'a; + #[cfg(hrtb)] + type Gat<'b> = i32 where Self: 'b; } fn main() {} From 7576b77e50f2f8a4f256876dd38563e5e5becdee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jan 2024 21:49:55 +0000 Subject: [PATCH 027/101] Do process_registered_region_obligations in a loop --- .../src/infer/outlives/obligations.rs | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index b10bf98e8b50a..cf68a60e280d1 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -153,22 +153,28 @@ impl<'tcx> InferCtxt<'tcx> { .try_collect() .map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?; - let my_region_obligations = self.take_registered_region_obligations(); - - for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { - let sup_type = - deeply_normalize_ty(sup_type, origin.clone()).map_err(|e| (e, origin.clone()))?; - debug!(?sup_type, ?sub_region, ?origin); - - let outlives = &mut TypeOutlives::new( - self, - self.tcx, - outlives_env.region_bound_pairs(), - None, - &normalized_caller_bounds, - ); - let category = origin.to_constraint_category(); - outlives.type_must_outlive(origin, sup_type, sub_region, category); + // Must loop since the process of normalizing may itself register region obligations. + loop { + let my_region_obligations = self.take_registered_region_obligations(); + if my_region_obligations.is_empty() { + break; + } + + for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { + let sup_type = deeply_normalize_ty(sup_type, origin.clone()) + .map_err(|e| (e, origin.clone()))?; + debug!(?sup_type, ?sub_region, ?origin); + + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + outlives_env.region_bound_pairs(), + None, + &normalized_caller_bounds, + ); + let category = origin.to_constraint_category(); + outlives.type_must_outlive(origin, sup_type, sub_region, category); + } } Ok(()) From 7d1fda7b40b580e5d8c7de1e3bfef7e35e997cee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jan 2024 21:50:05 +0000 Subject: [PATCH 028/101] Normalize type outlives obligations in NLL --- .../src/type_check/constraint_conversion.rs | 97 +++++++++++++++---- .../src/type_check/free_region_relations.rs | 72 +++++++++----- compiler/rustc_borrowck/src/type_check/mod.rs | 6 +- .../normalize-type-outlives-in-param-env.rs | 18 ++++ .../next-solver/normalize-type-outlives.rs | 13 +++ 5 files changed, 156 insertions(+), 50 deletions(-) create mode 100644 tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs create mode 100644 tests/ui/traits/next-solver/normalize-type-outlives.rs diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 52559f9039b65..71035eea5d175 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -5,10 +5,15 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::solve::deeply_normalize; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; +use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use crate::{ constraints::OutlivesConstraint, @@ -33,6 +38,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { /// our special inference variable there, we would mess that up. region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, + param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, @@ -47,6 +53,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, + param_env: ty::ParamEnv<'tcx>, known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, @@ -59,6 +66,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { universal_regions, region_bound_pairs, implicit_region_bound, + param_env, known_type_outlives_obligations, locations, span, @@ -137,36 +145,83 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // Extract out various useful fields we'll need below. let ConstraintConversion { tcx, + infcx, + param_env, region_bound_pairs, implicit_region_bound, known_type_outlives_obligations, .. } = *self; - let ty::OutlivesPredicate(k1, r2) = predicate; - match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - let r1_vid = self.to_region_vid(r1); - let r2_vid = self.to_region_vid(r2); - self.add_outlives(r1_vid, r2_vid, constraint_category); - } + let mut outlives_predicates = vec![(predicate, constraint_category)]; + while let Some((ty::OutlivesPredicate(k1, r2), constraint_category)) = + outlives_predicates.pop() + { + match k1.unpack() { + GenericArgKind::Lifetime(r1) => { + let r1_vid = self.to_region_vid(r1); + let r2_vid = self.to_region_vid(r2); + self.add_outlives(r1_vid, r2_vid, constraint_category); + } - GenericArgKind::Type(t1) => { - // we don't actually use this for anything, but - // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + GenericArgKind::Type(mut t1) => { + // Normalize the type we receive from a `TypeOutlives` obligation + // in the new trait solver. + if infcx.next_trait_solver() { + let result = CustomTypeOp::new( + |ocx| { + match deeply_normalize( + ocx.infcx.at( + &ObligationCause::dummy_with_span(self.span), + param_env, + ), + t1, + ) { + Ok(normalized_ty) => { + t1 = normalized_ty; + } + Err(e) => { + infcx.err_ctxt().report_fulfillment_errors(e); + } + } - TypeOutlives::new( - &mut *self, - tcx, - region_bound_pairs, - Some(implicit_region_bound), - known_type_outlives_obligations, - ) - .type_must_outlive(origin, t1, r2, constraint_category); - } + Ok(()) + }, + "normalize type outlives obligation", + ) + .fully_perform(infcx, self.span); + + match result { + Ok(TypeOpOutput { output: (), constraints, .. }) => { + if let Some(constraints) = constraints { + assert!( + constraints.member_constraints.is_empty(), + "FIXME(-Znext-solver): How do I handle these?" + ); + outlives_predicates + .extend(constraints.outlives.iter().copied()); + } + } + Err(_) => {} + } + } - GenericArgKind::Const(_) => unreachable!(), + // we don't actually use this for anything, but + // the `TypeOutlives` code needs an origin. + let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + + TypeOutlives::new( + &mut *self, + tcx, + region_bound_pairs, + Some(implicit_region_bound), + known_type_outlives_obligations, + ) + .type_must_outlive(origin, t1, r2, constraint_category); + } + + GenericArgKind::Const(_) => unreachable!(), + } } } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index d518f54fd2533..4d53a53ee197b 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -8,8 +8,11 @@ use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; -use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; +use rustc_trait_selection::solve::deeply_normalize_with_skipped_universes; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use type_op::TypeOpOutput; @@ -52,7 +55,6 @@ pub(crate) struct CreateResult<'tcx> { pub(crate) fn create<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], implicit_region_bound: ty::Region<'tcx>, universal_regions: &Rc>, constraints: &mut MirTypeckRegionConstraints<'tcx>, @@ -60,7 +62,6 @@ pub(crate) fn create<'tcx>( UniversalRegionRelationsBuilder { infcx, param_env, - known_type_outlives_obligations, implicit_region_bound, constraints, universal_regions: universal_regions.clone(), @@ -178,7 +179,6 @@ impl UniversalRegionRelations<'_> { struct UniversalRegionRelationsBuilder<'this, 'tcx> { infcx: &'this InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], universal_regions: Rc>, implicit_region_bound: ty::Region<'tcx>, constraints: &'this mut MirTypeckRegionConstraints<'tcx>, @@ -222,6 +222,35 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.relate_universal_regions(fr, fr_fn_body); } + // Normalize the assumptions we use to borrowck the program. + let mut constraints = vec![]; + let mut known_type_outlives_obligations = vec![]; + for bound in param_env.caller_bounds() { + let Some(outlives) = bound.as_type_outlives_clause() else { continue }; + let ty::OutlivesPredicate(mut ty, region) = outlives.skip_binder(); + + // In the new solver, normalize the type-outlives obligation assumptions. + if self.infcx.next_trait_solver() { + match deeply_normalize_with_skipped_universes( + self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) { + Ok(normalized_ty) => { + ty = normalized_ty; + } + Err(e) => { + self.infcx.err_ctxt().report_fulfillment_errors(e); + } + } + } + + known_type_outlives_obligations + .push(outlives.rebind(ty::OutlivesPredicate(ty, region))); + } + let known_type_outlives_obligations = + self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); + let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys @@ -239,7 +268,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // the `relations` is built. let mut normalized_inputs_and_output = Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); - let mut constraints = vec![]; for ty in unnormalized_input_output_tys { debug!("build: input_or_output={:?}", ty); // We add implied bounds from both the unnormalized and normalized ty. @@ -304,7 +332,19 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } for c in constraints { - self.push_region_constraints(c, span); + constraint_conversion::ConstraintConversion::new( + self.infcx, + &self.universal_regions, + &self.region_bound_pairs, + self.implicit_region_bound, + param_env, + known_type_outlives_obligations, + Locations::All(span), + span, + ConstraintCategory::Internal, + self.constraints, + ) + .convert_all(c); } CreateResult { @@ -313,30 +353,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { outlives: self.outlives.freeze(), inverse_outlives: self.inverse_outlives.freeze(), }), - known_type_outlives_obligations: self.known_type_outlives_obligations, + known_type_outlives_obligations, region_bound_pairs: self.region_bound_pairs, normalized_inputs_and_output, } } - #[instrument(skip(self, data), level = "debug")] - fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) { - debug!("constraints generated: {:#?}", data); - - constraint_conversion::ConstraintConversion::new( - self.infcx, - &self.universal_regions, - &self.region_bound_pairs, - self.implicit_region_bound, - self.known_type_outlives_obligations, - Locations::All(span), - span, - ConstraintCategory::Internal, - self.constraints, - ) - .convert_all(data); - } - /// Update the type of a single local, which should represent /// either the return type of the MIR or one of its arguments. At /// the same time, compute and add any implied bounds that come diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 59c4d9a6c78ca..c65173baea57f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -156,10 +156,6 @@ pub(crate) fn type_check<'mir, 'tcx>( } = free_region_relations::create( infcx, param_env, - // FIXME(-Znext-solver): These are unnormalized. Normalize them. - infcx.tcx.arena.alloc_from_iter( - param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()), - ), implicit_region_bound, universal_regions, &mut constraints, @@ -1136,6 +1132,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.borrowck_context.universal_regions, self.region_bound_pairs, self.implicit_region_bound, + self.param_env, self.known_type_outlives_obligations, locations, locations.span(self.body), @@ -2740,6 +2737,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.borrowck_context.universal_regions, self.region_bound_pairs, self.implicit_region_bound, + self.param_env, self.known_type_outlives_obligations, locations, DUMMY_SP, // irrelevant; will be overridden. diff --git a/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs new file mode 100644 index 0000000000000..7477c56cd5487 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: -Znext-solver + +trait Mirror { + type Assoc; +} + +impl Mirror for T { + type Assoc = T; +} + +fn is_static() {} + +fn test() where ::Assoc: 'static { + is_static::(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-type-outlives.rs b/tests/ui/traits/next-solver/normalize-type-outlives.rs new file mode 100644 index 0000000000000..f50eb6326e239 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-type-outlives.rs @@ -0,0 +1,13 @@ +// check-pass + +trait Tr<'a> { + type Assoc; +} + +fn outlives<'o, T: 'o>() {} + +fn foo<'a, 'b, T: Tr<'a, Assoc = ()>>() { + outlives::<'b, T::Assoc>(); +} + +fn main() {} From a371059933c11c79f9583ec149d56774e87b940f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 1 Feb 2024 18:04:16 +0000 Subject: [PATCH 029/101] Don't hang when there's an infinite loop of outlives obligations --- .../src/type_check/constraint_conversion.rs | 133 ++++++++++-------- .../src/infer/outlives/obligations.rs | 8 +- 2 files changed, 83 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 71035eea5d175..4c224248945b3 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -154,74 +154,93 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } = *self; let mut outlives_predicates = vec![(predicate, constraint_category)]; - while let Some((ty::OutlivesPredicate(k1, r2), constraint_category)) = - outlives_predicates.pop() - { - match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - let r1_vid = self.to_region_vid(r1); - let r2_vid = self.to_region_vid(r2); - self.add_outlives(r1_vid, r2_vid, constraint_category); - } + for iteration in 0.. { + if outlives_predicates.is_empty() { + break; + } - GenericArgKind::Type(mut t1) => { - // Normalize the type we receive from a `TypeOutlives` obligation - // in the new trait solver. - if infcx.next_trait_solver() { - let result = CustomTypeOp::new( - |ocx| { - match deeply_normalize( - ocx.infcx.at( - &ObligationCause::dummy_with_span(self.span), - param_env, - ), - t1, - ) { - Ok(normalized_ty) => { - t1 = normalized_ty; - } - Err(e) => { - infcx.err_ctxt().report_fulfillment_errors(e); + if !self.tcx.recursion_limit().value_within_limit(iteration) { + bug!( + "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}" + ); + } + + let mut next_outlives_predicates = vec![]; + for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates { + match k1.unpack() { + GenericArgKind::Lifetime(r1) => { + let r1_vid = self.to_region_vid(r1); + let r2_vid = self.to_region_vid(r2); + self.add_outlives(r1_vid, r2_vid, constraint_category); + } + + GenericArgKind::Type(mut t1) => { + // Normalize the type we receive from a `TypeOutlives` obligation + // in the new trait solver. + if infcx.next_trait_solver() { + let result = CustomTypeOp::new( + |ocx| { + match deeply_normalize( + ocx.infcx.at( + &ObligationCause::dummy_with_span(self.span), + param_env, + ), + t1, + ) { + Ok(normalized_ty) => { + t1 = normalized_ty; + } + Err(e) => { + infcx.err_ctxt().report_fulfillment_errors(e); + } } - } - Ok(()) - }, - "normalize type outlives obligation", - ) - .fully_perform(infcx, self.span); + Ok(()) + }, + "normalize type outlives obligation", + ) + .fully_perform(infcx, self.span); - match result { - Ok(TypeOpOutput { output: (), constraints, .. }) => { - if let Some(constraints) = constraints { - assert!( - constraints.member_constraints.is_empty(), - "FIXME(-Znext-solver): How do I handle these?" - ); - outlives_predicates - .extend(constraints.outlives.iter().copied()); + match result { + Ok(TypeOpOutput { output: (), constraints, .. }) => { + if let Some(constraints) = constraints { + assert!( + constraints.member_constraints.is_empty(), + "no member constraints expected from normalizing: {:#?}", + constraints.member_constraints + ); + next_outlives_predicates + .extend(constraints.outlives.iter().copied()); + } } + Err(_) => {} } - Err(_) => {} } - } - // we don't actually use this for anything, but - // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + // we don't actually use this for anything, but + // the `TypeOutlives` code needs an origin. + let origin = infer::RelateParamBound(DUMMY_SP, t1, None); - TypeOutlives::new( - &mut *self, - tcx, - region_bound_pairs, - Some(implicit_region_bound), - known_type_outlives_obligations, - ) - .type_must_outlive(origin, t1, r2, constraint_category); - } + TypeOutlives::new( + &mut *self, + tcx, + region_bound_pairs, + Some(implicit_region_bound), + known_type_outlives_obligations, + ) + .type_must_outlive( + origin, + t1, + r2, + constraint_category, + ); + } - GenericArgKind::Const(_) => unreachable!(), + GenericArgKind::Const(_) => unreachable!(), + } } + + outlives_predicates = next_outlives_predicates; } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index cf68a60e280d1..c36d8556d17dd 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -154,12 +154,18 @@ impl<'tcx> InferCtxt<'tcx> { .map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?; // Must loop since the process of normalizing may itself register region obligations. - loop { + for iteration in 0.. { let my_region_obligations = self.take_registered_region_obligations(); if my_region_obligations.is_empty() { break; } + if !self.tcx.recursion_limit().value_within_limit(iteration) { + bug!( + "FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}" + ); + } + for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { let sup_type = deeply_normalize_ty(sup_type, origin.clone()) .map_err(|e| (e, origin.clone()))?; From e951bcff96ac606aad3b7870c7fa64a4a48aa04b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Feb 2024 18:31:35 +0000 Subject: [PATCH 030/101] Normalize the whole PolyTypeOutlivesPredicate, more simplifications --- .../src/type_check/constraint_conversion.rs | 84 +++++++++---------- .../src/type_check/free_region_relations.rs | 17 ++-- .../src/infer/error_reporting/mod.rs | 7 +- .../src/infer/lexical_region_resolve/mod.rs | 2 +- .../rustc_infer/src/infer/outlives/mod.rs | 13 +-- .../src/infer/outlives/obligations.rs | 38 +++++---- compiler/rustc_trait_selection/src/regions.rs | 6 +- .../src/traits/auto_trait.rs | 2 +- .../next-solver/specialization-transmute.rs | 2 +- .../specialization-transmute.stderr | 2 +- 10 files changed, 92 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 4c224248945b3..c97e31701669c 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -5,13 +5,11 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; +use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::GenericArgKind; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::solve::deeply_normalize; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -146,7 +144,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let ConstraintConversion { tcx, infcx, - param_env, region_bound_pairs, implicit_region_bound, known_type_outlives_obligations, @@ -178,43 +175,10 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // Normalize the type we receive from a `TypeOutlives` obligation // in the new trait solver. if infcx.next_trait_solver() { - let result = CustomTypeOp::new( - |ocx| { - match deeply_normalize( - ocx.infcx.at( - &ObligationCause::dummy_with_span(self.span), - param_env, - ), - t1, - ) { - Ok(normalized_ty) => { - t1 = normalized_ty; - } - Err(e) => { - infcx.err_ctxt().report_fulfillment_errors(e); - } - } - - Ok(()) - }, - "normalize type outlives obligation", - ) - .fully_perform(infcx, self.span); - - match result { - Ok(TypeOpOutput { output: (), constraints, .. }) => { - if let Some(constraints) = constraints { - assert!( - constraints.member_constraints.is_empty(), - "no member constraints expected from normalizing: {:#?}", - constraints.member_constraints - ); - next_outlives_predicates - .extend(constraints.outlives.iter().copied()); - } - } - Err(_) => {} - } + t1 = self.normalize_and_add_type_outlives_constraints( + t1, + &mut next_outlives_predicates, + ); } // we don't actually use this for anything, but @@ -306,6 +270,42 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { debug!("add_type_test(type_test={:?})", type_test); self.constraints.type_tests.push(type_test); } + + fn normalize_and_add_type_outlives_constraints( + &self, + ty: Ty<'tcx>, + next_outlives_predicates: &mut Vec<( + ty::OutlivesPredicate, ty::Region<'tcx>>, + ConstraintCategory<'tcx>, + )>, + ) -> Ty<'tcx> { + let result = CustomTypeOp::new( + |ocx| { + deeply_normalize( + ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), + ty, + ) + .map_err(|_| NoSolution) + }, + "normalize type outlives obligation", + ) + .fully_perform(self.infcx, self.span); + + match result { + Ok(TypeOpOutput { output: ty, constraints, .. }) => { + if let Some(constraints) = constraints { + assert!( + constraints.member_constraints.is_empty(), + "no member constraints expected from normalizing: {:#?}", + constraints.member_constraints + ); + next_outlives_predicates.extend(constraints.outlives.iter().copied()); + } + ty + } + Err(_) => ty, + } + } } impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 4d53a53ee197b..2e0caf4481902 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -11,7 +11,7 @@ use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; -use rustc_trait_selection::solve::deeply_normalize_with_skipped_universes; +use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; @@ -226,18 +226,16 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let mut constraints = vec![]; let mut known_type_outlives_obligations = vec![]; for bound in param_env.caller_bounds() { - let Some(outlives) = bound.as_type_outlives_clause() else { continue }; - let ty::OutlivesPredicate(mut ty, region) = outlives.skip_binder(); + let Some(mut outlives) = bound.as_type_outlives_clause() else { continue }; // In the new solver, normalize the type-outlives obligation assumptions. if self.infcx.next_trait_solver() { - match deeply_normalize_with_skipped_universes( + match deeply_normalize( self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), - ty, - vec![None; ty.outer_exclusive_binder().as_usize()], + outlives, ) { - Ok(normalized_ty) => { - ty = normalized_ty; + Ok(normalized_outlives) => { + outlives = normalized_outlives; } Err(e) => { self.infcx.err_ctxt().report_fulfillment_errors(e); @@ -245,8 +243,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } } - known_type_outlives_obligations - .push(outlives.rebind(ty::OutlivesPredicate(ty, region))); + known_type_outlives_obligations.push(outlives); } let known_type_outlives_obligations = self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b8344310d5dfd..f74e13db44795 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -519,10 +520,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } - RegionResolutionError::CannotNormalize(ty, origin) => { + RegionResolutionError::CannotNormalize(clause, origin) => { + let clause: ty::Clause<'tcx> = + clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx); self.tcx .dcx() - .struct_span_err(origin.span(), format!("cannot normalize `{ty}`")) + .struct_span_err(origin.span(), format!("cannot normalize `{clause}`")) .emit(); } } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 4a1169e68e087..6137506d4a994 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -99,7 +99,7 @@ pub enum RegionResolutionError<'tcx> { Region<'tcx>, // the placeholder `'b` ), - CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>), + CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>), } impl<'tcx> RegionResolutionError<'tcx> { diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 926e198b21915..a4f9316b5020f 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -4,8 +4,8 @@ use super::region_constraints::RegionConstraintData; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; -use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::traits::query::{NoSolution, OutlivesBound}; +use rustc_middle::ty; pub mod components; pub mod env; @@ -49,12 +49,15 @@ impl<'tcx> InferCtxt<'tcx> { pub fn resolve_regions_with_normalize( &self, outlives_env: &OutlivesEnvironment<'tcx>, - deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result, Ty<'tcx>>, + deeply_normalize_ty: impl Fn( + ty::PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) -> Result, NoSolution>, ) -> Vec> { match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) { Ok(()) => {} - Err((ty, origin)) => { - return vec![RegionResolutionError::CannotNormalize(ty, origin)]; + Err((clause, origin)) => { + return vec![RegionResolutionError::CannotNormalize(clause, origin)]; } }; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index c36d8556d17dd..7208f17fb340f 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -68,8 +68,9 @@ use crate::infer::{ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::GenericArgKind; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; use rustc_span::DUMMY_SP; use smallvec::smallvec; @@ -125,11 +126,15 @@ impl<'tcx> InferCtxt<'tcx> { /// invoked after all type-inference variables have been bound -- /// right before lexical region resolution. #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))] - pub fn process_registered_region_obligations( + pub fn process_registered_region_obligations( &self, outlives_env: &OutlivesEnvironment<'tcx>, - mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result, E>, - ) -> Result<(), (E, SubregionOrigin<'tcx>)> { + mut deeply_normalize_ty: impl FnMut( + PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) + -> Result, NoSolution>, + ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> { assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); let normalized_caller_bounds: Vec<_> = outlives_env @@ -137,21 +142,19 @@ impl<'tcx> InferCtxt<'tcx> { .caller_bounds() .iter() .filter_map(|clause| { - let bound_clause = clause.kind(); - let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else { - return None; - }; + let outlives = clause.as_type_outlives_clause()?; Some( deeply_normalize_ty( - outlives.0, + outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP), ) - .map(|ty| bound_clause.rebind(ty::OutlivesPredicate(ty, outlives.1))), + // FIXME(-Znext-solver): How do we accurately report an error span here :( + .map_err(|NoSolution| { + (outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)) + }), ) }) - // FIXME(-Znext-solver): How do we accurately report an error here :( - .try_collect() - .map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?; + .try_collect()?; // Must loop since the process of normalizing may itself register region obligations. for iteration in 0.. { @@ -167,8 +170,13 @@ impl<'tcx> InferCtxt<'tcx> { } for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { - let sup_type = deeply_normalize_ty(sup_type, origin.clone()) - .map_err(|e| (e, origin.clone()))?; + let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); + let ty::OutlivesPredicate(sup_type, sub_region) = + deeply_normalize_ty(outlives, origin.clone()) + .map_err(|NoSolution| (outlives, origin.clone()))? + .no_bound_vars() + .expect("started with no bound vars, should end with no bound vars"); + debug!(?sup_type, ?sub_region, ?origin); let outlives = &mut TypeOutlives::new( diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index e5a7b27446b4a..756db7cc2063f 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -1,5 +1,6 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionResolutionError}; +use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; pub trait InferCtxtRegionExt<'tcx> { @@ -24,15 +25,14 @@ impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { let ty = self.resolve_vars_if_possible(ty); if self.next_trait_solver() { - crate::solve::deeply_normalize_with_skipped_universes( + crate::solve::deeply_normalize( self.at( &ObligationCause::dummy_with_span(origin.span()), outlives_env.param_env, ), ty, - vec![None; ty.outer_exclusive_binder().as_usize()], ) - .map_err(|_| ty) + .map_err(|_| NoSolution) } else { Ok(ty) } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 7933654a91546..81c72fc4b7b03 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -179,7 +179,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } let outlives_env = OutlivesEnvironment::new(full_env); - let _ = infcx.process_registered_region_obligations::(&outlives_env, |ty, _| Ok(ty)); + let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty)); let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone(); diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs index e7de564877d09..a0855dd1e1714 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.rs +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -1,5 +1,5 @@ // compile-flags: -Znext-solver -//~^ ERROR cannot normalize `::Id` +//~^ ERROR cannot normalize `::Id: '_` #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index a1cf5b761e34f..3100a92e3eb4d 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -8,7 +8,7 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error: cannot normalize `::Id` +error: cannot normalize `::Id: '_` error[E0282]: type annotations needed --> $DIR/specialization-transmute.rs:14:23 From f5d6eb30a845109ab6f69855b4720a15573e8fad Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Jan 2024 22:03:16 +0300 Subject: [PATCH 031/101] hir: Stop keeping prefixes for most of `use` list stems And make sure all other imports have non-empty resolution lists. --- compiler/rustc_ast_lowering/src/item.rs | 19 +++++++++++++------ compiler/rustc_ast_lowering/src/lib.rs | 12 +++++++++--- compiler/rustc_ast_lowering/src/path.rs | 1 + 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index dd3f7289a60b2..60685119fb98e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -496,8 +496,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - let res = - self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect(); + let res = self.lower_import_res(id, path.span); let path = self.lower_use_path(res, &path, ParamMode::Explicit); hir::ItemKind::Use(path, hir::UseKind::Single) } @@ -533,7 +532,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // for that we return the `{}` import (called the // `ListStem`). - let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None }; + let span = prefix.span.to(path.span); + let prefix = Path { segments, span, tokens: None }; // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { @@ -567,9 +567,16 @@ impl<'hir> LoweringContext<'_, 'hir> { }); } - let res = - self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect(); - let path = self.lower_use_path(res, &prefix, ParamMode::Explicit); + let path = if trees.is_empty() && !prefix.segments.is_empty() { + // For empty lists we need to lower the prefix so it is checked for things + // like stability later. + let res = self.lower_import_res(id, span); + self.lower_use_path(res, &prefix, ParamMode::Explicit) + } else { + // For non-empty lists we can just drop all the data, the prefix is already + // present in HIR as a part of nested imports. + self.arena.alloc(hir::UsePath { res: smallvec![], segments: &[], span }) + }; hir::ItemKind::Use(path, hir::UseKind::ListStem) } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3621844efc8d2..14a83c7eda6db 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -63,7 +63,7 @@ use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{DesugaringKind, Span, DUMMY_SP}; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use thin_vec::ThinVec; @@ -749,8 +749,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res()) } - fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator> { - self.resolver.get_import_res(id).present_items() + fn lower_import_res(&mut self, id: NodeId, span: Span) -> SmallVec<[Res; 3]> { + let res = self.resolver.get_import_res(id).present_items(); + let res: SmallVec<_> = res.map(|res| self.lower_res(res)).collect(); + if res.is_empty() { + self.dcx().span_delayed_bug(span, "no resolution for an import"); + return smallvec![Res::Err]; + } + res } fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index c679ee56fcd8b..4df68f8e9297d 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -156,6 +156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &Path, param_mode: ParamMode, ) -> &'hir hir::UsePath<'hir> { + assert!((1..=3).contains(&res.len())); self.arena.alloc(hir::UsePath { res, segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| { From 17f0919e8acba48224558c7ebcfc06f14d30d235 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 3 Feb 2024 12:33:00 +0300 Subject: [PATCH 032/101] rustc_monomorphize: fix outdated comment in partition --- compiler/rustc_monomorphize/src/partitioning.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 7ff182381b835..032686101d968 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -156,7 +156,7 @@ where placed }; - // Merge until we have at most `max_cgu_count` codegen units. + // Merge until we don't exceed the max CGU count. // `merge_codegen_units` is responsible for updating the CGU size // estimates. { From 934618fe472727cf5e45535c945516c2c62dd75e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 3 Feb 2024 19:57:47 -0500 Subject: [PATCH 033/101] Emit a diagnostic for invalid target options --- compiler/rustc_codegen_llvm/messages.ftl | 2 ++ compiler/rustc_codegen_llvm/src/errors.rs | 6 ++++++ compiler/rustc_codegen_llvm/src/llvm_util.rs | 16 ++++++++-------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index d5bc04f594da1..d14fe0299e64c 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -28,6 +28,8 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two = codegen_llvm_invalid_minimum_alignment_too_large = invalid minimum global alignment: {$align} is too large +codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`" + codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}" codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index d82ff6656f4d3..43250d73b48fe 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -253,3 +253,9 @@ pub struct MismatchedDataLayout<'a> { pub llvm_target: &'a str, pub llvm_layout: &'a str, } + +#[derive(Diagnostic)] +#[diag(codegen_llvm_invalid_target_feature_prefix)] +pub(crate) struct InvalidTargetFeaturePrefix<'a> { + pub feature: &'a str, +} diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 99f4488ac0f97..4bb400b187989 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -1,7 +1,7 @@ use crate::back::write::create_informational_target_machine; use crate::errors::{ - PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, - UnknownCTargetFeaturePrefix, UnstableCTargetFeature, + InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable, + UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature, }; use crate::llvm; use libc::c_int; @@ -511,7 +511,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec Vec Vec Option<&str> { +fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> { // features must start with a `+` or `-`. - let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| { - bug!("target feature `{}` must begin with a `+` or `-`", s); - }); + let feature = s + .strip_prefix(&['+', '-'][..]) + .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s })); // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. if RUSTC_SPECIFIC_FEATURES.contains(&feature) { From a4cb55f2aca24f3cbf33b025c147d7a894bceefd Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Sat, 3 Feb 2024 10:37:28 -0800 Subject: [PATCH 034/101] For E0223, suggest methods that look similar to the path --- .../rustc_hir_analysis/src/astconv/mod.rs | 52 ++++++++++++++ tests/ui/suggestions/issue-109195.rs | 20 ++++++ tests/ui/suggestions/issue-109195.stderr | 69 +++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 tests/ui/suggestions/issue-109195.rs create mode 100644 tests/ui/suggestions/issue-109195.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 89f39897ea874..d69f366a66c95 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -29,6 +29,7 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; +use rustc_middle::query::Key; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty, TyCtxt, TypeVisitableExt, @@ -1373,6 +1374,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .emit() // Already reported in an earlier stage. } else { + // suggest methods that look similar to the path + // e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195) + for (_, node) in tcx.hir().parent_iter(qself.hir_id) { + if let hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::Path(hir::QPath::TypeRelative( + hir::Ty { + kind: + hir::TyKind::Path(hir::QPath::TypeRelative( + _, + hir::PathSegment { ident: ident2, .. }, + )), + .. + }, + hir::PathSegment { ident: ident3, .. }, + )), + .. + }) = node + { + let name = format!("{ident2}_{ident3}"); + if if let Some(ty_def_id) = qself_ty.ty_def_id() + && let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id) + && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx + .associated_items(inherent_impl) + .filter_by_name_unhygienic(Symbol::intern(&name)) + .next() + { + true + } else { + qself_ty.is_str() + && ["from_utf8", "from_utf8_mut"].contains(&name.as_str()) + } { + let reported = struct_span_code_err!( + tcx.dcx(), + span, + E0223, + "ambiguous associated type" + ) + .with_span_suggestion_verbose( + ident2.span.to(ident3.span), + format!("you might have meant to use `{name}`"), + name, + Applicability::MaybeIncorrect, + ) + .emit(); + self.set_tainted_by_errors(reported); + return Err(reported); + } + } + } + let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); diff --git a/tests/ui/suggestions/issue-109195.rs b/tests/ui/suggestions/issue-109195.rs new file mode 100644 index 0000000000000..badb859dbb701 --- /dev/null +++ b/tests/ui/suggestions/issue-109195.rs @@ -0,0 +1,20 @@ +fn main() { + String::from::utf8; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8` + String::from::utf8(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8` + String::from::utf16(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf16` + String::from::method_that_doesnt_exist(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `from` + str::from::utf8(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8` + str::from::utf8_mut(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8_mut` +} diff --git a/tests/ui/suggestions/issue-109195.stderr b/tests/ui/suggestions/issue-109195.stderr new file mode 100644 index 0000000000000..5c9ef9f98f513 --- /dev/null +++ b/tests/ui/suggestions/issue-109195.stderr @@ -0,0 +1,69 @@ +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:2:5 + | +LL | String::from::utf8; + | ^^^^^^^^^^^^ + | +help: you might have meant to use `from_utf8` + | +LL | String::from_utf8; + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:5:5 + | +LL | String::from::utf8(); + | ^^^^^^^^^^^^ + | +help: you might have meant to use `from_utf8` + | +LL | String::from_utf8(); + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:8:5 + | +LL | String::from::utf16(); + | ^^^^^^^^^^^^ + | +help: you might have meant to use `from_utf16` + | +LL | String::from_utf16(); + | ~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:11:5 + | +LL | String::from::method_that_doesnt_exist(); + | ^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path + | +LL | ::from::method_that_doesnt_exist(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:14:5 + | +LL | str::from::utf8(); + | ^^^^^^^^^ + | +help: you might have meant to use `from_utf8` + | +LL | str::from_utf8(); + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:17:5 + | +LL | str::from::utf8_mut(); + | ^^^^^^^^^ + | +help: you might have meant to use `from_utf8_mut` + | +LL | str::from_utf8_mut(); + | ~~~~~~~~~~~~~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0223`. From c9192be5611576ecb3200636711356061f804995 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 26 Jan 2024 23:21:21 +0800 Subject: [PATCH 035/101] Reconstify `Add` --- library/core/src/ops/arith.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index bb3cdde66d173..fd50f80474833 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -73,6 +73,7 @@ append_const_msg )] #[doc(alias = "+")] +#[const_trait] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -94,7 +95,8 @@ pub trait Add { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl Add for $t { + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + impl const Add for $t { type Output = $t; #[inline] From 96108c59812bd2a227d6098e0682b2f2811c36c0 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 28 Jan 2024 00:20:52 +0800 Subject: [PATCH 036/101] make effect infer variables suggestable in diagnostics it works when a non-const context that does not enable effects calls into a const effects-enabled trait. We'd simply suggest the non-const trait bound in this case consistent to its fallback. --- compiler/rustc_middle/src/ty/diagnostics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8678f388298c2..13cc5cbed443f 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -98,6 +98,7 @@ impl<'tcx, T> IsSuggestable<'tcx> for T where T: TypeVisitable> + TypeFoldable>, { + #[tracing::instrument(level = "debug", skip(tcx))] fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool { self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue() } @@ -533,6 +534,9 @@ impl<'tcx> TypeVisitor> for IsSuggestableVisitor<'tcx> { match c.kind() { ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {} + // effect variables are always suggestable, because they are not visible + ConstKind::Infer(InferConst::EffectVar(_)) => {} + ConstKind::Infer(..) | ConstKind::Bound(..) | ConstKind::Placeholder(..) From 74dbf3a070adac13f28f39e2d447b0148998cc40 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 28 Jan 2024 00:22:47 +0800 Subject: [PATCH 037/101] fix ui tests these ui changes are closer to what was there before const_trait_impl changes. --- tests/ui/suggestions/invalid-bin-op.stderr | 4 +++ tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr | 26 +++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/ui/suggestions/invalid-bin-op.stderr b/tests/ui/suggestions/invalid-bin-op.stderr index 2bd745c645a1c..018250c8c1b60 100644 --- a/tests/ui/suggestions/invalid-bin-op.stderr +++ b/tests/ui/suggestions/invalid-bin-op.stderr @@ -16,6 +16,10 @@ help: consider annotating `S` with `#[derive(PartialEq)]` LL + #[derive(PartialEq)] LL | struct S(T); | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub fn foo(s: S, t: S) where S: PartialEq { + | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index e90784a54ae0d..c1281ce6a422f 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -11,6 +11,19 @@ LL | >::add(1, 2); <&'a i32 as Add> <&i32 as Add<&i32>> +error[E0277]: cannot add `u32` to `i32` + --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 + | +LL | >::add(1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` + | + = help: the trait `Add` is not implemented for `i32` + = help: the following other types implement trait `Add`: + + > + <&'a i32 as Add> + <&i32 as Add<&i32>> + error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:7:28 | @@ -55,19 +68,6 @@ help: change the type of the numeric literal from `u32` to `i32` LL | >::add(1, 2i32); | ~~~ -error[E0277]: cannot add `u32` to `i32` - --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 - | -LL | >::add(1, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` - | - = help: the trait `Add` is not implemented for `i32` - = help: the following other types implement trait `Add`: - - > - <&'a i32 as Add> - <&i32 as Add<&i32>> - error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. From bae4f177b8767f6acab5474c6fec2734df759a32 Mon Sep 17 00:00:00 2001 From: Jarl Evanson Date: Sun, 4 Feb 2024 12:04:39 -0600 Subject: [PATCH 038/101] Enable `structs` SROA MIR-opt test --- tests/mir-opt/remove_storage_markers.rs | 2 +- tests/mir-opt/sroa/structs.rs | 125 ++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 7 deletions(-) diff --git a/tests/mir-opt/remove_storage_markers.rs b/tests/mir-opt/remove_storage_markers.rs index 74e399b6c0eed..27661ab325411 100644 --- a/tests/mir-opt/remove_storage_markers.rs +++ b/tests/mir-opt/remove_storage_markers.rs @@ -7,7 +7,7 @@ // EMIT_MIR remove_storage_markers.main.RemoveStorageMarkers.diff fn main() { - // CHECK-LABLE: fn main( + // CHECK-LABEL: fn main( // CHECK-NOT: StorageDead // CHECK-NOT: StorageLive diff --git a/tests/mir-opt/sroa/structs.rs b/tests/mir-opt/sroa/structs.rs index 73563e12c94fc..5ea3795b86e2d 100644 --- a/tests/mir-opt/sroa/structs.rs +++ b/tests/mir-opt/sroa/structs.rs @@ -1,4 +1,3 @@ -// skip-filecheck // unit-test: ScalarReplacementOfAggregates // compile-flags: -Cpanic=abort // no-prefer-dynamic @@ -13,28 +12,68 @@ impl Drop for Tag { fn drop(&mut self) {} } +/// Check that SROA excludes structs with a `Drop` implementation. pub fn dropping() { + // CHECK-LABEL: fn dropping( + + // CHECK: [[aggregate:_[0-9]+]]: S; + + // CHECK: bb0: { + // CHECK: [[aggregate]] = S S(Tag(0), Tag(1), Tag(2)).1; } +/// Check that SROA excludes enums. pub fn enums(a: usize) -> usize { + // CHECK-LABEL: fn enums( + + // CHECK: [[enum:_[0-9]+]]: std::option::Option; + + // CHECK: bb0: { + // CHECK: [[enum]] = Option::::Some + // CHECK: _5 = (([[enum]] as Some).0: usize) + // CHECK: _0 = _5 if let Some(a) = Some(a) { a } else { 0 } } +/// Check that SROA destructures `U`. pub fn structs(a: f32) -> f32 { + // CHECK-LABEL: fn structs( struct U { _foo: usize, a: f32, } - + // CHECK: [[ret:_0]]: f32; + // CHECK: [[struct:_[0-9]+]]: structs::U; + // CHECK: [[a_tmp:_[0-9]+]]: f32; + // CHECK: [[foo:_[0-9]+]]: usize; + // CHECK: [[a_ret:_[0-9]+]]: f32; + + // CHECK: bb0: { + // CHECK-NOT: [[struct]] + // CHECK: [[a_tmp]] = _1; + // CHECK-NOT: [[struct]] + // CHECK: [[foo]] = const 0_usize; + // CHECK-NOT: [[struct]] + // CHECK: [[a_ret]] = move [[a_tmp]]; + // CHECK-NOT: [[struct]] + // CHECK: _0 = [[a_ret]]; + // CHECK-NOT: [[struct]] U { _foo: 0, a }.a } +/// Check that SROA excludes unions. pub fn unions(a: f32) -> u32 { + // CHECK-LABEL: fn unions( union Repr { f: f32, u: u32, } + // CHECK: [[union:_[0-9]+]]: unions::Repr; + + // CHECK: bb0: { + // CHECK: [[union]] = Repr { + // CHECK: _0 = ([[union]].1: u32) unsafe { Repr { f: a }.u } } @@ -46,11 +85,21 @@ struct Foo { d: Option, } -fn g() -> u32 { - 3 -} - +/// Check that non-escaping uses of a struct are destructured. pub fn flat() { + // CHECK-LABEL: fn flat( + + // CHECK: [[struct:_[0-9]+]]: Foo; + + // CHECK: bb0: { + // CHECK: [[init_unit:_[0-9]+]] = (); + // CHECK: [[init_opt_isize:_[0-9]+]] = Option::::Some + + // CHECK: [[destr_five:_[0-9]+]] = const 5_u8; + // CHECK: [[destr_unit:_[0-9]+]] = move [[init_unit]]; + // CHECK: [[destr_a:_[0-9]+]] = const "a"; + // CHECK: [[destr_opt_isize:_[0-9]+]] = move [[init_opt_isize]]; + let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) }; let _ = a; let _ = b; @@ -65,6 +114,10 @@ struct Escaping { c: u32, } +fn g() -> u32 { + 3 +} + fn f(a: *const u32) { println!("{}", unsafe { *a.add(2) }); } @@ -76,10 +129,38 @@ fn f(a: *const u32) { // of them to `f`. However, this would lead to a miscompilation because `b` and `c` // might no longer appear right after `a` in memory. pub fn escaping() { + // CHECK-LABEL: fn escaping( + + // CHECK: [[ptr:_[0-9]+]]: *const u32; + // CHECK: [[ref:_[0-9]+]]: &u32; + // CHECK: [[struct:_[0-9]+]]: Escaping; + // CHECK: [[a:_[0-9]+]]: u32; + + // CHECK: bb0: { + // CHECK: [[struct]] = Escaping { + // CHECK: [[ref]] = &([[struct]].0 + // CHECK: [[ptr]] = &raw const (*[[ref]]); f(&Escaping { a: 1, b: 2, c: g() }.a); } +/// Check that copies from an internal struct are destructured and reassigned to +/// the original struct. fn copies(x: Foo) { + // CHECK-LABEL: fn copies( + + // CHECK: [[external:_[0-9]+]]: Foo) -> + // CHECK: [[internal:_[0-9]+]]: Foo; + // CHECK: [[byte:_[0-9]+]]: u8; + // CHECK: [[unit:_[0-9]+]]: (); + // CHECK: [[str:_[0-9]+]]: &str; + // CHECK: [[opt_isize:_[0-9]+]]: std::option::Option; + + // CHECK: bb0: { + // CHECK: [[byte]] = ([[external]].0 + // CHECK: [[unit]] = ([[external]].1 + // CHECK: [[str]] = ([[external]].2 + // CHECK: [[opt_isize]] = ([[external]].3 + let y = x; let t = y.a; let u = y.c; @@ -87,13 +168,44 @@ fn copies(x: Foo) { let a = z.b; } +/// Check that copies from an internal struct are destructured and reassigned to +/// the original struct. fn ref_copies(x: &Foo) { + // CHECK-LABEL: fn ref_copies( + + // CHECK: [[external:_[0-9]+]]: &Foo) -> + // CHECK: [[internal:_[0-9]+]]: Foo; + // CHECK: [[byte:_[0-9]+]]: u8; + // CHECK: [[unit:_[0-9]+]]: (); + // CHECK: [[str:_[0-9]+]]: &str; + // CHECK: [[opt_isize:_[0-9]+]]: std::option::Option; + + // CHECK: bb0: { + // CHECK: [[byte]] = ((*[[external]]).0 + // CHECK: [[unit]] = ((*[[external]]).1 + // CHECK: [[str]] = ((*[[external]]).2 + // CHECK: [[opt_isize]] = ((*[[external]]).3 + let y = *x; let t = y.a; let u = y.c; } +/// Check that deaggregated assignments from constants are placed after the constant's +/// assignment. Also check that copying field accesses from the copy of the constant are +/// reassigned to copy from the constant. fn constant() { + // CHECK-LABEL: constant( + + // CHECK: [[constant:_[0-9]+]]: (usize, u8); + // CHECK: [[t:_[0-9]+]]: usize; + // CHECK: [[u:_[0-9]+]]: u8; + + // CHECK: bb0: { + // CHECK-NOT: [[constant]] + // CHECK: [[constant]] = const + // CHECK: [[t]] = move ([[constant]].0: usize) + // CHECK: [[u]] = move ([[constant]].1: u8) const U: (usize, u8) = (5, 9); let y = U; let t = y.0; @@ -101,6 +213,7 @@ fn constant() { } fn main() { + // CHECK-LABEL: fn main( dropping(); enums(5); structs(5.); From f47cb984b6266555a17c91f727f44a76f60fa17c Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 30 Jan 2024 14:19:07 -0500 Subject: [PATCH 039/101] Re-enable M1 runners on GitHub Actions This reverts commit 0f9844d10cc8210f1c0ef784ef8d67a1e073c3c1. --- .github/workflows/ci.yml | 20 ++++++++++++++++---- src/ci/github-actions/ci.yml | 36 ++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02a2193ad883f..1f7776be6c4ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -364,8 +364,8 @@ jobs: os: macos-13 - name: dist-aarch64-apple env: - SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc" + SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin" + RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_13.4.1.app USE_XCODE_CLANG: 1 @@ -375,8 +375,20 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - JEMALLOC_SYS_WITH_LG_PAGE: 14 - os: macos-13 + os: macos-13-xlarge + - name: aarch64-apple + env: + SCRIPT: "./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin" + RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_13.4.1.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + os: macos-13-xlarge - name: x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 61e0e2c0bc7f5..7ebf65a3184a3 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -555,16 +555,14 @@ jobs: # This target only needs to support 11.0 and up as nothing else supports the hardware - name: dist-aarch64-apple env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --stage 2 + SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin RUST_CONFIGURE_ARGS: >- - --build=x86_64-apple-darwin - --host=aarch64-apple-darwin - --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler - --disable-docs --set rust.jemalloc + --set llvm.ninja=false + --set rust.lto=thin RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_13.4.1.app USE_XCODE_CLANG: 1 @@ -574,15 +572,25 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - # Corresponds to 16K page size - # - # Shouldn't be needed if jemalloc-sys is updated to - # handle this platform like iOS or if we build on - # aarch64-apple-darwin itself. - # - # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237 - JEMALLOC_SYS_WITH_LG_PAGE: 14 - <<: *job-macos-xl + <<: *job-macos-m1 + + # This target only needs to support 11.0 and up as nothing else supports the hardware + - name: aarch64-apple + env: + SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_13.4.1.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-m1 ###################### # Windows Builders # From c2573c7574027bf9c939fd7eda6ea3815df23e62 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 30 Jan 2024 14:24:32 -0500 Subject: [PATCH 040/101] Use new publicly-available M1 runners https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/ --- .github/workflows/ci.yml | 4 ++-- src/ci/github-actions/ci.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f7776be6c4ce..26e589c092eda 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -375,7 +375,7 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-13-xlarge + os: macos-14 - name: aarch64-apple env: SCRIPT: "./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin" @@ -388,7 +388,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-13-xlarge + os: macos-14 - name: x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 7ebf65a3184a3..43e48c01176f3 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -93,7 +93,7 @@ x--expand-yaml-anchors--remove: <<: *base-job - &job-macos-m1 - os: macos-13-xlarge + os: macos-14 <<: *base-job - &job-windows-8c From 285d8c225d05966040f6a69bfdea83165b54483f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 3 Feb 2024 01:32:01 +0100 Subject: [PATCH 041/101] Suggest `[tail @ ..]` on `[..tail]` and `[...tail]` where `tail` is unresolved --- compiler/rustc_resolve/messages.ftl | 3 + compiler/rustc_resolve/src/errors.rs | 14 +++++ .../rustc_resolve/src/late/diagnostics.rs | 38 +++++++----- ...-pattern-meant-to-be-slice-rest-pattern.rs | 16 ++++- ...tern-meant-to-be-slice-rest-pattern.stderr | 61 +++++++++++++++++-- 5 files changed, 112 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 02847a0f5f914..769c469a5ab2b 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -292,6 +292,9 @@ resolve_underscore_lifetime_name_cannot_be_used_here = resolve_unexpected_res_change_ty_to_const_param_sugg = you might have meant to write a const parameter here +resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg = + if you meant to collect the rest of the slice in `{$ident}`, use the at operator + resolve_unreachable_label = use of unreachable label `{$name}` .label = unreachable label `{$name}` diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 655fc9812d747..49a0e597dbc75 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -800,3 +800,17 @@ pub(crate) struct UnexpectedResChangeTyToConstParamSugg { #[applicability] pub applicability: Applicability, } + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg, + code = "{snippet}", + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct UnexpectedResUseAtOpInSlicePatWithRangeSugg { + #[primary_span] + pub span: Span, + pub ident: Ident, + pub snippet: String, +} diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 310c126213ad2..5d712461993d8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1077,24 +1077,34 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err: &mut Diagnostic, path: &[Segment], ) { - if let Some(pat) = self.diagnostic_metadata.current_pat - && let ast::PatKind::Range(Some(start), None, range) = &pat.kind - && let ExprKind::Path(None, range_path) = &start.kind + let Some(pat) = self.diagnostic_metadata.current_pat else { return }; + let (bound, side, range) = match &pat.kind { + ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range), + ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range), + _ => return, + }; + if let ExprKind::Path(None, range_path) = &bound.kind && let [segment] = &range_path.segments[..] && let [s] = path && segment.ident == s.ident + && segment.ident.span.eq_ctxt(range.span) { - // We've encountered `[first, rest..]` where the user might have meant - // `[first, rest @ ..]` (#88404). - err.span_suggestion_verbose( - segment.ident.span.between(range.span), - format!( - "if you meant to collect the rest of the slice in `{}`, use the at operator", - segment.ident, - ), - " @ ", - Applicability::MaybeIncorrect, - ); + // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591) + // where the user might have meant `[first, rest @ ..]`. + let (span, snippet) = match side { + Side::Start => (segment.ident.span.between(range.span), " @ ".into()), + Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)), + }; + err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg { + span, + ident: segment.ident, + snippet, + }); + } + + enum Side { + Start, + End, } } diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs index a619fcafc8614..1eba7aeb4d64a 100644 --- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs +++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs @@ -1,9 +1,23 @@ fn main() { match &[1, 2, 3][..] { - [1, rest..] => println!("{rest:?}"), + [1, rest..] => println!("{rest}"), //~^ ERROR cannot find value `rest` in this scope //~| ERROR cannot find value `rest` in this scope //~| ERROR `X..` patterns in slices are experimental _ => {} } + match &[4, 5, 6][..] { + [] => {} + [_, ..tail] => println!("{tail}"), + //~^ ERROR cannot find value `tail` in this scope + //~| ERROR cannot find value `tail` in this scope + //~| ERROR exclusive range pattern syntax is experimental + } + match &[7, 8, 9][..] { + [] => {} + [_, ...tail] => println!("{tail}"), + //~^ ERROR cannot find value `tail` in this scope + //~| ERROR cannot find value `tail` in this scope + //~| ERROR range-to patterns with `...` are not allowed + } } diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr index c3c9131b63eb2..3a19517c85bd2 100644 --- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr +++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr @@ -1,31 +1,82 @@ +error: range-to patterns with `...` are not allowed + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:13 + | +LL | [_, ...tail] => println!("{tail}"), + | ^^^ help: use `..=` instead + error[E0425]: cannot find value `rest` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13 | -LL | [1, rest..] => println!("{rest:?}"), +LL | [1, rest..] => println!("{rest}"), | ^^^^ not found in this scope | help: if you meant to collect the rest of the slice in `rest`, use the at operator | -LL | [1, rest @ ..] => println!("{rest:?}"), +LL | [1, rest @ ..] => println!("{rest}"), | + error[E0425]: cannot find value `rest` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35 | -LL | [1, rest..] => println!("{rest:?}"), +LL | [1, rest..] => println!("{rest}"), + | ^^^^ not found in this scope + +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:15 + | +LL | [_, ..tail] => println!("{tail}"), + | ^^^^ not found in this scope + | +help: if you meant to collect the rest of the slice in `tail`, use the at operator + | +LL | [_, tail @ ..] => println!("{tail}"), + | ~~~~~~~~~ + +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:35 + | +LL | [_, ..tail] => println!("{tail}"), | ^^^^ not found in this scope +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:16 + | +LL | [_, ...tail] => println!("{tail}"), + | ^^^^ not found in this scope + | +help: if you meant to collect the rest of the slice in `tail`, use the at operator + | +LL | [_, tail @ ..] => println!("{tail}"), + | ~~~~~~~~~ + +error[E0425]: cannot find value `tail` in this scope + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:36 + | +LL | [_, ...tail] => println!("{tail}"), + | ^^^^ not found in this scope + error[E0658]: `X..` patterns in slices are experimental --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13 | -LL | [1, rest..] => println!("{rest:?}"), +LL | [1, rest..] => println!("{rest}"), | ^^^^^^ | = note: see issue #67264 for more information = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:13 + | +LL | [_, ..tail] => println!("{tail}"), + | ^^^^^^ + | + = note: see issue #37854 for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0425, E0658. For more information about an error, try `rustc --explain E0425`. From e8c3cbf44b9f003482871e8638859c8f65b234bb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Jan 2024 09:25:42 +1100 Subject: [PATCH 042/101] Make `Diagnostic::is_error` return false for `Level::FailureNote`. It doesn't affect behaviour, but makes sense with (a) `FailureNote` having `()` as its emission guarantee, and (b) in `Level` the `is_error` levels now are all listed before the non-`is_error` levels. --- compiler/rustc_errors/src/diagnostic.rs | 4 ++-- compiler/rustc_errors/src/lib.rs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 8ad4925cff288..09570fe74b6ff 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -238,8 +238,7 @@ impl Diagnostic { Level::Bug | Level::DelayedBug(DelayedBugKind::Normal) | Level::Fatal - | Level::Error - | Level::FailureNote => true, + | Level::Error => true, Level::ForceWarning(_) | Level::Warning @@ -248,6 +247,7 @@ impl Diagnostic { | Level::OnceNote | Level::Help | Level::OnceHelp + | Level::FailureNote | Level::Allow | Level::Expect(_) => false, } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b2bd4d8eb956e..42b1c85e93968 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1541,6 +1541,8 @@ pub enum Level { /// /// The [`LintExpectationId`] is used for expected lint diagnostics. In all other cases this /// should be `None`. + /// + /// Its `EmissionGuarantee` is `()`. ForceWarning(Option), /// A warning about the code being compiled. Does not prevent compilation from finishing. @@ -1570,7 +1572,8 @@ pub enum Level { /// Its `EmissionGuarantee` is `()`. OnceHelp, - /// Similar to `Note`, but used in cases where compilation has failed. Rare. + /// Similar to `Note`, but used in cases where compilation has failed. When printed for human + /// consumption, it doesn't have any kind of `note:` label. Rare. /// /// Its `EmissionGuarantee` is `()`. FailureNote, From 5dd0431386867a051f726cbba6e0f46f7bba5e5d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Jan 2024 13:56:22 +1100 Subject: [PATCH 043/101] Tighten the assertion in `downgrade_to_delayed_bug`. I.e. `Bug` and `Fatal` level diagnostics are never downgraded. --- compiler/rustc_errors/src/diagnostic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 09570fe74b6ff..299e4a840f726 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -306,7 +306,7 @@ impl Diagnostic { #[track_caller] pub fn downgrade_to_delayed_bug(&mut self) { assert!( - self.is_error(), + matches!(self.level, Level::Error | Level::DelayedBug(_)), "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", self.level ); From c3673868325f95203d5291f2fa3a399425c14876 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Jan 2024 15:10:23 +1100 Subject: [PATCH 044/101] Refactor `emit_diagnostic`. - Combine two different blocks involving `diagnostic.level.get_expectation_id()` into one. - Combine several `if`s involving `diagnostic.level` into a single `match`. This requires reordering some of the operations, but this has no functional effect. --- compiler/rustc_errors/src/lib.rs | 82 +++++++++++++++----------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 42b1c85e93968..b3461b676be27 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1247,24 +1247,41 @@ impl DiagCtxtInner { } fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option { - // The `LintExpectationId` can be stable or unstable depending on when it was created. - // Diagnostics created before the definition of `HirId`s are unstable and can not yet - // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by - // a stable one by the `LintLevelsBuilder`. - if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() { - self.unstable_expect_diagnostics.push(diagnostic); - return None; + if let Some(expectation_id) = diagnostic.level.get_expectation_id() { + // The `LintExpectationId` can be stable or unstable depending on when it was created. + // Diagnostics created before the definition of `HirId`s are unstable and can not yet + // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by + // a stable one by the `LintLevelsBuilder`. + if let LintExpectationId::Unstable { .. } = expectation_id { + self.unstable_expect_diagnostics.push(diagnostic); + return None; + } + self.suppressed_expected_diag = true; + self.fulfilled_expectations.insert(expectation_id.normalize()); + } + + if diagnostic.has_future_breakage() { + // Future breakages aren't emitted if they're Level::Allow, + // but they still need to be constructed and stashed below, + // so they'll trigger the good-path bug check. + self.suppressed_expected_diag = true; + self.future_breakage_diagnostics.push(diagnostic.clone()); + } + + if matches!(diagnostic.level, DelayedBug(_)) && self.flags.eagerly_emit_delayed_bugs { + diagnostic.level = Error; } - // FIXME(eddyb) this should check for `has_errors` and stop pushing - // once *any* errors were emitted (and truncate `span_delayed_bugs` - // when an error is first emitted, also), but maybe there's a case - // in which that's not sound? otherwise this is really inefficient. match diagnostic.level { - DelayedBug(_) if self.flags.eagerly_emit_delayed_bugs => { - diagnostic.level = Error; + // This must come after the possible promotion of `DelayedBug` to `Error` above. + Fatal | Error if self.treat_next_err_as_bug() => { + diagnostic.level = Bug; } DelayedBug(DelayedBugKind::Normal) => { + // FIXME(eddyb) this should check for `has_errors` and stop pushing + // once *any* errors were emitted (and truncate `span_delayed_bugs` + // when an error is first emitted, also), but maybe there's a case + // in which that's not sound? otherwise this is really inefficient. let backtrace = std::backtrace::Backtrace::capture(); self.span_delayed_bugs .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); @@ -1277,38 +1294,17 @@ impl DiagCtxtInner { .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); return None; } - _ => {} - } - - // This must come after the possible promotion of `DelayedBug` to - // `Error` above. - if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() { - diagnostic.level = Bug; - } - - if diagnostic.has_future_breakage() { - // Future breakages aren't emitted if they're Level::Allow, - // but they still need to be constructed and stashed below, - // so they'll trigger the good-path bug check. - self.suppressed_expected_diag = true; - self.future_breakage_diagnostics.push(diagnostic.clone()); - } - - if let Some(expectation_id) = diagnostic.level.get_expectation_id() { - self.suppressed_expected_diag = true; - self.fulfilled_expectations.insert(expectation_id.normalize()); - } - - if diagnostic.level == Warning && !self.flags.can_emit_warnings { - if diagnostic.has_future_breakage() { + Warning if !self.flags.can_emit_warnings => { + if diagnostic.has_future_breakage() { + (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); + } + return None; + } + Allow | Expect(_) => { (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); + return None; } - return None; - } - - if matches!(diagnostic.level, Expect(_) | Allow) { - (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); - return None; + _ => {} } let mut guaranteed = None; From 59e0bc2de7134a2d88e9c14db32884e631e90373 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Jan 2024 11:23:54 +1100 Subject: [PATCH 045/101] Split `Level::DelayedBug` in two. The two kinds of delayed bug have quite different semantics so a stronger conceptual separation is nice. (`is_error` is a good example, because the two kinds have different behaviour.) The commit also moves the `DelayedBug` variant after `Error` in `Level`, to reflect the fact that it's weaker than `Error` -- it might trigger an error but also might not. (The pre-existing `downgrade_to_delayed_bug` function also reflects the notion that delayed bugs are lower/after normal errors.) Plus it condenses some of the comments on `Level` into a table, for easier reading, and introduces `can_be_top_or_sub` to indicate which levels can be used in top-level diagnostics vs. subdiagnostics. Finally, it renames `DiagCtxtInner::span_delayed_bugs` as `DiagCtxtInner::delayed_bugs`. The `span_` prefix is unnecessary because some delayed bugs don't have a span. --- compiler/rustc_error_messages/src/lib.rs | 2 +- .../src/annotate_snippet_emitter_writer.rs | 6 +- compiler/rustc_errors/src/diagnostic.rs | 18 +- compiler/rustc_errors/src/emitter.rs | 1 + compiler/rustc_errors/src/lib.rs | 159 ++++++++++-------- .../equality-in-canonical-query.clone.stderr | 2 +- ...equality_in_canonical_query.current.stderr | 2 +- 7 files changed, 101 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 8fd7c5764797e..d212e18b4cd72 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -378,7 +378,7 @@ impl From> for DiagnosticMessage { } } -/// A workaround for "good path" ICEs when formatting types in disabled lints. +/// A workaround for good_path_delayed_bug ICEs when formatting types in disabled lints. /// /// Delays formatting until `.into(): DiagnosticMessage` is used. pub struct DelayDm(pub F); diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 949f52ef6b586..06f6c58c5ff2e 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -85,7 +85,11 @@ fn source_string(file: Lrc, line: &Line) -> String { /// Maps `Diagnostic::Level` to `snippet::AnnotationType` fn annotation_type_for_level(level: Level) -> AnnotationType { match level { - Level::Bug | Level::DelayedBug(_) | Level::Fatal | Level::Error => AnnotationType::Error, + Level::Bug + | Level::Fatal + | Level::Error + | Level::DelayedBug + | Level::GoodPathDelayedBug => AnnotationType::Error, Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, Level::Help | Level::OnceHelp => AnnotationType::Help, diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 299e4a840f726..1763c355069a9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,8 +1,7 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, - ErrCode, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, - SuggestionStyle, + CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level, + MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; @@ -235,14 +234,11 @@ impl Diagnostic { pub fn is_error(&self) -> bool { match self.level { - Level::Bug - | Level::DelayedBug(DelayedBugKind::Normal) - | Level::Fatal - | Level::Error => true, + Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true, - Level::ForceWarning(_) + Level::GoodPathDelayedBug + | Level::ForceWarning(_) | Level::Warning - | Level::DelayedBug(DelayedBugKind::GoodPath) | Level::Note | Level::OnceNote | Level::Help @@ -306,11 +302,11 @@ impl Diagnostic { #[track_caller] pub fn downgrade_to_delayed_bug(&mut self) { assert!( - matches!(self.level, Level::Error | Level::DelayedBug(_)), + matches!(self.level, Level::Error | Level::DelayedBug), "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", self.level ); - self.level = Level::DelayedBug(DelayedBugKind::Normal); + self.level = Level::DelayedBug; } /// Appends a labeled span to the diagnostic. diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4be5ed923e5e0..6370e1d387c37 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2116,6 +2116,7 @@ impl HumanEmitter { } if !self.short_message { for child in children { + assert!(child.level.can_be_top_or_sub().1); let span = &child.span; if let Err(err) = self.emit_messages_default_inner( span, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b3461b676be27..cfb2dfbeb984a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -439,7 +439,7 @@ struct DiagCtxtInner { has_printed: bool, emitter: Box, - span_delayed_bugs: Vec, + delayed_bugs: Vec, good_path_delayed_bugs: Vec, /// This flag indicates that an expected diagnostic was emitted and suppressed. /// This is used for the `good_path_delayed_bugs` check. @@ -523,8 +523,7 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { pub static TRACK_DIAGNOSTIC: AtomicRef = AtomicRef::new(&(default_track_diagnostic as _)); -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] -pub enum DelayedBugKind { +enum DelayedBugKind { Normal, GoodPath, } @@ -557,11 +556,6 @@ impl Drop for DiagCtxtInner { self.flush_delayed(DelayedBugKind::Normal) } - // FIXME(eddyb) this explains what `good_path_delayed_bugs` are! - // They're `span_delayed_bugs` but for "require some diagnostic happened" - // instead of "require some error happened". Sadly that isn't ideal, as - // lints can be `#[allow]`'d, potentially leading to this triggering. - // Also, "good path" should be replaced with a better naming. if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() { self.flush_delayed(DelayedBugKind::GoodPath); } @@ -608,7 +602,7 @@ impl DiagCtxt { deduplicated_warn_count: 0, has_printed: false, emitter, - span_delayed_bugs: Vec::new(), + delayed_bugs: Vec::new(), good_path_delayed_bugs: Vec::new(), suppressed_expected_diag: false, taught_diagnostics: Default::default(), @@ -664,7 +658,7 @@ impl DiagCtxt { inner.has_printed = false; // actually free the underlying memory (which `clear` would not do) - inner.span_delayed_bugs = Default::default(); + inner.delayed_bugs = Default::default(); inner.good_path_delayed_bugs = Default::default(); inner.taught_diagnostics = Default::default(); inner.emitted_diagnostic_codes = Default::default(); @@ -865,8 +859,7 @@ impl DiagCtxt { /// directly). #[track_caller] pub fn delayed_bug(&self, msg: impl Into) -> ErrorGuaranteed { - DiagnosticBuilder::::new(self, DelayedBug(DelayedBugKind::Normal), msg) - .emit() + DiagnosticBuilder::::new(self, DelayedBug, msg).emit() } /// Like `delayed_bug`, but takes an additional span. @@ -879,15 +872,12 @@ impl DiagCtxt { sp: impl Into, msg: impl Into, ) -> ErrorGuaranteed { - DiagnosticBuilder::::new(self, DelayedBug(DelayedBugKind::Normal), msg) - .with_span(sp) - .emit() + DiagnosticBuilder::::new(self, DelayedBug, msg).with_span(sp).emit() } - // FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's - // where the explanation of what "good path" is (also, it should be renamed). + /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`. pub fn good_path_delayed_bug(&self, msg: impl Into) { - DiagnosticBuilder::<()>::new(self, DelayedBug(DelayedBugKind::GoodPath), msg).emit() + DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit() } #[track_caller] @@ -961,7 +951,7 @@ impl DiagCtxt { pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { let inner = self.inner.borrow(); let result = - inner.has_errors() || inner.lint_err_count > 0 || !inner.span_delayed_bugs.is_empty(); + inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty(); result.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() @@ -1247,6 +1237,8 @@ impl DiagCtxtInner { } fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option { + assert!(diagnostic.level.can_be_top_or_sub().0); + if let Some(expectation_id) = diagnostic.level.get_expectation_id() { // The `LintExpectationId` can be stable or unstable depending on when it was created. // Diagnostics created before the definition of `HirId`s are unstable and can not yet @@ -1268,27 +1260,29 @@ impl DiagCtxtInner { self.future_breakage_diagnostics.push(diagnostic.clone()); } - if matches!(diagnostic.level, DelayedBug(_)) && self.flags.eagerly_emit_delayed_bugs { + if matches!(diagnostic.level, DelayedBug | GoodPathDelayedBug) + && self.flags.eagerly_emit_delayed_bugs + { diagnostic.level = Error; } match diagnostic.level { - // This must come after the possible promotion of `DelayedBug` to `Error` above. + // This must come after the possible promotion of `DelayedBug`/`GoodPathDelayedBug` to + // `Error` above. Fatal | Error if self.treat_next_err_as_bug() => { diagnostic.level = Bug; } - DelayedBug(DelayedBugKind::Normal) => { + DelayedBug => { // FIXME(eddyb) this should check for `has_errors` and stop pushing - // once *any* errors were emitted (and truncate `span_delayed_bugs` + // once *any* errors were emitted (and truncate `delayed_bugs` // when an error is first emitted, also), but maybe there's a case // in which that's not sound? otherwise this is really inefficient. let backtrace = std::backtrace::Backtrace::capture(); - self.span_delayed_bugs - .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); + self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); #[allow(deprecated)] return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); } - DelayedBug(DelayedBugKind::GoodPath) => { + GoodPathDelayedBug => { let backtrace = std::backtrace::Backtrace::capture(); self.good_path_delayed_bugs .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); @@ -1392,12 +1386,12 @@ impl DiagCtxtInner { fn flush_delayed(&mut self, kind: DelayedBugKind) { let (bugs, note1) = match kind { DelayedBugKind::Normal => ( - std::mem::take(&mut self.span_delayed_bugs), - "no errors encountered even though `span_delayed_bug` issued", + std::mem::take(&mut self.delayed_bugs), + "no errors encountered even though delayed bugs were created", ), DelayedBugKind::GoodPath => ( std::mem::take(&mut self.good_path_delayed_bugs), - "no warnings or errors encountered even though `good_path_delayed_bugs` issued", + "no warnings or errors encountered even though good path delayed bugs were created", ), }; let note2 = "those delayed bugs will now be shown as internal compiler errors"; @@ -1436,8 +1430,8 @@ impl DiagCtxtInner { let mut bug = if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner }; - // "Undelay" the `DelayedBug`s (into plain `Bug`s). - if !matches!(bug.level, DelayedBug(_)) { + // "Undelay" the delayed bugs (into plain `Bug`s). + if !matches!(bug.level, DelayedBug | GoodPathDelayedBug) { // NOTE(eddyb) not panicking here because we're already producing // an ICE, and the more information the merrier. bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel { @@ -1503,85 +1497,89 @@ impl DelayedDiagnostic { } } +/// Level is_error EmissionGuarantee Top-level Sub Used in lints? +/// ----- -------- ----------------- --------- --- -------------- +/// Bug yes BugAbort yes - - +/// Fatal yes FatalAbort/FatalError(*) yes - - +/// Error yes ErrorGuaranteed yes - yes +/// DelayedBug yes ErrorGuaranteed yes - - +/// GoodPathDelayedBug - () yes - - +/// ForceWarning - () yes - lint-only +/// Warning - () yes yes yes +/// Note - () rare yes - +/// OnceNote - () - yes lint-only +/// Help - () rare yes - +/// OnceHelp - () - yes lint-only +/// FailureNote - () rare - - +/// Allow - () yes - lint-only +/// Expect - () yes - lint-only +/// +/// (*) `FatalAbort` normally, `FatalError` in the non-aborting "almost fatal" case that is +/// occasionally used. +/// #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] pub enum Level { /// For bugs in the compiler. Manifests as an ICE (internal compiler error) panic. - /// - /// Its `EmissionGuarantee` is `BugAbort`. Bug, - /// This is a strange one: lets you register an error without emitting it. If compilation ends - /// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be - /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths - /// that should only be reached when compiling erroneous code. - /// - /// Its `EmissionGuarantee` is `ErrorGuaranteed` for `Normal` delayed bugs, and `()` for - /// `GoodPath` delayed bugs. - DelayedBug(DelayedBugKind), - /// An error that causes an immediate abort. Used for things like configuration errors, /// internal overflows, some file operation errors. - /// - /// Its `EmissionGuarantee` is `FatalAbort`, except in the non-aborting "almost fatal" case - /// that is occasionally used, where it is `FatalError`. Fatal, /// An error in the code being compiled, which prevents compilation from finishing. This is the /// most common case. - /// - /// Its `EmissionGuarantee` is `ErrorGuaranteed`. Error, + /// This is a strange one: lets you register an error without emitting it. If compilation ends + /// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be + /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths + /// that should only be reached when compiling erroneous code. + DelayedBug, + + /// Like `DelayedBug`, but weaker: lets you register an error without emitting it. If + /// compilation ends without any other diagnostics being emitted (and without an expected lint + /// being suppressed), this will be emitted as a bug. Otherwise, it will be silently dropped. + /// I.e. "expect other diagnostics are emitted (or suppressed)" semantics. Useful on code paths + /// that should only be reached when emitting diagnostics, e.g. for expensive one-time + /// diagnostic formatting operations. + /// + /// FIXME(nnethercote) good path delayed bugs are semantically strange: if printed they produce + /// an ICE, but they don't satisfy `is_error` and they don't guarantee an error is emitted. + /// Plus there's the extra complication with expected (suppressed) lints. They have limited + /// use, and are used in very few places, and "good path" isn't a good name. It would be good + /// to remove them. + GoodPathDelayedBug, + /// A `force-warn` lint warning about the code being compiled. Does not prevent compilation /// from finishing. /// /// The [`LintExpectationId`] is used for expected lint diagnostics. In all other cases this /// should be `None`. - /// - /// Its `EmissionGuarantee` is `()`. ForceWarning(Option), /// A warning about the code being compiled. Does not prevent compilation from finishing. - /// - /// Its `EmissionGuarantee` is `()`. Warning, - /// A message giving additional context. Rare, because notes are more commonly attached to other - /// diagnostics such as errors. - /// - /// Its `EmissionGuarantee` is `()`. + /// A message giving additional context. Note, - /// A note that is only emitted once. Rare, mostly used in circumstances relating to lints. - /// - /// Its `EmissionGuarantee` is `()`. + /// A note that is only emitted once. OnceNote, - /// A message suggesting how to fix something. Rare, because help messages are more commonly - /// attached to other diagnostics such as errors. - /// - /// Its `EmissionGuarantee` is `()`. + /// A message suggesting how to fix something. Help, - /// A help that is only emitted once. Rare. - /// - /// Its `EmissionGuarantee` is `()`. + /// A help that is only emitted once. OnceHelp, /// Similar to `Note`, but used in cases where compilation has failed. When printed for human - /// consumption, it doesn't have any kind of `note:` label. Rare. - /// - /// Its `EmissionGuarantee` is `()`. + /// consumption, it doesn't have any kind of `note:` label. FailureNote, /// Only used for lints. - /// - /// Its `EmissionGuarantee` is `()`. Allow, /// Only used for lints. - /// - /// Its `EmissionGuarantee` is `()`. Expect(LintExpectationId), } @@ -1595,7 +1593,7 @@ impl Level { fn color(self) -> ColorSpec { let mut spec = ColorSpec::new(); match self { - Bug | DelayedBug(_) | Fatal | Error => { + Bug | Fatal | Error | DelayedBug | GoodPathDelayedBug => { spec.set_fg(Some(Color::Red)).set_intense(true); } ForceWarning(_) | Warning => { @@ -1615,7 +1613,7 @@ impl Level { pub fn to_str(self) -> &'static str { match self { - Bug | DelayedBug(_) => "error: internal compiler error", + Bug | DelayedBug | GoodPathDelayedBug => "error: internal compiler error", Fatal | Error => "error", ForceWarning(_) | Warning => "warning", Note | OnceNote => "note", @@ -1635,6 +1633,19 @@ impl Level { _ => None, } } + + // Can this level be used in a top-level diagnostic message and/or a + // subdiagnostic message? + fn can_be_top_or_sub(&self) -> (bool, bool) { + match self { + Bug | DelayedBug | Fatal | Error | GoodPathDelayedBug | ForceWarning(_) + | FailureNote | Allow | Expect(_) => (true, false), + + Warning | Note | Help => (true, true), + + OnceNote | OnceHelp => (false, true), + } + } } // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite. diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr index 1011fc4163bca..0e3cd2ff06099 100644 --- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr +++ b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr @@ -1,4 +1,4 @@ -note: no errors encountered even though `span_delayed_bug` issued +note: no errors encountered even though delayed bugs were created note: those delayed bugs will now be shown as internal compiler errors diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr index d92bafce142c2..fd76526644bdd 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr @@ -1,4 +1,4 @@ -note: no errors encountered even though `span_delayed_bug` issued +note: no errors encountered even though delayed bugs were created note: those delayed bugs will now be shown as internal compiler errors From d6221957e03d017d2763bd6635f88548984176eb Mon Sep 17 00:00:00 2001 From: Chris Copeland Date: Sun, 4 Feb 2024 15:28:35 -0800 Subject: [PATCH 046/101] Add an `armv8r-none-eabihf` target to support the Cortex-R52. --- compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/targets/armv8r_none_eabihf.rs | 35 ++++++++++++++++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../src/platform-support/arm-none-eabi.md | 1 + .../platform-support/armv8r-none-eabihf.md | 40 +++++++++++++++++++ src/tools/build-manifest/src/main.rs | 1 + tests/assembly/targets/targets-elf.rs | 3 ++ 8 files changed, 83 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs create mode 100644 src/doc/rustc/src/platform-support/armv8r-none-eabihf.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6c698c5b01dd5..a57255db795ac 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1543,6 +1543,7 @@ supported_targets! { ("armebv7r-none-eabihf", armebv7r_none_eabihf), ("armv7r-none-eabi", armv7r_none_eabi), ("armv7r-none-eabihf", armv7r_none_eabihf), + ("armv8r-none-eabihf", armv8r_none_eabihf), ("x86_64-pc-solaris", x86_64_pc_solaris), ("sparcv9-sun-solaris", sparcv9_sun_solaris), diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs new file mode 100644 index 0000000000000..28dba4f7f5d83 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs @@ -0,0 +1,35 @@ +// Targets the Little-endian Cortex-R52 processor (ARMv8-R) + +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "armv8r-none-eabihf".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + + options: TargetOptions { + abi: "eabihf".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + relocation_model: RelocModel::Static, + panic_strategy: PanicStrategy::Abort, + // The Cortex-R52 has two variants with respect to floating-point support: + // 1. fp-armv8, SP-only, with 16 DP (32 SP) registers + // 2. neon-fp-armv8, SP+DP, with 32 DP registers + // Use the lesser of these two options as the default, as it will produce code + // compatible with either variant. + // + // Reference: + // Arm Cortex-R52 Processor Technical Reference Manual + // - Chapter 15 Advanced SIMD and floating-point support + features: "+fp-armv8,-fp64,-d32".into(), + max_atomic_width: Some(64), + emit_debug_gdb_scripts: false, + // GCC defaults to 8 for arm-none here. + c_enum_min_bits: Some(8), + ..Default::default() + }, + } +} diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 1998b008dc811..1f9307203bc3c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -26,6 +26,7 @@ - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md) + - [armv8r-none-eabihf](platform-support/armv8r-none-eabihf.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f648a60b6c48d..13a7b483d6f3d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -278,6 +278,7 @@ target | std | host | notes [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * | | Bare ARMv7-A, hardfloat +[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare ARMv8-R, hardfloat [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS `armv7s-apple-ios` | ✓ | | ARMv7-A Apple-A6 Apple iOS `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index 4f76d0d7bbce7..6335a6405a102 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -13,6 +13,7 @@ - [{arm,thumb}v4t-none-eabi](armv4t-none-eabi.md) - [{arm,thumb}v5te-none-eabi](armv5te-none-eabi.md) - armv7a-none-eabihf +- [armv8r-none-eabihf](armv8r-none-eabihf.md) Bare-metal target for 32-bit ARM CPUs. diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md new file mode 100644 index 0000000000000..588e5d7c99449 --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md @@ -0,0 +1,40 @@ +# `armv8r-none-eabihf` + +**Tier: 3** + +Bare-metal target for CPUs in the ARMv8-R architecture family, supporting +dual ARM/Thumb mode, with ARM mode as the default. + +Processors in this family include the Arm [Cortex-R52][cortex-r52] +and [Cortex-R52+][cortex-r52-plus]. + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +[cortex-r52]: https://www.arm.com/products/silicon-ip-cpu/cortex-r/cortex-r52 +[cortex-r52-plus]: https://www.arm.com/products/silicon-ip-cpu/cortex-r/cortex-r52-plus + +## Target maintainers + +- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net` + +## Requirements + +The Cortex-R52 family always includes a floating-point unit, so there is no +non-`hf` version of this target. The floating-point features assumed by this +target are those of the single-precision-only config of the Cortex-R52, which +has 16 double-precision registers, accessible as 32 single-precision registers. +The other variant of Cortex-R52 includes double-precision, 32 double-precision +registers, and Advanced SIMD (Neon). + +The manual refers to this as the "Full Advanced SIMD config". To compile code +for this variant, use: `-C target-feature=+fp64,+d32,+neon`. See the [Advanced +SIMD and floating-point support][fpu] section of the Cortex-R52 Processor +Technical Reference Manual for more details. + +[fpu]: https://developer.arm.com/documentation/100026/0104/Advanced-SIMD-and-floating-point-support/About-the-Advanced-SIMD-and-floating-point-support + +## Cross-compilation toolchains and C code + +This target supports C code compiled with the `arm-none-eabi` target triple and +`-march=armv8-r` or a suitable `-mcpu` flag. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 1ef8cf7de3cd5..808fb0c07ea51 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -83,6 +83,7 @@ static TARGETS: &[&str] = &[ "armebv7r-none-eabihf", "armv7r-none-eabi", "armv7r-none-eabihf", + "armv8r-none-eabihf", "armv7s-apple-ios", "bpfeb-unknown-none", "bpfel-unknown-none", diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 41f5df0fba001..6105ea430ddd3 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -174,6 +174,9 @@ // revisions: armv7r_none_eabihf // [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf // [armv7r_none_eabihf] needs-llvm-components: arm +// revisions: armv8r_none_eabihf +// [armv8r_none_eabihf] compile-flags: --target armv8r-none-eabihf +// [armv8r_none_eabihf] needs-llvm-components: arm // FIXME: disabled since it fails on CI saying the csky component is missing /* revisions: csky_unknown_linux_gnuabiv2 From 9cd6c68033929d60441ad4286d1270eeafbb8620 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 5 Feb 2024 10:51:18 +0100 Subject: [PATCH 047/101] cleanup effect var handling --- .../src/infer/canonical/canonicalizer.rs | 2 +- .../rustc_infer/src/infer/canonical/mod.rs | 8 +++- compiler/rustc_infer/src/infer/freshen.rs | 9 +--- compiler/rustc_infer/src/infer/mod.rs | 15 ++++--- .../rustc_infer/src/infer/relate/combine.rs | 38 +++-------------- compiler/rustc_infer/src/infer/resolve.rs | 9 ++-- compiler/rustc_middle/src/infer/unify_key.rs | 42 ++++++++++--------- 7 files changed, 52 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e4b37f05b778f..30ca70326fa87 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -480,7 +480,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } ty::ConstKind::Infer(InferConst::EffectVar(vid)) => { match self.infcx.unwrap().probe_effect_var(vid) { - Some(value) => return self.fold_const(value.as_const(self.tcx)), + Some(value) => return self.fold_const(value), None => { return self.canonicalize_const_var( CanonicalVarInfo { kind: CanonicalVarKind::Effect }, diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 386fdb09ba5d5..1f68a5a9c6179 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,6 +24,7 @@ use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; use rustc_index::IndexVec; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, List, Ty, TyCtxt}; @@ -152,7 +153,12 @@ impl<'tcx> InferCtxt<'tcx> { ) .into(), CanonicalVarKind::Effect => { - let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; + let vid = self + .inner + .borrow_mut() + .effect_unification_table() + .new_key(EffectVarValue::Unknown) + .vid; ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool) .into() } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index d256994d8d1fd..2d5fa1b5c7001 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -151,13 +151,8 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty()) } ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { - let opt_ct = self - .infcx - .inner - .borrow_mut() - .effect_unification_table() - .probe_value(v) - .map(|effect| effect.as_const(self.infcx.tcx)); + let opt_ct = + self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known(); self.freshen_const( opt_ct, ty::InferConst::EffectVar(v), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 0a39fe007fd22..13baecf6002c0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -8,6 +8,7 @@ pub use self::ValuePairs::*; pub use relate::combine::ObligationEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::undo_log::UndoLogs; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use self::opaque_types::OpaqueTypeStorage; @@ -25,8 +26,8 @@ use rustc_data_structures::unify as ut; use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; -use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::{select, DefiningAnchor}; @@ -818,7 +819,7 @@ impl<'tcx> InferCtxt<'tcx> { (0..table.len()) .map(|i| ty::EffectVid::from_usize(i)) - .filter(|&vid| table.probe_value(vid).is_none()) + .filter(|&vid| table.probe_value(vid).is_unknown()) .map(|v| { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool) }) @@ -1236,7 +1237,8 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; + let effect_vid = + self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid; let ty = self .tcx .type_of(param.def_id) @@ -1416,8 +1418,8 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn probe_effect_var(&self, vid: EffectVid) -> Option> { - self.inner.borrow_mut().effect_unification_table().probe_value(vid) + pub fn probe_effect_var(&self, vid: EffectVid) -> Option> { + self.inner.borrow_mut().effect_unification_table().probe_value(vid).known() } /// Attempts to resolve all type/region/const variables in @@ -1893,7 +1895,8 @@ impl<'a, 'tcx> TypeFolder> for ShallowResolver<'a, 'tcx> { .borrow_mut() .effect_unification_table() .probe_value(vid) - .map_or(ct, |val| val.as_const(self.infcx.tcx)), + .known() + .unwrap_or(ct), _ => ct, } } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 1c120646f1f90..13c17ee1cd2b8 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -202,11 +202,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::ConstKind::Infer(InferConst::EffectVar(a_vid)), ty::ConstKind::Infer(InferConst::EffectVar(b_vid)), ) => { - self.inner - .borrow_mut() - .effect_unification_table() - .unify_var_var(a_vid, b_vid) - .map_err(|a| effect_unification_error(self.tcx, relation.a_is_expected(), a))?; + self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid); return Ok(a); } @@ -233,19 +229,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { - return self.unify_effect_variable( - relation.a_is_expected(), - vid, - EffectVarValue::Const(b), - ); + return Ok(self.unify_effect_variable(vid, b)); } (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => { - return self.unify_effect_variable( - !relation.a_is_expected(), - vid, - EffectVarValue::Const(a), - ); + return Ok(self.unify_effect_variable(vid, a)); } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) @@ -366,18 +354,12 @@ impl<'tcx> InferCtxt<'tcx> { Ok(Ty::new_float(self.tcx, val)) } - fn unify_effect_variable( - &self, - vid_is_expected: bool, - vid: ty::EffectVid, - val: EffectVarValue<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { + fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> { self.inner .borrow_mut() .effect_unification_table() - .unify_var_value(vid, Some(val)) - .map_err(|e| effect_unification_error(self.tcx, vid_is_expected, e))?; - Ok(val.as_const(self.tcx)) + .union_value(vid, EffectVarValue::Known(val)); + val } } @@ -579,11 +561,3 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) } - -fn effect_unification_error<'tcx>( - _tcx: TyCtxt<'tcx>, - _a_is_expected: bool, - (_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>), -) -> TypeError<'tcx> { - bug!("unexpected effect unification error") -} diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 959b09031277c..d5999331dfab6 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -237,14 +237,13 @@ impl<'tcx> TypeFolder> for EagerResolver<'_, 'tcx> { } ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool); - match self.infcx.probe_effect_var(vid) { - Some(c) => c.as_const(self.infcx.tcx), - None => ty::Const::new_infer( + self.infcx.probe_effect_var(vid).unwrap_or_else(|| { + ty::Const::new_infer( self.infcx.tcx, ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)), self.infcx.tcx.types.bool, - ), - } + ) + }) } _ => { if c.has_infer() { diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index c35799ef47f2b..63c0ebd5f6b79 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -194,33 +194,37 @@ impl<'tcx> UnifyValue for ConstVariableValue<'tcx> { /// values for the effect inference variable #[derive(Clone, Copy, Debug)] pub enum EffectVarValue<'tcx> { - /// The host effect is on, enabling access to syscalls, filesystem access, etc. - Host, - /// The host effect is off. Execution is restricted to const operations only. - NoHost, - Const(ty::Const<'tcx>), + Unknown, + Known(ty::Const<'tcx>), } impl<'tcx> EffectVarValue<'tcx> { - pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> { + pub fn known(self) -> Option> { match self { - EffectVarValue::Host => tcx.consts.true_, - EffectVarValue::NoHost => tcx.consts.false_, - EffectVarValue::Const(c) => c, + EffectVarValue::Unknown => None, + EffectVarValue::Known(value) => Some(value), + } + } + + pub fn is_unknown(self) -> bool { + match self { + EffectVarValue::Unknown => true, + EffectVarValue::Known(_) => false, } } } impl<'tcx> UnifyValue for EffectVarValue<'tcx> { - type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>); + type Error = NoError; fn unify_values(value1: &Self, value2: &Self) -> Result { - match (value1, value2) { - (EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host), - (EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost), - (EffectVarValue::NoHost | EffectVarValue::Host, _) - | (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)), - (EffectVarValue::Const(_), EffectVarValue::Const(_)) => { - bug!("equating two const variables, both of which have known values") + match (*value1, *value2) { + (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown), + (EffectVarValue::Unknown, EffectVarValue::Known(val)) + | (EffectVarValue::Known(val), EffectVarValue::Unknown) => { + Ok(EffectVarValue::Known(val)) + } + (EffectVarValue::Known(_), EffectVarValue::Known(_)) => { + bug!("equating known inference variables: {value1:?} {value2:?}") } } } @@ -229,7 +233,7 @@ impl<'tcx> UnifyValue for EffectVarValue<'tcx> { #[derive(PartialEq, Copy, Clone, Debug)] pub struct EffectVidKey<'tcx> { pub vid: ty::EffectVid, - pub phantom: PhantomData>, + pub phantom: PhantomData>, } impl<'tcx> From for EffectVidKey<'tcx> { @@ -239,7 +243,7 @@ impl<'tcx> From for EffectVidKey<'tcx> { } impl<'tcx> UnifyKey for EffectVidKey<'tcx> { - type Value = Option>; + type Value = EffectVarValue<'tcx>; #[inline] fn index(&self) -> u32 { self.vid.as_u32() From d9508a1fd2bdbc2f7c4e2ee28503f15487fdc8ce Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 15:44:22 +1100 Subject: [PATCH 048/101] Make `Emitter::emit_diagnostic` consuming. All the other `emit`/`emit_diagnostic` methods were recently made consuming (e.g. #119606), but this one wasn't. But it makes sense to. Much of this is straightforward, and lots of `clone` calls are avoided. There are a couple of tricky bits. - `Emitter::primary_span_formatted` no longer takes a `Diagnostic` and returns a pair. Instead it takes the two fields from `Diagnostic` that it used (`span` and `suggestions`) as `&mut`, and modifies them. This is necessary to avoid the cloning of `diag.children` in two emitters. - `from_errors_diagnostic` is rearranged so various uses of `diag` occur before the consuming `emit_diagnostic` call. --- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- .../src/annotate_snippet_emitter_writer.rs | 16 +++--- compiler/rustc_errors/src/emitter.rs | 41 +++++++-------- compiler/rustc_errors/src/json.rs | 52 ++++++++++--------- compiler/rustc_errors/src/lib.rs | 26 ++++++---- .../passes/lint/check_code_block_syntax.rs | 2 +- src/tools/rustfmt/src/parse/session.rs | 20 +++---- 7 files changed, 84 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 4211f875dd01a..9b24339d2551f 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1810,7 +1810,7 @@ impl Translate for SharedEmitter { } impl Emitter for SharedEmitter { - fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) { + fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) { let args: FxHashMap = diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect(); drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 949f52ef6b586..1ce75a0381237 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -44,15 +44,15 @@ impl Translate for AnnotateSnippetEmitter { impl Emitter for AnnotateSnippetEmitter { /// The entry point for the diagnostics generation - fn emit_diagnostic(&mut self, diag: &Diagnostic) { + fn emit_diagnostic(&mut self, mut diag: Diagnostic) { let fluent_args = to_fluent_args(diag.args()); - let mut children = diag.children.clone(); - let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); + let mut suggestions = diag.suggestions.unwrap_or(vec![]); + self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &mut primary_span, - &mut children, + &mut diag.span, + &mut diag.children, &diag.level, self.macro_backtrace, ); @@ -62,9 +62,9 @@ impl Emitter for AnnotateSnippetEmitter { &diag.messages, &fluent_args, &diag.code, - &primary_span, - &children, - suggestions, + &diag.span, + &diag.children, + &suggestions, ); } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4be5ed923e5e0..12d947f2098b1 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -193,7 +193,7 @@ pub type DynEmitter = dyn Emitter + DynSend; /// Emitter trait for emitting errors. pub trait Emitter: Translate { /// Emit a structured diagnostic. - fn emit_diagnostic(&mut self, diag: &Diagnostic); + fn emit_diagnostic(&mut self, diag: Diagnostic); /// Emit a notification that an artifact has been output. /// Currently only supported for the JSON format. @@ -230,17 +230,17 @@ pub trait Emitter: Translate { /// /// * If the current `Diagnostic` has only one visible `CodeSuggestion`, /// we format the `help` suggestion depending on the content of the - /// substitutions. In that case, we return the modified span only. + /// substitutions. In that case, we modify the span and clear the + /// suggestions. /// /// * If the current `Diagnostic` has multiple suggestions, - /// we return the original `primary_span` and the original suggestions. - fn primary_span_formatted<'a>( + /// we leave `primary_span` and the suggestions untouched. + fn primary_span_formatted( &mut self, - diag: &'a Diagnostic, + primary_span: &mut MultiSpan, + suggestions: &mut Vec, fluent_args: &FluentArgs<'_>, - ) -> (MultiSpan, &'a [CodeSuggestion]) { - let mut primary_span = diag.span.clone(); - let suggestions = diag.suggestions.as_deref().unwrap_or(&[]); + ) { if let Some((sugg, rest)) = suggestions.split_first() { let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap(); if rest.is_empty() && @@ -287,16 +287,15 @@ pub trait Emitter: Translate { primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); // We return only the modified primary_span - (primary_span, &[]) + suggestions.clear(); } else { // if there are multiple suggestions, print them all in full // to be consistent. We could try to figure out if we can // make one (or the first one) inline, but that would give // undue importance to a semi-random suggestion - (primary_span, suggestions) } } else { - (primary_span, suggestions) + // do nothing } } @@ -518,16 +517,15 @@ impl Emitter for HumanEmitter { self.sm.as_ref() } - fn emit_diagnostic(&mut self, diag: &Diagnostic) { + fn emit_diagnostic(&mut self, mut diag: Diagnostic) { let fluent_args = to_fluent_args(diag.args()); - let mut children = diag.children.clone(); - let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); - debug!("emit_diagnostic: suggestions={:?}", suggestions); + let mut suggestions = diag.suggestions.unwrap_or(vec![]); + self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &mut primary_span, - &mut children, + &mut diag.span, + &mut diag.children, &diag.level, self.macro_backtrace, ); @@ -537,9 +535,9 @@ impl Emitter for HumanEmitter { &diag.messages, &fluent_args, &diag.code, - &primary_span, - &children, - suggestions, + &diag.span, + &diag.children, + &suggestions, self.track_diagnostics.then_some(&diag.emitted_at), ); } @@ -576,9 +574,8 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, diag: &Diagnostic) { + fn emit_diagnostic(&mut self, mut diag: Diagnostic) { if diag.level == Level::Fatal { - let mut diag = diag.clone(); diag.note(self.fatal_note.clone()); self.fatal_dcx.emit_diagnostic(diag); } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 6f92299827950..470e3d52452cf 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -176,7 +176,7 @@ impl Translate for JsonEmitter { } impl Emitter for JsonEmitter { - fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) { + fn emit_diagnostic(&mut self, diag: crate::Diagnostic) { let data = Diagnostic::from_errors_diagnostic(diag, self); let result = self.emit(EmitTyped::Diagnostic(data)); if let Err(e) = result { @@ -201,7 +201,7 @@ impl Emitter for JsonEmitter { } FutureBreakageItem { diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic( - &diag, self, + diag, self, )), } }) @@ -340,7 +340,7 @@ struct UnusedExterns<'a, 'b, 'c> { } impl Diagnostic { - fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { + fn from_errors_diagnostic(diag: crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { let args = to_fluent_args(diag.args()); let sugg = diag.suggestions.iter().flatten().map(|sugg| { let translated_message = @@ -382,6 +382,28 @@ impl Diagnostic { Ok(()) } } + + let translated_message = je.translate_messages(&diag.messages, &args); + + let code = if let Some(code) = diag.code { + Some(DiagnosticCode { + code: code.to_string(), + explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(), + }) + } else if let Some(IsLint { name, .. }) = &diag.is_lint { + Some(DiagnosticCode { code: name.to_string(), explanation: None }) + } else { + None + }; + let level = diag.level.to_str(); + let spans = DiagnosticSpan::from_multispan(&diag.span, &args, je); + let children = diag + .children + .iter() + .map(|c| Diagnostic::from_sub_diagnostic(c, &args, je)) + .chain(sugg) + .collect(); + let buf = BufWriter::default(); let output = buf.clone(); je.json_rendered @@ -398,30 +420,12 @@ impl Diagnostic { let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); - let translated_message = je.translate_messages(&diag.messages, &args); - - let code = if let Some(code) = diag.code { - Some(DiagnosticCode { - code: code.to_string(), - explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(), - }) - } else if let Some(IsLint { name, .. }) = &diag.is_lint { - Some(DiagnosticCode { code: name.to_string(), explanation: None }) - } else { - None - }; - Diagnostic { message: translated_message.to_string(), code, - level: diag.level.to_str(), - spans: DiagnosticSpan::from_multispan(&diag.span, &args, je), - children: diag - .children - .iter() - .map(|c| Diagnostic::from_sub_diagnostic(c, &args, je)) - .chain(sugg) - .collect(), + level, + spans, + children, rendered: Some(output), } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b2bd4d8eb956e..a48fcf3af9b02 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -990,9 +990,13 @@ impl DiagCtxt { match (errors.len(), warnings.len()) { (0, 0) => return, - (0, _) => inner - .emitter - .emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))), + (0, _) => { + // Use `inner.emitter` directly, otherwise the warning might not be emitted, e.g. + // with a configuration like `--cap-lints allow --force-warn bare_trait_objects`. + inner + .emitter + .emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))); + } (_, 0) => { inner.emit_diagnostic(Diagnostic::new(Fatal, errors)); } @@ -1056,7 +1060,7 @@ impl DiagCtxt { } pub fn force_print_diagnostic(&self, db: Diagnostic) { - self.inner.borrow_mut().emitter.emit_diagnostic(&db); + self.inner.borrow_mut().emitter.emit_diagnostic(db); } pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option { @@ -1324,11 +1328,15 @@ impl DiagCtxtInner { !self.emitted_diagnostics.insert(diagnostic_hash) }; + let is_error = diagnostic.is_error(); + let is_lint = diagnostic.is_lint.is_some(); + // Only emit the diagnostic if we've been asked to deduplicate or // haven't already emitted an equivalent diagnostic. if !(self.flags.deduplicate_diagnostics && already_emitted) { debug!(?diagnostic); debug!(?self.emitted_diagnostics); + let already_emitted_sub = |sub: &mut SubDiagnostic| { debug!(?sub); if sub.level != OnceNote && sub.level != OnceHelp { @@ -1340,7 +1348,6 @@ impl DiagCtxtInner { debug!(?diagnostic_hash); !self.emitted_diagnostics.insert(diagnostic_hash) }; - diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); if already_emitted { diagnostic.note( @@ -1348,16 +1355,17 @@ impl DiagCtxtInner { ); } - self.emitter.emit_diagnostic(&diagnostic); - if diagnostic.is_error() { + if is_error { self.deduplicated_err_count += 1; } else if matches!(diagnostic.level, ForceWarning(_) | Warning) { self.deduplicated_warn_count += 1; } self.has_printed = true; + + self.emitter.emit_diagnostic(diagnostic); } - if diagnostic.is_error() { - if diagnostic.is_lint.is_some() { + if is_error { + if is_lint { self.lint_err_count += 1; } else { self.err_count += 1; diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index e73649c722493..6649894f9c25d 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -156,7 +156,7 @@ impl Translate for BufferEmitter { } impl Emitter for BufferEmitter { - fn emit_diagnostic(&mut self, diag: &Diagnostic) { + fn emit_diagnostic(&mut self, diag: Diagnostic) { let mut buffer = self.buffer.borrow_mut(); let fluent_args = to_fluent_args(diag.args()); diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 6dc3eac44d43d..f0af401d3da4b 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -47,7 +47,7 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, _db: &Diagnostic) {} + fn emit_diagnostic(&mut self, _db: Diagnostic) {} } fn silent_emitter() -> Box { @@ -64,7 +64,7 @@ struct SilentOnIgnoredFilesEmitter { } impl SilentOnIgnoredFilesEmitter { - fn handle_non_ignoreable_error(&mut self, db: &Diagnostic) { + fn handle_non_ignoreable_error(&mut self, db: Diagnostic) { self.has_non_ignorable_parser_errors = true; self.can_reset.store(false, Ordering::Release); self.emitter.emit_diagnostic(db); @@ -86,7 +86,7 @@ impl Emitter for SilentOnIgnoredFilesEmitter { None } - fn emit_diagnostic(&mut self, db: &Diagnostic) { + fn emit_diagnostic(&mut self, db: Diagnostic) { if db.level() == DiagnosticLevel::Fatal { return self.handle_non_ignoreable_error(db); } @@ -365,7 +365,7 @@ mod tests { None } - fn emit_diagnostic(&mut self, _db: &Diagnostic) { + fn emit_diagnostic(&mut self, _db: Diagnostic) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } } @@ -424,7 +424,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, Some(span)); - emitter.emit_diagnostic(&fatal_diagnostic); + emitter.emit_diagnostic(fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } @@ -449,7 +449,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); - emitter.emit_diagnostic(&non_fatal_diagnostic); + emitter.emit_diagnostic(non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0); assert_eq!(can_reset_errors.load(Ordering::Acquire), true); } @@ -473,7 +473,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); - emitter.emit_diagnostic(&non_fatal_diagnostic); + emitter.emit_diagnostic(non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } @@ -512,9 +512,9 @@ mod tests { let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span)); let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span)); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None); - emitter.emit_diagnostic(&bar_diagnostic); - emitter.emit_diagnostic(&foo_diagnostic); - emitter.emit_diagnostic(&fatal_diagnostic); + emitter.emit_diagnostic(bar_diagnostic); + emitter.emit_diagnostic(foo_diagnostic); + emitter.emit_diagnostic(fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 2); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } From f32aa1aef991d70c5d3a72a2d35fe65a99348d48 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 5 Feb 2024 14:16:40 +0300 Subject: [PATCH 049/101] rustc_metadata: fix typo --- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 542caf8622385..85631bd8edbfa 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -386,7 +386,7 @@ impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { } } -// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would +// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy($value))`, which would // normally need extra variables to avoid errors about multiple mutable borrows. macro_rules! record { ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ @@ -398,7 +398,7 @@ macro_rules! record { }}; } -// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would +// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_array($value))`, which would // normally need extra variables to avoid errors about multiple mutable borrows. macro_rules! record_array { ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ From 9f58cf43c78e77b59479da2beaea0265f529280e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jan 2024 13:47:29 +0100 Subject: [PATCH 050/101] get rid of nontrivial_structural_match lint and custom_eq const qualif --- .../src/transform/check_consts/check.rs | 29 +---- .../src/transform/check_consts/qualifs.rs | 32 +---- compiler/rustc_lint/src/lib.rs | 5 + compiler/rustc_lint_defs/src/builtin.rs | 43 +------ compiler/rustc_middle/src/mir/query.rs | 3 +- .../src/thir/pattern/const_to_pat.rs | 113 +++++------------- .../rustc_mir_build/src/thir/pattern/mod.rs | 18 +-- ...corner_cases.rs => accept_corner_cases.rs} | 11 +- .../const_in_pattern/custom-eq-branch-pass.rs | 3 +- .../const_in_pattern/custom-eq-branch-warn.rs | 38 ------ .../custom-eq-branch-warn.stderr | 14 --- .../const_in_pattern/issue-73431.stderr | 1 - .../const_in_pattern/warn_corner_cases.stderr | 36 ------ ...2307-match-ref-ref-forbidden-without-eq.rs | 2 +- ...-match-ref-ref-forbidden-without-eq.stderr | 2 +- 15 files changed, 53 insertions(+), 297 deletions(-) rename tests/ui/consts/const_in_pattern/{warn_corner_cases.rs => accept_corner_cases.rs} (76%) delete mode 100644 tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs delete mode 100644 tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr delete mode 100644 tests/ui/consts/const_in_pattern/issue-73431.stderr delete mode 100644 tests/ui/consts/const_in_pattern/warn_corner_cases.stderr diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 89c65d9232586..5ff81615552bf 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -20,7 +20,7 @@ use std::mem; use std::ops::{ControlFlow, Deref}; use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; +use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; @@ -149,37 +149,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let return_loc = ccx.body.terminator_loc(return_block); - let custom_eq = match ccx.const_kind() { - // We don't care whether a `const fn` returns a value that is not structurally - // matchable. Functions calls are opaque and always use type-based qualification, so - // this value should never be used. - hir::ConstContext::ConstFn => true, - - // If we know that all values of the return type are structurally matchable, there's no - // need to run dataflow. - // Opaque types do not participate in const generics or pattern matching, so we can safely count them out. - _ if ccx.body.return_ty().has_opaque_types() - || !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => - { - false - } - - hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => { - let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) - .into_engine(ccx.tcx, ccx.body) - .iterate_to_fixpoint() - .into_results_cursor(ccx.body); - - cursor.seek_after_primary_effect(return_loc); - cursor.get().contains(RETURN_PLACE) - } - }; - ConstQualifs { needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc), has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), - custom_eq, tainted_by_errors, } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 1efa52df5817b..67fef20807910 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::*; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty}; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, + ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, }; use super::ConstCx; @@ -24,7 +24,6 @@ pub fn in_any_value_of_ty<'tcx>( has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), - custom_eq: CustomEq::in_any_value_of_ty(cx, ty), tainted_by_errors, } } @@ -213,35 +212,6 @@ impl Qualif for NeedsNonConstDrop { } } -/// A constant that cannot be used as part of a pattern in a `match` expression. -pub struct CustomEq; - -impl Qualif for CustomEq { - const ANALYSIS_NAME: &'static str = "flow_custom_eq"; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.custom_eq - } - - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`, - // we know that at least some values of that type are not structural-match. I say "some" - // because that component may be part of an enum variant (e.g., - // `Option::::Some`), in which case some values of this type may be - // structural-match (`Option::None`). - traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some() - } - - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - def: AdtDef<'tcx>, - args: GenericArgsRef<'tcx>, - ) -> bool { - let ty = Ty::new_adt(cx.tcx, def, args); - !ty.is_structural_eq_shallow(cx.tcx) - } -} - // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. /// Returns `true` if this `Rvalue` contains qualif `Q`. diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0a15671e68692..1c03de410ee7d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -520,6 +520,11 @@ fn register_builtins(store: &mut LintStore) { "illegal_floating_point_literal_pattern", "no longer a warning, float patterns behave the same as `==`", ); + store.register_removed( + "nontrivial_structural_match", + "no longer needed, see RFC #3535 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 07c0e75a71c96..e4298a2636f9f 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3,6 +3,9 @@ //! These are the built-in lints that are emitted direct in the main //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. +//! +//! When removing a lint, make sure to also add a call to `register_removed` in +//! compiler/rustc_lint/src/lib.rs. use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason}; use rustc_span::edition::Edition; @@ -66,7 +69,6 @@ declare_lint_pass! { MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, NON_EXHAUSTIVE_OMITTED_PATTERNS, - NONTRIVIAL_STRUCTURAL_MATCH, ORDER_DEPENDENT_TRAIT_OBJECTS, OVERLAPPING_RANGE_ENDPOINTS, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -2341,45 +2343,6 @@ declare_lint! { }; } -declare_lint! { - /// The `nontrivial_structural_match` lint detects constants that are used in patterns, - /// whose type is not structural-match and whose initializer body actually uses values - /// that are not structural-match. So `Option` is ok if the constant - /// is just `None`. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(nontrivial_structural_match)] - /// - /// #[derive(Copy, Clone, Debug)] - /// struct NoDerive(u32); - /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } - /// impl Eq for NoDerive { } - /// fn main() { - /// const INDEX: Option = [None, Some(NoDerive(10))][0]; - /// match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Previous versions of Rust accepted constants in patterns, even if those constants' types - /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of - /// `PartialEq`, which can report that two constants are not equal even if they are - /// bit-equivalent. - pub NONTRIVIAL_STRUCTURAL_MATCH, - Warn, - "constant used in pattern of non-structural-match type and the constant's initializer \ - expression contains values of non-structural-match types", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #73448 ", - }; -} - declare_lint! { /// The `const_patterns_without_partial_eq` lint detects constants that are used in patterns, /// whose type does not implement `PartialEq`. diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 98642adc19090..90b6df1dd1f5e 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -189,7 +189,7 @@ pub struct BorrowCheckResult<'tcx> { /// The result of the `mir_const_qualif` query. /// -/// Each field (except `error_occurred`) corresponds to an implementer of the `Qualif` trait in +/// Each field (except `tainted_by_errors`) corresponds to an implementer of the `Qualif` trait in /// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each /// `Qualif`. #[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)] @@ -197,7 +197,6 @@ pub struct ConstQualifs { pub has_mut_interior: bool, pub needs_drop: bool, pub needs_non_const_drop: bool, - pub custom_eq: bool, pub tainted_by_errors: Option, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 9d3a9bf6745e7..18a00724c3d0e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -1,6 +1,5 @@ use rustc_apfloat::Float; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_index::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::Obligation; @@ -17,8 +16,8 @@ use std::cell::Cell; use super::PatCtxt; use crate::errors::{ - IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch, - NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern, + IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch, PointerPattern, + TypeNotStructural, UnionPattern, UnsizedPattern, }; impl<'a, 'tcx> PatCtxt<'a, 'tcx> { @@ -33,11 +32,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { cv: mir::Const<'tcx>, id: hir::HirId, span: Span, - check_body_for_struct_match_violation: Option, ) -> Box> { let infcx = self.tcx.infer_ctxt().build(); let mut convert = ConstToPat::new(self, id, span, infcx); - convert.to_pat(cv, check_body_for_struct_match_violation) + convert.to_pat(cv) } } @@ -103,11 +101,7 @@ impl<'tcx> ConstToPat<'tcx> { ty.is_structural_eq_shallow(self.infcx.tcx) } - fn to_pat( - &mut self, - cv: mir::Const<'tcx>, - check_body_for_struct_match_violation: Option, - ) -> Box> { + fn to_pat(&mut self, cv: mir::Const<'tcx>) -> Box> { trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be @@ -116,14 +110,6 @@ impl<'tcx> ConstToPat<'tcx> { // once indirect_structural_match is a full fledged error, this // level of indirection can be eliminated - let mir_structural_match_violation = check_body_for_struct_match_violation.map(|def_id| { - // `mir_const_qualif` must be called with the `DefId` of the item where the const is - // defined, not where it is declared. The difference is significant for associated - // constants. - self.tcx().mir_const_qualif(def_id).custom_eq - }); - debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation); - let have_valtree = matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_))); let inlined_const_as_pat = match cv { @@ -137,15 +123,15 @@ impl<'tcx> ConstToPat<'tcx> { | ty::ConstKind::Expr(_) => { span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind()) } - ty::ConstKind::Value(valtree) => self - .recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false)) - .unwrap_or_else(|_: FallbackToOpaqueConst| { + ty::ConstKind::Value(valtree) => { + self.recur(valtree, cv.ty()).unwrap_or_else(|_: FallbackToOpaqueConst| { Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Constant { value: cv }, }) - }), + }) + } }, mir::Const::Unevaluated(_, _) => { span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}") @@ -160,7 +146,12 @@ impl<'tcx> ConstToPat<'tcx> { if self.saw_const_match_error.get().is_none() { // If we were able to successfully convert the const to some pat (possibly with some // lints, but no errors), double-check that all types in the const implement - // `Structural` and `PartialEq`. + // `PartialEq`. Even if we have a valtree, we may have found something + // in there with non-structural-equality, meaning we match using `PartialEq` + // and we hence have to check that that impl exists. + // This is all messy but not worth cleaning up: at some point we'll emit + // a hard error when we don't have a valtree or when we find something in + // the valtree that is not structural; then this can all be made a lot simpler. let structural = traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty()); @@ -170,19 +161,12 @@ impl<'tcx> ConstToPat<'tcx> { structural ); - // This can occur because const qualification treats all associated constants as - // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them - // before it runs. - // - // FIXME(#73448): Find a way to bring const qualification into parity with - // `search_for_structural_match_violation`. - if structural.is_none() && mir_structural_match_violation.unwrap_or(false) { - warn!("MIR const-checker found novel structural match violation. See #73448."); - return inlined_const_as_pat; - } - if let Some(non_sm_ty) = structural { if !self.type_has_partial_eq_impl(cv.ty()) { + // This is reachable and important even if we have a valtree: there might be + // non-structural things in a valtree, in which case we fall back to `PartialEq` + // comparison, in which case we better make sure the trait is implemented for + // each inner type (and not just for the surrounding type). let e = if let ty::Adt(def, ..) = non_sm_ty.kind() { if def.is_union() { let err = UnionPattern { span: self.span }; @@ -201,35 +185,18 @@ impl<'tcx> ConstToPat<'tcx> { // We errored. Signal that in the pattern, so that follow up errors can be silenced. let kind = PatKind::Error(e); return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); - } else if let ty::Adt(..) = cv.ty().kind() - && matches!(cv, mir::Const::Val(..)) - { - // This branch is only entered when the current `cv` is `mir::Const::Val`. - // This is because `mir::Const::ty` has already been handled by `Self::recur` - // and the invalid types may be ignored. + } else if !have_valtree { + // Not being structural prevented us from constructing a valtree, + // so this is definitely a case we want to reject. let err = TypeNotStructural { span: self.span, non_sm_ty }; let e = self.tcx().dcx().emit_err(err); let kind = PatKind::Error(e); return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); - } else if !self.saw_const_match_lint.get() { - if let Some(mir_structural_match_violation) = mir_structural_match_violation { - match non_sm_ty.kind() { - ty::Adt(..) if mir_structural_match_violation => { - self.tcx().emit_node_span_lint( - lint::builtin::INDIRECT_STRUCTURAL_MATCH, - self.id, - self.span, - IndirectStructuralMatch { non_sm_ty }, - ); - } - _ => { - debug!( - "`search_for_structural_match_violation` found one, but `CustomEq` was \ - not in the qualifs for that `const`" - ); - } - } - } + } else { + // This could be a violation in an inactive enum variant. + // Since we have a valtree, we trust that we have traversed the full valtree and + // complained about structural match violations there, so we don't + // have to check anything any more. } } else if !have_valtree && !self.saw_const_match_lint.get() { // The only way valtree construction can fail without the structural match @@ -299,7 +266,7 @@ impl<'tcx> ConstToPat<'tcx> { let field = FieldIdx::new(idx); // Patterns can only use monomorphic types. let ty = self.tcx().normalize_erasing_regions(self.param_env, ty); - Ok(FieldPat { field, pattern: self.recur(val, ty, false)? }) + Ok(FieldPat { field, pattern: self.recur(val, ty)? }) }) .collect() } @@ -310,7 +277,6 @@ impl<'tcx> ConstToPat<'tcx> { &self, cv: ValTree<'tcx>, ty: Ty<'tcx>, - mir_structural_match_violation: bool, ) -> Result>, FallbackToOpaqueConst> { let id = self.id; let span = self.span; @@ -395,7 +361,7 @@ impl<'tcx> ConstToPat<'tcx> { prefix: cv .unwrap_branch() .iter() - .map(|val| self.recur(*val, *elem_ty, false)) + .map(|val| self.recur(*val, *elem_ty)) .collect::>()?, slice: None, suffix: Box::new([]), @@ -404,7 +370,7 @@ impl<'tcx> ConstToPat<'tcx> { prefix: cv .unwrap_branch() .iter() - .map(|val| self.recur(*val, *elem_ty, false)) + .map(|val| self.recur(*val, *elem_ty)) .collect::>()?, slice: None, suffix: Box::new([]), @@ -471,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> { _ => *pointee_ty, }; // References have the same valtree representation as their pointee. - let subpattern = self.recur(cv, pointee_ty, false)?; + let subpattern = self.recur(cv, pointee_ty)?; self.behind_reference.set(old); PatKind::Deref { subpattern } } @@ -512,25 +478,6 @@ impl<'tcx> ConstToPat<'tcx> { } }; - if self.saw_const_match_error.get().is_none() - && !self.saw_const_match_lint.get() - && mir_structural_match_violation - // FIXME(#73448): Find a way to bring const qualification into parity with - // `search_for_structural_match_violation` and then remove this condition. - - // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we - // could get `Option`, even though `Option` is annotated with derive. - && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, ty) - { - self.saw_const_match_lint.set(true); - tcx.emit_node_span_lint( - lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, - id, - span, - NontrivialStructuralMatch { non_sm_ty }, - ); - } - Ok(Box::new(Pat { span, ty, kind })) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 2190ad14b5511..1a5cf13e28978 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -542,7 +542,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match const_value { Ok(const_) => { - let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id())); + let pattern = self.const_to_pat(const_, id, span); if !is_associated_const { return pattern; @@ -612,7 +612,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; if let Some(lit_input) = lit_input { match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind, + Ok(c) => return self.const_to_pat(Const::Ty(c), id, span).kind, // If an error occurred, ignore that it's a literal // and leave reporting the error up to const eval of // the unevaluated constant below. @@ -635,17 +635,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) { - let subpattern = self.const_to_pat( - Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), - id, - span, - None, - ); + let subpattern = + self.const_to_pat(Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span); PatKind::InlineConstant { subpattern, def: def_id } } else { // If that fails, convert it to an opaque constant pattern. match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { - Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind, + Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span).kind, Err(ErrorHandled::TooGeneric(_)) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span }); @@ -681,9 +677,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lit_input = LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { - Ok(constant) => { - self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind - } + Ok(constant) => self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span).kind, Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs b/tests/ui/consts/const_in_pattern/accept_corner_cases.rs similarity index 76% rename from tests/ui/consts/const_in_pattern/warn_corner_cases.rs rename to tests/ui/consts/const_in_pattern/accept_corner_cases.rs index 75f1965921c91..d5b3908f35437 100644 --- a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs +++ b/tests/ui/consts/const_in_pattern/accept_corner_cases.rs @@ -2,9 +2,8 @@ // This test is checking our logic for structural match checking by enumerating // the different kinds of const expressions. This test is collecting cases where -// we have accepted the const expression as a pattern in the past but we want -// to begin warning the user that a future version of Rust may start rejecting -// such const expressions. +// we have accepted the const expression as a pattern in the past and wish to +// continue doing so. // The specific corner cases we are exploring here are instances where the // const-evaluator computes a value that *does* meet the conditions for @@ -24,18 +23,12 @@ impl Eq for NoDerive { } fn main() { const INDEX: Option = [None, Some(NoDerive(10))][0]; match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; - //~^ WARN must be annotated with `#[derive(PartialEq)]` - //~| WARN this was previously accepted const fn build() -> Option { None } const CALL: Option = build(); match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; - //~^ WARN must be annotated with `#[derive(PartialEq)]` - //~| WARN this was previously accepted impl NoDerive { const fn none() -> Option { None } } const METHOD_CALL: Option = NoDerive::none(); match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; - //~^ WARN must be annotated with `#[derive(PartialEq)]` - //~| WARN this was previously accepted } diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs index a38731ceb8a86..ac89b7925ffec 100644 --- a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs +++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs @@ -12,6 +12,7 @@ impl PartialEq for CustomEq { } #[derive(PartialEq, Eq)] +#[allow(unused)] enum Foo { Bar, Baz, @@ -21,7 +22,7 @@ enum Foo { const BAR_BAZ: Foo = if 42 == 42 { Foo::Bar } else { - Foo::Baz + Foo::Qux(CustomEq) // dead arm }; fn main() { diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs deleted file mode 100644 index 34b1422dfb3cb..0000000000000 --- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs +++ /dev/null @@ -1,38 +0,0 @@ -// check-pass - -struct CustomEq; - -impl Eq for CustomEq {} -impl PartialEq for CustomEq { - fn eq(&self, _: &Self) -> bool { - false - } -} - -#[derive(PartialEq, Eq)] -enum Foo { - Bar, - Baz, - Qux(CustomEq), -} - -// We know that `BAR_BAZ` will always be `Foo::Bar` and thus eligible for structural matching, but -// dataflow will be more conservative. -const BAR_BAZ: Foo = if 42 == 42 { - Foo::Bar -} else { - Foo::Qux(CustomEq) -}; - -fn main() { - match Foo::Qux(CustomEq) { - BAR_BAZ => panic!(), - //~^ WARN must be annotated with `#[derive(PartialEq)]` - //~| NOTE the traits must be derived - //~| NOTE StructuralPartialEq.html for details - //~| WARN this was previously accepted - //~| NOTE see issue #73448 - //~| NOTE `#[warn(nontrivial_structural_match)]` on by default - _ => {} - } -} diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr deleted file mode 100644 index c473c00f8dbbd..0000000000000 --- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq)]` - --> $DIR/custom-eq-branch-warn.rs:29:9 - | -LL | BAR_BAZ => panic!(), - | ^^^^^^^ - | - = 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 #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details - = note: `#[warn(nontrivial_structural_match)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/consts/const_in_pattern/issue-73431.stderr b/tests/ui/consts/const_in_pattern/issue-73431.stderr deleted file mode 100644 index c82dea4aa50df..0000000000000 --- a/tests/ui/consts/const_in_pattern/issue-73431.stderr +++ /dev/null @@ -1 +0,0 @@ -WARN rustc_mir_build::thir::pattern::const_to_pat MIR const-checker found novel structural match violation. See #73448. diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr deleted file mode 100644 index 8ffd035ebec61..0000000000000 --- a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr +++ /dev/null @@ -1,36 +0,0 @@ -warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]` - --> $DIR/warn_corner_cases.rs:26:47 - | -LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; - | ^^^^^ - | - = 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 #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details - = note: `#[warn(nontrivial_structural_match)]` on by default - -warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]` - --> $DIR/warn_corner_cases.rs:32:47 - | -LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; - | ^^^^ - | - = 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 #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details - -warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]` - --> $DIR/warn_corner_cases.rs:38:47 - | -LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; - | ^^^^^^^^^^^ - | - = 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 #73448 - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details - -warning: 3 warnings emitted - diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs index fdb67bcf2d8e4..374e5d5acd080 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -10,7 +10,7 @@ // Issue 62307 pointed out a case where the structural-match checking // was too shallow. -#![warn(indirect_structural_match, nontrivial_structural_match)] +#![warn(indirect_structural_match)] // run-pass #[derive(Debug)] diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr index d0f2b820afa90..3e140a9317ef7 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -11,7 +11,7 @@ LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); note: the lint level is defined here --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 | -LL | #![warn(indirect_structural_match, nontrivial_structural_match)] +LL | #![warn(indirect_structural_match)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` From 48abca761a3479d0ae5a41a338dcbe742e240d7c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jan 2024 13:52:06 +0100 Subject: [PATCH 051/101] show indirect_structural_match and pointer_structural_match in future compat reports --- compiler/rustc_lint_defs/src/builtin.rs | 4 +- .../match/match-edge-cases_1.stderr | 11 ++ ...ssue-34784-match-on-non-int-raw-ptr.stderr | 60 ++++++++++ .../const_in_pattern/issue-44333.stderr | 30 +++++ .../reject_non_structural.stderr | 17 +++ .../const-partial_eq-fallback-ice.stderr | 18 +++ .../pattern/usefulness/consts-opaque.stderr | 88 ++++++++++++++ ...ide-behind-doubly-indirect-embedded.stderr | 17 +++ ...t-hide-behind-doubly-indirect-param.stderr | 17 +++ ...ide-behind-indirect-struct-embedded.stderr | 17 +++ ...t-hide-behind-indirect-struct-param.stderr | 17 +++ .../fn-ptr-is-structurally-matchable.stderr | 110 ++++++++++++++++++ ...-match-ref-ref-forbidden-without-eq.stderr | 34 ++++++ .../issue-63479-match-fnptr.stderr | 30 +++++ 14 files changed, 468 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e4298a2636f9f..5bd25b4a54b57 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2282,7 +2282,7 @@ declare_lint! { Warn, "constant used in pattern contains value of non-structural-match type in a field or a variant", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #62411 ", }; } @@ -2338,7 +2338,7 @@ declare_lint! { Warn, "pointers are not structural-match", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #62411 ", }; } diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr index c83ba41976bcd..7aa83de84ee71 100644 --- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr @@ -10,3 +10,14 @@ LL | NUMBER_POINTER => (), warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/match-edge-cases_1.rs:29:13 + | +LL | NUMBER_POINTER => (), + | ^^^^^^^^^^^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + diff --git a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr index 1546f23908c6f..416343a14dd27 100644 --- a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr +++ b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr @@ -41,3 +41,63 @@ LL | STR => {} error: aborting due to 4 previous errors +Future incompatibility report: Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:10:9 + | +LL | C => {} + | ^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:18:9 + | +LL | C_INNER => {} + | ^^^^^^^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9 + | +LL | D => {} + | ^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9 + | +LL | STR => {} + | ^^^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 + | +LL | #![deny(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr index 441aeecbc6d95..8b62e2a505746 100644 --- a/tests/ui/consts/const_in_pattern/issue-44333.stderr +++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr @@ -23,3 +23,33 @@ LL | BAR => println!("bar"), warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:19:9 + | +LL | FOO => println!("foo"), + | ^^^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:21:9 + | +LL | BAR => println!("bar"), + | ^^^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index da32b6d698bb5..31202e26044af 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -97,3 +97,20 @@ LL | #![warn(indirect_structural_match)] error: aborting due to 9 previous errors; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/reject_non_structural.rs:98:29 + | +LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; + | ^^^^^^^ + | + = 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 #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/reject_non_structural.rs:14:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr index 0b4d99727581b..2c38dc516bf84 100644 --- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr +++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr @@ -9,3 +9,21 @@ LL | if let CONSTANT = &&MyType { error: aborting due to 1 previous error +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]` + --> $DIR/const-partial_eq-fallback-ice.rs:14:12 + | +LL | if let CONSTANT = &&MyType { + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/const-partial_eq-fallback-ice.rs:1:10 + | +LL | #![allow(warnings)] + | ^^^^^^^^ + = note: `#[allow(indirect_structural_match)]` implied by `#[allow(warnings)]` + diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index 0b1a2e2736e1d..ca87f4a2aeec8 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -166,3 +166,91 @@ LL | WRAPQUUX => {}, Wrap(_) => todo!() error: aborting due to 10 previous errors; 8 warnings emitted For more information about this error, try `rustc --explain E0004`. +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:96:9 + | +LL | QUUX => {} + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:98:9 + | +LL | QUUX => {} + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:108:9 + | +LL | WRAPQUUX => {} + | ^^^^^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:110:9 + | +LL | WRAPQUUX => {} + | ^^^^^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:117:9 + | +LL | WRAPQUUX => {} + | ^^^^^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:127:9 + | +LL | WRAPQUUX => {} + | ^^^^^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:139:9 + | +LL | WHOKNOWSQUUX => {} + | ^^^^^^^^^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/consts-opaque.rs:142:9 + | +LL | WHOKNOWSQUUX => {} + | ^^^^^^^^^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr index 910d491baaf43..fc8dd75af6881 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr index cadd9be023c50..7c4c72bf888c6 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr index e4321cc6a4c71..e0c75c94da307 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9 + | +LL | WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = 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 #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr index decc29ad67cd2..0f815daf8a2eb 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr @@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]` + --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9 + | +LL | WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^ + | + = 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 #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr index 080bf5885ba75..cebe4a26d31ea 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr @@ -91,3 +91,113 @@ LL | CFOO => count += 1, warning: 10 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:43:14 + | +LL | Wrap(CFN1) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:52:14 + | +LL | Wrap(CFN2) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14 + | +LL | Wrap(CFN3) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14 + | +LL | Wrap(CFN4) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14 + | +LL | Wrap(CFN5) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14 + | +LL | Wrap(CFN6) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14 + | +LL | Wrap(CFN7) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14 + | +LL | Wrap(CFN8) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14 + | +LL | Wrap(CFN9) => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9 + | +LL | CFOO => count += 1, + | ^^^^ + | + = 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 #62411 + = note: `#[warn(pointer_structural_match)]` on by default + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr index 3e140a9317ef7..1665a9c8078ad 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -27,3 +27,37 @@ LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9 + | +LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } + | ^^^^^ + | + = 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 #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9 + | +LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } + | ^^^^^ + | + = 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 #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr index 4fdfce60bb861..fa672f7ef22e6 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr @@ -23,3 +23,33 @@ LL | TEST2 => println!("matched"), warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:36:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:42:5 + | +LL | TEST2 => println!("matched"), + | ^^^^^ + | + = 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 #62411 +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + From 45d01b81311b0888530cd9a394b62d6af04bd972 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jan 2024 14:22:56 +0100 Subject: [PATCH 052/101] update the tracking issue for structural match violations and bless a test I missed --- compiler/rustc_lint_defs/src/builtin.rs | 4 +- .../match/match-edge-cases_1.stderr | 4 +- ...ssue-34784-match-on-non-int-raw-ptr.stderr | 16 ++++---- .../const_in_pattern/issue-44333.stderr | 8 ++-- .../const_in_pattern/reject_non_structural.rs | 2 +- .../reject_non_structural.stderr | 4 +- tests/ui/consts/issue-89088.stderr | 17 ++++++++ .../const-partial_eq-fallback-ice.stderr | 2 +- .../pattern/usefulness/consts-opaque.stderr | 32 +++++++-------- ...ide-behind-doubly-indirect-embedded.stderr | 4 +- ...t-hide-behind-doubly-indirect-param.stderr | 4 +- ...ide-behind-indirect-struct-embedded.stderr | 4 +- ...t-hide-behind-indirect-struct-param.stderr | 4 +- .../fn-ptr-is-structurally-matchable.stderr | 40 +++++++++---------- ...-match-ref-ref-forbidden-without-eq.stderr | 8 ++-- .../issue-63479-match-fnptr.stderr | 8 ++-- 16 files changed, 89 insertions(+), 72 deletions(-) create mode 100644 tests/ui/consts/issue-89088.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5bd25b4a54b57..6a2a2c1e48e2a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2283,7 +2283,7 @@ declare_lint! { "constant used in pattern contains value of non-structural-match type in a field or a variant", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #62411 ", + reference: "issue #120362 ", }; } @@ -2339,7 +2339,7 @@ declare_lint! { "pointers are not structural-match", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #62411 ", + reference: "issue #120362 ", }; } diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr index 7aa83de84ee71..8a2aaade66503 100644 --- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr @@ -5,7 +5,7 @@ LL | NUMBER_POINTER => (), | ^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default warning: 1 warning emitted @@ -18,6 +18,6 @@ LL | NUMBER_POINTER => (), | ^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default diff --git a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr index 416343a14dd27..bc1015c173426 100644 --- a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr +++ b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr @@ -5,7 +5,7 @@ LL | C => {} | ^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 | @@ -19,7 +19,7 @@ LL | C_INNER => {} | ^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9 @@ -28,7 +28,7 @@ LL | D => {} | ^ | = 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 #62411 + = note: for more information, see issue #120362 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9 @@ -37,7 +37,7 @@ LL | STR => {} | ^^^ | = 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 #62411 + = note: for more information, see issue #120362 error: aborting due to 4 previous errors @@ -49,7 +49,7 @@ LL | C => {} | ^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 | @@ -64,7 +64,7 @@ LL | C_INNER => {} | ^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 | @@ -79,7 +79,7 @@ LL | D => {} | ^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 | @@ -94,7 +94,7 @@ LL | STR => {} | ^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9 | diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr index 8b62e2a505746..f5931f0cad08b 100644 --- a/tests/ui/consts/const_in_pattern/issue-44333.stderr +++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr @@ -5,7 +5,7 @@ LL | FOO => println!("foo"), | ^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-44333.rs:3:9 | @@ -19,7 +19,7 @@ LL | BAR => println!("bar"), | ^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: 2 warnings emitted @@ -31,7 +31,7 @@ LL | FOO => println!("foo"), | ^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-44333.rs:3:9 | @@ -46,7 +46,7 @@ LL | BAR => println!("bar"), | ^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-44333.rs:3:9 | diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs index 196930baed5de..71d4138104db1 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs @@ -100,5 +100,5 @@ fn main() { //~| NOTE the traits must be derived //~| NOTE StructuralPartialEq.html for details //~| WARN previously accepted by the compiler but is being phased out - //~| NOTE for more information, see issue #62411 + //~| NOTE for more information, see } diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index 31202e26044af..2c7aaf89aa787 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -86,7 +86,7 @@ LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops") | ^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here @@ -105,7 +105,7 @@ LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops") | ^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr new file mode 100644 index 0000000000000..d5c5f76b90a01 --- /dev/null +++ b/tests/ui/consts/issue-89088.stderr @@ -0,0 +1,17 @@ +Future incompatibility report: Future breakage diagnostic: +warning: to use a constant of type `Cow<'_, str>` in a pattern, `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]` + --> $DIR/issue-89088.rs:19:9 + | +LL | FOO => todo!(), + | ^^^ + | + = 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 #120362 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +note: the lint level is defined here + --> $DIR/issue-89088.rs:5:10 + | +LL | #![allow(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr index 2c38dc516bf84..59b454d398195 100644 --- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr +++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr @@ -17,7 +17,7 @@ LL | if let CONSTANT = &&MyType { | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index ca87f4a2aeec8..6a5bd185e39b3 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -5,7 +5,7 @@ LL | QUUX => {} | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. @@ -15,7 +15,7 @@ LL | QUUX => {} | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/consts-opaque.rs:108:9 @@ -24,7 +24,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/consts-opaque.rs:110:9 @@ -33,7 +33,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/consts-opaque.rs:117:9 @@ -42,7 +42,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/consts-opaque.rs:127:9 @@ -51,7 +51,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/consts-opaque.rs:139:9 @@ -60,7 +60,7 @@ LL | WHOKNOWSQUUX => {} | ^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/consts-opaque.rs:142:9 @@ -69,7 +69,7 @@ LL | WHOKNOWSQUUX => {} | ^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 error: unreachable pattern --> $DIR/consts-opaque.rs:48:9 @@ -174,7 +174,7 @@ LL | QUUX => {} | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -185,7 +185,7 @@ LL | QUUX => {} | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -196,7 +196,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -207,7 +207,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -218,7 +218,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -229,7 +229,7 @@ LL | WRAPQUUX => {} | ^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -240,7 +240,7 @@ LL | WHOKNOWSQUUX => {} | ^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -251,6 +251,6 @@ LL | WHOKNOWSQUUX => {} | ^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr index fc8dd75af6881..9945041113d79 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr @@ -5,7 +5,7 @@ LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLIN | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here @@ -24,7 +24,7 @@ LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLIN | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr index 7c4c72bf888c6..6ac261ae81437 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr @@ -5,7 +5,7 @@ LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here @@ -24,7 +24,7 @@ LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr index e0c75c94da307..41616fb90fe96 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr @@ -5,7 +5,7 @@ LL | WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itse | ^^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here @@ -24,7 +24,7 @@ LL | WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itse | ^^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr index 0f815daf8a2eb..99dea5171d1bc 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr @@ -5,7 +5,7 @@ LL | WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself | ^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here @@ -24,7 +24,7 @@ LL | WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself | ^^^^^^^^^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr index cebe4a26d31ea..11163ba70ec65 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr @@ -5,7 +5,7 @@ LL | Wrap(CFN1) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. @@ -15,7 +15,7 @@ LL | Wrap(CFN2) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14 @@ -24,7 +24,7 @@ LL | Wrap(CFN3) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14 @@ -33,7 +33,7 @@ LL | Wrap(CFN4) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14 @@ -42,7 +42,7 @@ LL | Wrap(CFN5) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14 @@ -51,7 +51,7 @@ LL | Wrap(CFN6) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14 @@ -60,7 +60,7 @@ LL | Wrap(CFN7) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14 @@ -69,7 +69,7 @@ LL | Wrap(CFN8) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14 @@ -78,7 +78,7 @@ LL | Wrap(CFN9) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9 @@ -87,7 +87,7 @@ LL | CFOO => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: 10 warnings emitted @@ -99,7 +99,7 @@ LL | Wrap(CFN1) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -110,7 +110,7 @@ LL | Wrap(CFN2) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -121,7 +121,7 @@ LL | Wrap(CFN3) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -132,7 +132,7 @@ LL | Wrap(CFN4) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -143,7 +143,7 @@ LL | Wrap(CFN5) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -154,7 +154,7 @@ LL | Wrap(CFN6) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -165,7 +165,7 @@ LL | Wrap(CFN7) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -176,7 +176,7 @@ LL | Wrap(CFN8) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -187,7 +187,7 @@ LL | Wrap(CFN9) => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default Future breakage diagnostic: @@ -198,6 +198,6 @@ LL | CFOO => count += 1, | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: `#[warn(pointer_structural_match)]` on by default diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr index 1665a9c8078ad..d4ab1ce3ba2ad 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -5,7 +5,7 @@ LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); | ^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here @@ -21,7 +21,7 @@ LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); | ^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details @@ -35,7 +35,7 @@ LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); | ^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here @@ -52,7 +52,7 @@ LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); | ^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details note: the lint level is defined here diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr index fa672f7ef22e6..0edcf44c4d795 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr @@ -5,7 +5,7 @@ LL | B(TEST) => println!("matched"), | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-63479-match-fnptr.rs:8:9 | @@ -19,7 +19,7 @@ LL | TEST2 => println!("matched"), | ^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 warning: 2 warnings emitted @@ -31,7 +31,7 @@ LL | B(TEST) => println!("matched"), | ^^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-63479-match-fnptr.rs:8:9 | @@ -46,7 +46,7 @@ LL | TEST2 => println!("matched"), | ^^^^^ | = 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 #62411 + = note: for more information, see issue #120362 note: the lint level is defined here --> $DIR/issue-63479-match-fnptr.rs:8:9 | From e00df17abd6eabfead30dce439592b1902fd0acd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jan 2024 10:03:02 +0100 Subject: [PATCH 053/101] merge the accepted-structural-match tests into one --- .../const_in_pattern/accept_corner_cases.rs | 34 ------------------- .../const_in_pattern/accept_structural.rs | 14 ++++++++ 2 files changed, 14 insertions(+), 34 deletions(-) delete mode 100644 tests/ui/consts/const_in_pattern/accept_corner_cases.rs diff --git a/tests/ui/consts/const_in_pattern/accept_corner_cases.rs b/tests/ui/consts/const_in_pattern/accept_corner_cases.rs deleted file mode 100644 index d5b3908f35437..0000000000000 --- a/tests/ui/consts/const_in_pattern/accept_corner_cases.rs +++ /dev/null @@ -1,34 +0,0 @@ -// run-pass - -// This test is checking our logic for structural match checking by enumerating -// the different kinds of const expressions. This test is collecting cases where -// we have accepted the const expression as a pattern in the past and wish to -// continue doing so. - -// The specific corner cases we are exploring here are instances where the -// const-evaluator computes a value that *does* meet the conditions for -// structural-match, but the const expression itself has abstractions (like -// calls to const functions) that may fit better with a type-based analysis -// rather than a commitment to a specific value. - -#![warn(indirect_structural_match)] - -#[derive(Copy, Clone, Debug)] -struct NoDerive(#[allow(dead_code)] u32); - -// This impl makes `NoDerive` irreflexive. -impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } -impl Eq for NoDerive { } - -fn main() { - const INDEX: Option = [None, Some(NoDerive(10))][0]; - match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; - - const fn build() -> Option { None } - const CALL: Option = build(); - match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; - - impl NoDerive { const fn none() -> Option { None } } - const METHOD_CALL: Option = NoDerive::none(); - match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; -} diff --git a/tests/ui/consts/const_in_pattern/accept_structural.rs b/tests/ui/consts/const_in_pattern/accept_structural.rs index 1f56f581c0270..69b4e75c62236 100644 --- a/tests/ui/consts/const_in_pattern/accept_structural.rs +++ b/tests/ui/consts/const_in_pattern/accept_structural.rs @@ -63,4 +63,18 @@ fn main() { const ADDR_OF: &OND = &None; match &None { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; + + // These ones are more subtle: the final value is fine, but statically analyzing the expression + // that computes the value would likely (incorrectly) have us conclude that this may match on + // values that do not have structural equality. + const INDEX: Option = [None, Some(NoDerive(10))][0]; + match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; + + const fn build() -> Option { None } + const CALL: Option = build(); + match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; + + impl NoDerive { const fn none() -> Option { None } } + const METHOD_CALL: Option = NoDerive::none(); + match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; } From 0184ca695bf10416211163008c3432d9d8144852 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Nov 2023 09:31:41 +0100 Subject: [PATCH 054/101] revert stabilization of const_intrinsic_copy --- library/core/src/intrinsics.rs | 8 ++++---- library/core/src/lib.rs | 1 + library/core/src/ptr/const_ptr.rs | 4 ++-- library/core/src/ptr/mod.rs | 7 +++++-- library/core/src/ptr/mut_ptr.rs | 8 ++++---- library/core/tests/lib.rs | 1 + tests/ui/consts/const-eval/raw-pointer-ub.rs | 2 +- 7 files changed, 18 insertions(+), 13 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 43124535ab5d8..6ea80c8d42faa 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2749,13 +2749,13 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[rustc_nounwind] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } @@ -2845,13 +2845,13 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[rustc_nounwind] fn copy(src: *const T, dst: *mut T, count: usize); } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a3279dcafef48..09d589f7cd807 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -135,6 +135,7 @@ #![feature(const_hint_assert_unchecked)] #![feature(const_index_range_slice_index)] #![feature(const_int_unchecked_arith)] +#![feature(const_intrinsic_copy)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] #![feature(const_ipv6)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index f3ceadee24c2f..1d5d683fa16cc 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1284,7 +1284,7 @@ impl *const T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1304,7 +1304,7 @@ impl *const T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index dce7e035fc73a..bc05b5b07def3 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1176,7 +1176,6 @@ pub const unsafe fn replace(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_read"] pub const unsafe fn read(src: *const T) -> T { @@ -1294,7 +1293,11 @@ pub const unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)] +#[rustc_allow_const_fn_unstable( + const_mut_refs, + const_maybe_uninit_as_mut_ptr, + const_intrinsic_copy +)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_read_unaligned"] pub const unsafe fn read_unaligned(src: *const T) -> T { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 3e47c4f440a44..376673d67c10b 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1385,7 +1385,7 @@ impl *mut T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1405,7 +1405,7 @@ impl *mut T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1425,7 +1425,7 @@ impl *mut T { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1445,7 +1445,7 @@ impl *mut T { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 9a3b477c2d159..15298e1c81622 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] +#![feature(const_intrinsic_copy)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_nonnull_new)] #![feature(const_pointer_is_aligned)] diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 3341f3c78e0d6..47105de453cb1 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -1,4 +1,4 @@ -#![feature(const_mut_refs)] +#![feature(const_mut_refs, const_intrinsic_copy)] const MISALIGNED_LOAD: () = unsafe { From 9aff42e358c8199d5667b92f157f753814c39235 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 5 Feb 2024 14:59:07 -0600 Subject: [PATCH 055/101] Update src/doc/rustc/src/platform-support.md --- src/doc/rustc/src/platform-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 13a7b483d6f3d..80d9dc85f162a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -278,9 +278,9 @@ target | std | host | notes [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * | | Bare ARMv7-A, hardfloat -[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare ARMv8-R, hardfloat [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS `armv7s-apple-ios` | ✓ | | ARMv7-A Apple-A6 Apple iOS +[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare ARMv8-R, hardfloat `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) From c94769a9748233559313c532d524f58ebb643b1d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 5 Feb 2024 22:21:40 +0100 Subject: [PATCH 056/101] Clarify order of operations during interning Co-authored-by: Ralf Jung --- compiler/rustc_const_eval/src/interpret/intern.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index c3a53f90e60a0..38e7843761be8 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -148,6 +148,13 @@ pub fn intern_const_alloc_recursive< // better errors. Maybe we should consider doing validation before interning in the future. while let Some(prov) = todo.pop() { let alloc_id = prov.alloc_id(); + // Crucially, we check this *before* checking whether the `alloc_id` + // has already been interned. The point of this check is to ensure that when + // there are multiple pointers to the same allocation, they are *all* immutable. + // Therefore it would be bad if we only checked the first pointer to any given + // allocation. + // (It is likely not possible to actually have multiple pointers to the same allocation, + // so alternatively we could also check that and ICE if there are multiple such pointers.) if intern_kind != InternKind::Promoted && inner_mutability == Mutability::Not && !prov.immutable() From d3214372046eb303ee7c4e569602cd3205975ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 6 Feb 2024 00:37:57 +0100 Subject: [PATCH 057/101] Remove b-naber from the compiler review rotation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 68c863bb919db..eba8e283815c8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -658,7 +658,6 @@ compiler-team = [ ] compiler-team-contributors = [ "@TaKO8Ki", - "@b-naber", "@nnethercote", "@fmease", ] From 411967c0786495d750a60d1cb67087471bc3684f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 31 Jan 2024 02:37:44 +0100 Subject: [PATCH 058/101] Zip together `place_ty` and `place_validity` --- .../rustc_pattern_analysis/src/usefulness.rs | 79 +++++++++++-------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index bbb68b353e436..246b15ad7d013 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -767,12 +767,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> { fn ctor_arity(&self, ctor: &Constructor) -> usize { self.cx.ctor_arity(ctor, self.ty) } - fn ctor_sub_tys( - &'a self, - ctor: &'a Constructor, - ) -> impl Iterator + ExactSizeIterator + Captures<'a> { - self.cx.ctor_sub_tys(ctor, self.ty) - } fn ctors_for_ty(&self) -> Result, Cx::Error> { self.cx.ctors_for_ty(self.ty) } @@ -828,6 +822,32 @@ impl fmt::Display for ValidityConstraint { } } +/// Data about a place under investigation. +struct PlaceInfo { + /// The type of the place. + ty: Cx::Ty, + /// Whether the place is known to contain valid data. + validity: ValidityConstraint, +} + +impl PlaceInfo { + fn specialize<'a>( + &'a self, + cx: &'a Cx, + ctor: &'a Constructor, + ) -> impl Iterator + ExactSizeIterator + Captures<'a> { + let ctor_sub_tys = cx.ctor_sub_tys(ctor, &self.ty); + let ctor_sub_validity = self.validity.specialize(ctor); + ctor_sub_tys.map(move |ty| PlaceInfo { ty, validity: ctor_sub_validity }) + } +} + +impl Clone for PlaceInfo { + fn clone(&self) -> Self { + Self { ty: self.ty.clone(), validity: self.validity } + } +} + /// Represents a pattern-tuple under investigation. // The three lifetimes are: // - 'p coming from the input @@ -1001,10 +1021,9 @@ struct Matrix<'p, Cx: TypeCx> { /// each column must have the same type. Each column corresponds to a place within the /// scrutinee. rows: Vec>, - /// Track the type of each column/place. - place_ty: SmallVec<[Cx::Ty; 2]>, - /// Track for each column/place whether it contains a known valid value. - place_validity: SmallVec<[ValidityConstraint; 2]>, + /// Track info about each place. Each place corresponds to a column in `rows`, and their types + /// must match. + place_info: SmallVec<[PlaceInfo; 2]>, /// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top /// of the file for details on relevancy. wildcard_row_is_relevant: bool, @@ -1032,10 +1051,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Self { + let place_info = PlaceInfo { ty: scrut_ty, validity: scrut_validity }; let mut matrix = Matrix { rows: Vec::with_capacity(arms.len()), - place_ty: smallvec![scrut_ty], - place_validity: smallvec![scrut_validity], + place_info: smallvec![place_info], wildcard_row_is_relevant: true, }; for (row_id, arm) in arms.iter().enumerate() { @@ -1051,11 +1070,11 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { matrix } - fn head_ty(&self) -> Option<&Cx::Ty> { - self.place_ty.first() + fn head_place(&self) -> Option<&PlaceInfo> { + self.place_info.first() } fn column_count(&self) -> usize { - self.place_ty.len() + self.place_info.len() } fn rows( @@ -1083,18 +1102,13 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { ctor: &Constructor, ctor_is_relevant: bool, ) -> Result, Cx::Error> { - let ctor_sub_tys = pcx.ctor_sub_tys(ctor); - let arity = ctor_sub_tys.len(); - let specialized_place_ty = ctor_sub_tys.chain(self.place_ty[1..].iter().cloned()).collect(); - let ctor_sub_validity = self.place_validity[0].specialize(ctor); - let specialized_place_validity = std::iter::repeat(ctor_sub_validity) - .take(arity) - .chain(self.place_validity[1..].iter().copied()) - .collect(); + let subfield_place_info = self.place_info[0].specialize(pcx.cx, ctor); + let arity = subfield_place_info.len(); + let specialized_place_info = + subfield_place_info.chain(self.place_info[1..].iter().cloned()).collect(); let mut matrix = Matrix { rows: Vec::new(), - place_ty: specialized_place_ty, - place_validity: specialized_place_validity, + place_info: specialized_place_info, wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant, }; for (i, row) in self.rows().enumerate() { @@ -1127,11 +1141,11 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> { .map(|row| row.iter().map(|pat| format!("{pat:?}")).collect()) .collect(); pretty_printed_matrix - .push(self.place_validity.iter().map(|validity| format!("{validity}")).collect()); + .push(self.place_info.iter().map(|place| format!("{}", place.validity)).collect()); let column_count = self.column_count(); assert!(self.rows.iter().all(|row| row.len() == column_count)); - assert!(self.place_validity.len() == column_count); + assert!(self.place_info.len() == column_count); let column_widths: Vec = (0..column_count) .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)) .collect(); @@ -1447,7 +1461,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( return Ok(WitnessMatrix::empty()); } - let Some(ty) = matrix.head_ty().cloned() else { + let Some(place) = matrix.head_place() else { // The base case: there are no columns in the matrix. We are morally pattern-matching on (). // A row is useful iff it has no (unguarded) rows above it. let mut useful = true; // Whether the next row is useful. @@ -1467,18 +1481,17 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( }; }; - debug!("ty: {ty:?}"); - let pcx = &PlaceCtxt { cx: mcx.tycx, ty: &ty }; + let ty = &place.ty.clone(); // Clone it out so we can mutate `matrix` later. + let pcx = &PlaceCtxt { cx: mcx.tycx, ty }; + debug!("ty: {:?}", pcx.ty); let ctors_for_ty = pcx.ctors_for_ty()?; - // Whether the place/column we are inspecting is known to contain valid data. - let place_validity = matrix.place_validity[0]; // We treat match scrutinees of type `!` or `EmptyEnum` differently. let is_toplevel_exception = is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors); // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`). - let empty_arms_are_unreachable = place_validity.is_known_valid() + let empty_arms_are_unreachable = place.validity.is_known_valid() && (is_toplevel_exception || mcx.tycx.is_exhaustive_patterns_feature_on() || mcx.tycx.is_min_exhaustive_patterns_feature_on()); From 6cac1c459ec1f2aa7dd31e9b1b90040c906c64f5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 31 Jan 2024 02:46:10 +0100 Subject: [PATCH 059/101] Track `is_top_level` via `PlaceInfo` --- .../rustc_pattern_analysis/src/usefulness.rs | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 246b15ad7d013..1ac984ce67eec 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -828,6 +828,8 @@ struct PlaceInfo { ty: Cx::Ty, /// Whether the place is known to contain valid data. validity: ValidityConstraint, + /// Whether the place is the scrutinee itself or a subplace of it. + is_scrutinee: bool, } impl PlaceInfo { @@ -838,13 +840,17 @@ impl PlaceInfo { ) -> impl Iterator + ExactSizeIterator + Captures<'a> { let ctor_sub_tys = cx.ctor_sub_tys(ctor, &self.ty); let ctor_sub_validity = self.validity.specialize(ctor); - ctor_sub_tys.map(move |ty| PlaceInfo { ty, validity: ctor_sub_validity }) + ctor_sub_tys.map(move |ty| PlaceInfo { + ty, + validity: ctor_sub_validity, + is_scrutinee: false, + }) } } impl Clone for PlaceInfo { fn clone(&self) -> Self { - Self { ty: self.ty.clone(), validity: self.validity } + Self { ty: self.ty.clone(), validity: self.validity, is_scrutinee: self.is_scrutinee } } } @@ -1051,7 +1057,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Self { - let place_info = PlaceInfo { ty: scrut_ty, validity: scrut_validity }; + let place_info = PlaceInfo { ty: scrut_ty, validity: scrut_validity, is_scrutinee: true }; let mut matrix = Matrix { rows: Vec::with_capacity(arms.len()), place_info: smallvec![place_info], @@ -1446,11 +1452,10 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( /// - unspecialization, where we lift the results from the previous step into results for this step /// (using `apply_constructor` and by updating `row.useful` for each parent row). /// This is all explained at the top of the file. -#[instrument(level = "debug", skip(mcx, is_top_level), ret)] +#[instrument(level = "debug", skip(mcx), ret)] fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( mcx: UsefulnessCtxt<'a, Cx>, matrix: &mut Matrix<'p, Cx>, - is_top_level: bool, ) -> Result, Cx::Error> { debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count())); @@ -1488,7 +1493,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // We treat match scrutinees of type `!` or `EmptyEnum` differently. let is_toplevel_exception = - is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors); + place.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors); // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`). let empty_arms_are_unreachable = place.validity.is_known_valid() @@ -1517,7 +1522,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // Decide what constructors to report. let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); - let always_report_all = is_top_level && !is_integers; + let always_report_all = place.is_scrutinee && !is_integers; // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". let report_individual_missing_ctors = always_report_all || !all_missing; // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() => @@ -1538,7 +1543,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty(); let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?; let mut witnesses = ensure_sufficient_stack(|| { - compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false) + compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix) })?; // Transform witnesses for `spec_matrix` into witnesses for `matrix`. @@ -1613,8 +1618,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( ) -> Result, Cx::Error> { let cx = UsefulnessCtxt { tycx }; let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity); - let non_exhaustiveness_witnesses = - compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?; + let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix)?; let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column(); let arm_usefulness: Vec<_> = arms From b2bb51734cd97682cf2124e70ebbb73a3304b6b0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 24 Jan 2024 17:18:08 +0000 Subject: [PATCH 060/101] Make sure that async closures (and fns) only capture their parent callable's parameters by move, and nothing else --- compiler/rustc_ast_lowering/src/item.rs | 9 ++-- compiler/rustc_hir_typeck/src/upvar.rs | 51 +++++++++++++++++++ .../async-borrowck-escaping-closure-error.rs | 2 +- ...ync-borrowck-escaping-closure-error.stderr | 21 ++++++++ .../issue-74072-lifetime-name-annotations.rs | 2 + ...sue-74072-lifetime-name-annotations.stderr | 49 ++++++++++++++++-- ...021-incompatible-closure-captures-96258.rs | 2 +- ...incompatible-closure-captures-96258.stderr | 27 +--------- 8 files changed, 127 insertions(+), 36 deletions(-) create mode 100644 tests/ui/async-await/async-borrowck-escaping-closure-error.stderr diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6b772c1295f55..a122b4c51133c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1278,10 +1278,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let closure_id = coroutine_kind.closure_id(); let coroutine_expr = self.make_desugared_coroutine_expr( - // FIXME(async_closures): This should only move locals, - // and not upvars. Capturing closure upvars by ref doesn't - // work right now anyways, so whatever. - CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, + // The default capture mode here is by-ref. Later on during upvar analysis, + // we will force the captured arguments to by-move, but for async closures, + // we want to make sure that we avoid unnecessarily moving captures, or else + // all async closures would default to `FnOnce` as their calling mode. + CaptureBy::Ref, closure_id, return_type_hint, body_span, diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 82c5e566f161c..864acf51025b5 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -200,6 +200,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_information: Default::default(), fake_reads: Default::default(), }; + + // As noted in `lower_coroutine_body_with_moved_arguments`, we default the capture mode + // to `ByRef` for the `async {}` block internal to async fns/closure. This means + // that we would *not* be moving all of the parameters into the async block by default. + // + // We force all of these arguments to be captured by move before we do expr use analysis. + // + // FIXME(async_closures): This could be cleaned up. It's a bit janky that we're just + // moving all of the `LocalSource::AsyncFn` locals here. + if let Some(hir::CoroutineKind::Desugared( + _, + hir::CoroutineSource::Fn | hir::CoroutineSource::Closure, + )) = self.tcx.coroutine_kind(closure_def_id) + { + let hir::ExprKind::Block(block, _) = body.value.kind else { + bug!(); + }; + for stmt in block.stmts { + let hir::StmtKind::Local(hir::Local { + init: Some(init), + source: hir::LocalSource::AsyncFn, + pat, + .. + }) = stmt.kind + else { + bug!(); + }; + let hir::PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), _, _, _) = + pat.kind + else { + // Complex pattern, skip the non-upvar local. + continue; + }; + let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = init.kind else { + bug!(); + }; + let hir::def::Res::Local(local_id) = path.res else { + bug!(); + }; + let place = self.place_for_root_variable(closure_def_id, local_id); + delegate.capture_information.push(( + place, + ty::CaptureInfo { + capture_kind_expr_id: Some(init.hir_id), + path_expr_id: Some(init.hir_id), + capture_kind: UpvarCapture::ByValue, + }, + )); + } + } + euv::ExprUseVisitor::new( &mut delegate, &self.infcx, diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs index f8ff9186842b8..c02bac2d7dd49 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -1,10 +1,10 @@ // edition:2018 -// check-pass #![feature(async_closure)] fn foo() -> Box> { let x = 0u32; Box::new((async || x)()) + //~^ ERROR closure may outlive the current function, but it borrows `x`, which is owned by the current function } fn main() { diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr new file mode 100644 index 0000000000000..87851e1ae5be5 --- /dev/null +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-borrowck-escaping-closure-error.rs:6:15 + | +LL | Box::new((async || x)()) + | ^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/async-borrowck-escaping-closure-error.rs:6:5 + | +LL | Box::new((async || x)()) + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | Box::new((async move || x)()) + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs index 95683241aba26..2d453e7891e5f 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs @@ -12,6 +12,7 @@ pub async fn async_fn(x: &mut i32) -> &i32 { pub fn async_closure(x: &mut i32) -> impl Future { (async move || { + //~^ captured variable cannot escape `FnMut` closure body let y = &*x; *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed y @@ -20,6 +21,7 @@ pub fn async_closure(x: &mut i32) -> impl Future { pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future { (async move || -> &i32 { + //~^ captured variable cannot escape `FnMut` closure body let y = &*x; *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed y diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr index 628ba1a481893..9120d78164e88 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -11,7 +11,7 @@ LL | y | - returning this value requires that `*x` is borrowed for `'1` error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:17:9 | LL | let y = &*x; | --- `*x` is borrowed here @@ -22,11 +22,32 @@ LL | y LL | })() | - return type of async closure is &'1 i32 +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-74072-lifetime-name-annotations.rs:14:20 + | +LL | pub fn async_closure(x: &mut i32) -> impl Future { + | - variable defined here +LL | (async move || { + | __________________-_^ + | | | + | | inferred to be a `FnMut` closure +LL | | +LL | | let y = &*x; + | | - variable captured here +LL | | *x += 1; +LL | | y +LL | | })() + | |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:24:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:26:9 | LL | (async move || -> &i32 { | - let's call the lifetime of this reference `'1` +LL | LL | let y = &*x; | --- `*x` is borrowed here LL | *x += 1; @@ -34,8 +55,28 @@ LL | *x += 1; LL | y | - returning this value requires that `*x` is borrowed for `'1` +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-74072-lifetime-name-annotations.rs:23:28 + | +LL | pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future { + | - variable defined here +LL | (async move || -> &i32 { + | __________________________-_^ + | | | + | | inferred to be a `FnMut` closure +LL | | +LL | | let y = &*x; + | | - variable captured here +LL | | *x += 1; +LL | | y +LL | | })() + | |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:32:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:34:9 | LL | let y = &*x; | --- `*x` is borrowed here @@ -46,6 +87,6 @@ LL | y LL | } | - return type of async block is &'1 i32 -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs index a9d678c1e6aff..66a432be35737 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs @@ -9,7 +9,7 @@ impl Numberer { //~^ ERROR `async fn` is not permitted in Rust 2015 interval: Duration, //~^ ERROR cannot find type `Duration` in this scope - ) -> Numberer { //~WARN: changes to closure capture in Rust 2021 + ) -> Numberer { Numberer {} } } diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr index 71e9e7602e8e7..60433e1c28467 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -18,32 +18,7 @@ help: consider importing this struct LL + use std::time::Duration; | -warning: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19 - | -LL | interval: Duration, - | -------- in Rust 2018, this causes the closure to capture `interval`, but in Rust 2021, it has no effect -LL | -LL | ) -> Numberer { - | _________________-_^ - | | | - | | in Rust 2018, `interval` is dropped here along with the closure, but in Rust 2021 `interval` is not part of the closure -LL | | Numberer {} -LL | | } - | |_____^ - | - = note: for more information, see -note: the lint level is defined here - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:1:9 - | -LL | #![warn(rust_2021_incompatible_closure_captures)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: add a dummy let to cause `interval` to be fully captured - | -LL | ) -> Numberer { let _ = &interval; - | ++++++++++++++++++ - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0412, E0670. For more information about an error, try `rustc --explain E0412`. From a20421734bb41437598aa3a959ed20441c3fb7f3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 24 Jan 2024 17:30:02 +0000 Subject: [PATCH 061/101] Make async closures directly lower to ClosureKind::CoroutineClosure --- compiler/rustc_ast_lowering/messages.ftl | 3 - compiler/rustc_ast_lowering/src/errors.rs | 7 -- compiler/rustc_ast_lowering/src/expr.rs | 27 ++---- compiler/rustc_ast_lowering/src/item.rs | 4 +- compiler/rustc_ast_lowering/src/lib.rs | 3 +- .../src/diagnostics/conflict_errors.rs | 23 +++-- .../rustc_borrowck/src/diagnostics/mod.rs | 4 +- .../src/diagnostics/region_name.rs | 15 +++- compiler/rustc_hir/src/hir.rs | 5 ++ .../src/collect/generics_of.rs | 1 + compiler/rustc_hir_typeck/src/closure.rs | 6 +- .../error_reporting/type_err_ctxt_ext.rs | 83 ++++++++++--------- 12 files changed, 93 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 8615016cda599..cee6525a86a5d 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -117,9 +117,6 @@ ast_lowering_never_pattern_with_guard = a guard on a never pattern will never be run .suggestion = remove this guard -ast_lowering_not_supported_for_lifetime_binder_async_closure = - `for<...>` binders on `async` closures are not currently supported - ast_lowering_previously_used_here = previously used here ast_lowering_register1 = register `{$reg1_name}` diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 51bb8a96fad26..afd156bd6f11b 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -326,13 +326,6 @@ pub struct MisplacedRelaxTraitBound { pub span: Span, } -#[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)] -pub struct NotSupportedForLifetimeBinderAsyncClosure { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_lowering_match_arm_with_no_body)] pub struct MatchArmWithNoBody { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0ad4a59c17eb1..2241b4cd8e504 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2,8 +2,7 @@ use super::errors::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, - NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, - UnderscoreExprLhsAssign, + NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; @@ -1026,30 +1025,21 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, fn_arg_span: Span, ) -> hir::ExprKind<'hir> { - if let &ClosureBinder::For { span, .. } = binder { - self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); - } - let (binder_clause, generic_params) = self.lower_closure_binder(binder); let body = self.with_new_scopes(fn_decl_span, |this| { + let inner_decl = + FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; + // Transform `async |x: u8| -> X { ... }` into // `|x: u8| || -> X { ... }`. let body_id = this.lower_body(|this| { - let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output { - let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock); - Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx))) - } else { - None - }; - let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( - decl, + &inner_decl, |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), body.span, coroutine_kind, hir::CoroutineSource::Closure, - async_ret_ty, ); let hir_id = this.lower_node_id(coroutine_kind.closure_id()); @@ -1060,15 +1050,12 @@ impl<'hir> LoweringContext<'_, 'hir> { body_id }); - let outer_decl = - FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. let fn_decl = - self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); + self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); let c = self.arena.alloc(hir::Closure { def_id: self.local_def_id(closure_id), @@ -1079,7 +1066,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), - kind: hir::ClosureKind::Closure, + kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async), constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a122b4c51133c..f347b2ec81b78 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1086,7 +1086,6 @@ impl<'hir> LoweringContext<'_, 'hir> { body.span, coroutine_kind, hir::CoroutineSource::Fn, - None, ); // FIXME(async_fn_track_caller): Can this be moved above? @@ -1108,7 +1107,6 @@ impl<'hir> LoweringContext<'_, 'hir> { body_span: Span, coroutine_kind: CoroutineKind, coroutine_source: hir::CoroutineSource, - return_type_hint: Option>, ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) { let mut parameters: Vec> = Vec::new(); let mut statements: Vec> = Vec::new(); @@ -1284,7 +1282,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // all async closures would default to `FnOnce` as their calling mode. CaptureBy::Ref, closure_id, - return_type_hint, + None, body_span, desugaring_kind, coroutine_source, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f26b1331ef388..0ea7d109182c3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -33,6 +33,7 @@ #![allow(internal_features)] #![feature(rustdoc_internals)] #![doc(rust_logo)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(let_chains)] #![deny(rustc::untranslatable_diagnostic)] @@ -296,7 +297,6 @@ enum ImplTraitPosition { Path, Variable, Trait, - AsyncBlock, Bound, Generic, ExternFnParam, @@ -323,7 +323,6 @@ impl std::fmt::Display for ImplTraitPosition { ImplTraitPosition::Path => "paths", ImplTraitPosition::Variable => "the type of variable bindings", ImplTraitPosition::Trait => "traits", - ImplTraitPosition::AsyncBlock => "async blocks", ImplTraitPosition::Bound => "bounds", ImplTraitPosition::Generic => "generics", ImplTraitPosition::ExternFnParam => "`extern fn` parameters", diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b0b7cc076bab5..6debb3362b04c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -858,7 +858,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span }, - hir::ClosureKind::Closure => MoveUseInClosure { var_span }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + MoveUseInClosure { var_span } + } } }); @@ -905,7 +907,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true } } } @@ -1056,7 +1058,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { var_span, is_single_var: true, }, - hir::ClosureKind::Closure => BorrowUsePlaceClosure { + hir::ClosureKind::Closure + | hir::ClosureKind::CoroutineClosure(_) => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true, @@ -1140,7 +1143,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { var_span, is_single_var: false, }, - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false } } } @@ -1158,7 +1161,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } } } @@ -1175,7 +1178,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { SecondBorrowUsePlaceClosure { place: desc_place, var_span } } } @@ -2942,7 +2945,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, - hir::ClosureKind::Closure => BorrowUseInClosure { var_span }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + BorrowUseInClosure { var_span } + } } }); @@ -2958,7 +2963,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, - hir::ClosureKind::Closure => BorrowUseInClosure { var_span }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + BorrowUseInClosure { var_span } + } } }); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index b35d4e16eccb0..59f3aa706edea 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -614,7 +614,7 @@ impl UseSpans<'_> { PartialAssignment => AssignPartInCoroutine { path_span }, }); } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { err.subdiagnostic(match action { Borrow => BorrowInClosure { path_span }, MatchOn | Use => UseInClosure { path_span }, @@ -1253,7 +1253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { hir::ClosureKind::Coroutine(_) => { CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial } } - hir::ClosureKind::Closure => { + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial } } }) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 15e1066e983a9..fc52306e10d0b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -692,7 +692,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, hir::CoroutineSource::Closure, - )) => " of async closure", + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => { + " of async closure" + } hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, @@ -719,7 +722,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure, - )) => " of gen closure", + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => { + " of gen closure" + } hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Gen, @@ -743,7 +749,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Closure, - )) => " of async gen closure", + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => { + " of async gen closure" + } hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::AsyncGen, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index de1b28acb1267..539ab5464e961 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -952,6 +952,11 @@ pub enum ClosureKind { /// usage (e.g. `let x = || { yield (); }`) or from a desugared expression /// (e.g. `async` and `gen` blocks). Coroutine(CoroutineKind), + /// This is a coroutine-closure, which is a special sugared closure that + /// returns one of the sugared coroutine (`async`/`gen`/`async gen`). It + /// additionally allows capturing the coroutine's upvars by ref, and therefore + /// needs to be specially treated during analysis and borrowck. + CoroutineClosure(CoroutineDesugaring), } /// A block of statements `{ .. }`, which may have a label (in this case the diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index c29d413184304..d7e91673c7a29 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -349,6 +349,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ClosureKind::Coroutine(_) => { &["", "", "", "", ""][..] } + ClosureKind::CoroutineClosure(_) => todo!(), }; params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index f51cc97b45deb..18dff5188af94 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -192,6 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(CoroutineTypes { resume_ty, yield_ty }), ) } + hir::ClosureKind::CoroutineClosure(_) => todo!(), }; check_fn( @@ -690,7 +691,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _, )) | hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) - | hir::ClosureKind::Closure => astconv.ty_infer(None, decl.output.span()), + | hir::ClosureKind::Closure + | hir::ClosureKind::CoroutineClosure(_) => { + astconv.ty_infer(None, decl.output.span()) + } }, }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index a8715b0764f0a..d57d9f58333c9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1924,45 +1924,50 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str { match kind { hir::ClosureKind::Closure => "a closure", - hir::ClosureKind::Coroutine(kind) => match kind { - hir::CoroutineKind::Coroutine(_) => "a coroutine", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) => "an async block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Fn, - ) => "an async function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure, - ) => "an async closure", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Block, - ) => "an async gen block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Fn, - ) => "an async gen function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Closure, - ) => "an async gen closure", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Block, - ) => "a gen block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Fn, - ) => "a gen function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Closure, - ) => "a gen closure", - }, + hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + )) => "an async block", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + )) => "an async function", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => { + "an async closure" + } + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Block, + )) => "an async gen block", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Fn, + )) => "an async gen function", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Closure, + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => { + "an async gen closure" + } + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Block, + )) => "a gen block", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Fn, + )) => "a gen function", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Closure, + )) + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => "a gen closure", } } From c567eddec2c628d4f13707866731e1b2013ad236 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 24 Jan 2024 18:01:56 +0000 Subject: [PATCH 062/101] Add CoroutineClosure to TyKind, AggregateKind, UpvarArgs --- .../src/diagnostics/mutability_errors.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 10 +- compiler/rustc_borrowck/src/path_utils.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 33 ++++- compiler/rustc_codegen_gcc/src/type_of.rs | 2 +- compiler/rustc_codegen_llvm/src/type_of.rs | 2 +- .../src/debuginfo/type_names.rs | 6 +- .../src/const_eval/valtrees.rs | 2 + .../src/interpret/eval_context.rs | 1 + .../src/interpret/intrinsics.rs | 1 + .../src/interpret/validity.rs | 1 + .../src/transform/validate.rs | 22 ++++ .../rustc_const_eval/src/util/type_name.rs | 1 + compiler/rustc_hir/src/hir.rs | 1 + .../src/coherence/inherent_impls.rs | 1 + .../src/coherence/orphan.rs | 1 + .../src/collect/generics_of.rs | 8 +- .../src/variance/constraints.rs | 4 +- compiler/rustc_hir_typeck/src/callee.rs | 12 +- compiler/rustc_hir_typeck/src/cast.rs | 1 + .../rustc_hir_typeck/src/method/suggest.rs | 1 + compiler/rustc_hir_typeck/src/upvar.rs | 22 ++-- .../src/infer/canonical/canonicalizer.rs | 1 + .../src/infer/error_reporting/mod.rs | 10 +- .../infer/error_reporting/need_type_info.rs | 5 +- .../infer/error_reporting/note_and_explain.rs | 7 +- compiler/rustc_infer/src/infer/mod.rs | 10 +- .../rustc_infer/src/infer/opaque_types.rs | 11 ++ .../src/infer/outlives/components.rs | 5 + compiler/rustc_lint/src/types.rs | 1 + compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 3 +- compiler/rustc_middle/src/mir/syntax.rs | 1 + compiler/rustc_middle/src/mir/tcx.rs | 3 + compiler/rustc_middle/src/mir/visit.rs | 6 + compiler/rustc_middle/src/ty/context.rs | 1 + compiler/rustc_middle/src/ty/error.rs | 2 +- compiler/rustc_middle/src/ty/fast_reject.rs | 7 +- compiler/rustc_middle/src/ty/flags.rs | 16 +++ compiler/rustc_middle/src/ty/generic_args.rs | 10 +- compiler/rustc_middle/src/ty/layout.rs | 6 + compiler/rustc_middle/src/ty/print/mod.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 42 +++++++ compiler/rustc_middle/src/ty/relate.rs | 7 ++ .../rustc_middle/src/ty/structural_impls.rs | 4 + compiler/rustc_middle/src/ty/sty.rs | 116 +++++++++++++++++- compiler/rustc_middle/src/ty/util.rs | 15 ++- compiler/rustc_middle/src/ty/walk.rs | 1 + .../src/build/expr/as_rvalue.rs | 3 + compiler/rustc_mir_build/src/build/mod.rs | 2 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 3 + .../src/move_paths/builder.rs | 8 +- .../src/abort_unwinding_calls.rs | 1 + .../rustc_mir_transform/src/check_unsafety.rs | 4 +- .../src/dataflow_const_prop.rs | 1 + .../src/ffi_unwind_calls.rs | 1 + compiler/rustc_mir_transform/src/gvn.rs | 11 +- .../rustc_mir_transform/src/remove_zsts.rs | 1 + .../src/canonicalizer.rs | 3 +- compiler/rustc_passes/src/liveness.rs | 5 + compiler/rustc_pattern_analysis/src/rustc.rs | 3 +- compiler/rustc_privacy/src/lib.rs | 1 + .../rustc_smir/src/rustc_smir/convert/mir.rs | 3 + .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 + compiler/rustc_symbol_mangling/src/legacy.rs | 7 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 8 +- compiler/rustc_symbol_mangling/src/v0.rs | 1 + .../src/solve/assembly/mod.rs | 5 +- .../src/solve/assembly/structural_traits.rs | 9 ++ .../src/solve/normalizes_to/mod.rs | 2 + .../src/solve/trait_goals.rs | 3 +- .../src/traits/coherence.rs | 2 +- .../error_reporting/type_err_ctxt_ext.rs | 6 +- .../src/traits/project.rs | 2 + .../src/traits/query/dropck_outlives.rs | 20 +++ .../src/traits/select/candidate_assembly.rs | 18 ++- .../src/traits/select/mod.rs | 9 ++ .../src/traits/structural_match.rs | 3 + .../rustc_trait_selection/src/traits/wf.rs | 8 ++ compiler/rustc_ty_utils/src/instance.rs | 1 + compiler/rustc_ty_utils/src/layout.rs | 11 ++ compiler/rustc_ty_utils/src/needs_drop.rs | 6 + compiler/rustc_ty_utils/src/ty.rs | 4 +- compiler/rustc_type_ir/src/ty_kind.rs | 28 +++-- src/librustdoc/clean/mod.rs | 1 + .../passes/collect_intra_doc_links.rs | 1 + .../clippy/clippy_lints/src/dereference.rs | 1 + .../clippy/clippy_lints/src/utils/author.rs | 3 + .../clippy/tests/ui/author/blocks.stdout | 4 +- .../internal-lints/ty_tykind_usage.rs | 1 + .../internal-lints/ty_tykind_usage.stderr | 36 +++--- 91 files changed, 579 insertions(+), 101 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 3fddf67f55b97..55649ec2f1645 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1472,7 +1472,7 @@ fn suggest_ampmut<'tcx>( } fn is_closure_or_coroutine(ty: Ty<'_>) -> bool { - ty.is_closure() || ty.is_coroutine() + ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() } /// Given a field that needs to be mutable, returns a span where the " mut " could go. diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8b5e548345c97..eaf9fc4583720 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1303,7 +1303,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // moved into the closure and subsequently used by the closure, // in order to populate our used_mut set. match **aggregate_kind { - AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => { + AggregateKind::Closure(def_id, _) + | AggregateKind::CoroutineClosure(def_id, _) + | AggregateKind::Coroutine(def_id, _) => { let def_id = def_id.expect_local(); let BorrowCheckResult { used_mut_upvars, .. } = self.infcx.tcx.mir_borrowck(def_id); @@ -1609,6 +1611,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::FnPtr(_) | ty::Dynamic(_, _, _) | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -1633,7 +1636,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return; } } - ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (), + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(_, _) + | ty::Tuple(_) => (), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index 2d997dfadf004..4cfde47664eee 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -164,7 +164,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>( match place_ref.last_projection() { Some((place_base, ProjectionElem::Field(field, _ty))) => { let base_ty = place_base.ty(body, tcx).ty; - if (base_ty.is_closure() || base_ty.is_coroutine()) + if (base_ty.is_closure() || base_ty.is_coroutine() || base_ty.is_coroutine_closure()) && (!by_ref || upvars[field.index()].is_by_ref()) { Some(field) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 59c4d9a6c78ca..90a9844fda9e4 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -808,6 +808,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }), }; } + ty::CoroutineClosure(_, args) => { + return match args.as_coroutine_closure().upvar_tys().get(field.index()) { + Some(&ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: args.as_coroutine_closure().upvar_tys().len(), + }), + }; + } ty::Coroutine(_, args) => { // Only prefix fields (upvars and current state) are // accessible without a variant index. @@ -1875,6 +1883,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }), } } + AggregateKind::CoroutineClosure(_, args) => { + match args.as_coroutine_closure().upvar_tys().get(field_index.as_usize()) { + Some(ty) => Ok(*ty), + None => Err(FieldAccessError::OutOfRange { + field_count: args.as_coroutine_closure().upvar_tys().len(), + }), + } + } AggregateKind::Array(ty) => Ok(ty), AggregateKind::Tuple => { unreachable!("This should have been covered in check_rvalues"); @@ -2478,6 +2494,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { AggregateKind::Tuple => None, AggregateKind::Closure(_, _) => None, AggregateKind::Coroutine(_, _) => None, + AggregateKind::CoroutineClosure(_, _) => None, }, } } @@ -2705,7 +2722,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // desugaring. A closure gets desugared to a struct, and // these extra requirements are basically like where // clauses on the struct. - AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => ( + AggregateKind::Closure(def_id, args) + | AggregateKind::CoroutineClosure(def_id, args) + | AggregateKind::Coroutine(def_id, args) => ( def_id, self.prove_closure_bounds( tcx, @@ -2754,10 +2773,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id); let parent_args = match tcx.def_kind(def_id) { - DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => { - args.as_coroutine().parent_args() + DefKind::Closure => { + // FIXME(async_closures): It's kind of icky to access HIR here. + match tcx.hir_node_by_def_id(def_id).expect_closure().kind { + hir::ClosureKind::Closure => args.as_closure().parent_args(), + hir::ClosureKind::Coroutine(_) => args.as_coroutine().parent_args(), + hir::ClosureKind::CoroutineClosure(_) => { + args.as_coroutine_closure().parent_args() + } + } } - DefKind::Closure => args.as_closure().parent_args(), DefKind::InlineConst => args.as_inline_const().parent_args(), other => bug!("unexpected item {:?}", other), }; diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index e5c0b2de4ca46..25149b8020162 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -87,7 +87,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str if !cx.sess().fewer_names() => { let mut name = with_no_trimmed_paths!(layout.ty.to_string()); diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index e88f4217c9dca..219c702531141 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -33,7 +33,7 @@ fn uncached_llvm_type<'a, 'tcx>( // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str // For performance reasons we use names only when emitting LLVM IR. if !cx.sess().fewer_names() => { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 4f9f70648bd88..5bd7442822a21 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -398,7 +398,9 @@ fn push_debuginfo_type_name<'tcx>( // processing visited.remove(&t); } - ty::Closure(def_id, args) | ty::Coroutine(def_id, args, ..) => { + ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) + | ty::Coroutine(def_id, args, ..) => { // Name will be "{closure_env#0}", "{coroutine_env#0}", or // "{async_fn_env#0}", etc. // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of @@ -768,6 +770,8 @@ fn push_closure_or_coroutine_name<'tcx>( // Truncate the args to the length of the above generics. This will cut off // anything closure- or coroutine-specific. + // FIXME(async_closures): This is probably not going to be correct w.r.t. + // multiple coroutine flavors. Maybe truncate to (parent + 1)? let args = args.truncate_to(tcx, generics); push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited); } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 12544f5b02955..5c2bf4626c4c3 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -172,6 +172,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( | ty::Infer(_) // FIXME(oli-obk): we can probably encode closures just like structs | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType), } @@ -301,6 +302,7 @@ pub fn valtree_to_const_value<'tcx>( | ty::Placeholder(..) | ty::Infer(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::FnPtr(_) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index c14bd142efacc..dd989ab80fd3c 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1007,6 +1007,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Error(_) => true, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 1e9e7d94596f8..7991f90b81549 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -85,6 +85,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::FnPtr(_) | ty::Dynamic(_, _, _) | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b5cd32595201f..811c2c3c208e0 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -644,6 +644,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Str | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) => Ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 21bdb66a27631..d3230a2455df3 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -665,6 +665,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; check_equal(self, location, f_ty); } + ty::CoroutineClosure(_, args) => { + let args = args.as_coroutine_closure(); + let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else { + fail_out_of_bounds(self, location); + return; + }; + check_equal(self, location, f_ty); + } &ty::Coroutine(def_id, args) => { let f_ty = if let Some(var) = parent_ty.variant_index { let gen_body = if def_id == self.body.source.def_id() { @@ -861,6 +869,20 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } + AggregateKind::CoroutineClosure(_, args) => { + let upvars = args.as_coroutine_closure().upvar_tys(); + if upvars.len() != fields.len() { + self.fail( + location, + "coroutine-closure has the wrong number of initialized fields", + ); + } + for (src, dest) in std::iter::zip(fields, upvars) { + if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { + self.fail(location, "coroutine-closure field has the wrong type"); + } + } + } }, Rvalue::Ref(_, BorrowKind::Fake, _) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 976e42ad76836..2b80623ab4545 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -51,6 +51,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 539ab5464e961..ff50086ff8f98 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3703,6 +3703,7 @@ impl<'hir> Node<'hir> { expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n; expect_crate, &'hir Mod<'hir>, Node::Crate(n), n; expect_infer, &'hir InferArg, Node::Infer(n), n; + expect_closure, &'hir Closure<'hir>, Node::Expr(Expr { kind: ExprKind::Closure(n), .. }), n; } } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index abef365c3ca3c..0df5a57bc2c45 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -171,6 +171,7 @@ impl<'tcx> InherentCollect<'tcx> { } ty::FnDef(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bound(..) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1736de760d5a6..45641be52d2f2 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -244,6 +244,7 @@ fn do_orphan_check_impl<'tcx>( | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther), ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bound(..) diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index d7e91673c7a29..1dabb6feb5e1b 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -349,7 +349,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ClosureKind::Coroutine(_) => { &["", "", "", "", ""][..] } - ClosureKind::CoroutineClosure(_) => todo!(), + ClosureKind::CoroutineClosure(_) => &[ + "", + "", + "", + "", + "", + ][..], }; params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index f09594cbbc667..580cdb4a3a209 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -235,8 +235,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // leaf type -- noop } - ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) => { - bug!("Unexpected closure type in variance computation"); + ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => { + bug!("Unexpected coroutine/closure type in variance computation"); } ty::Ref(region, ty, mutbl) => { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index b263c98553421..80650dcb53c3f 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check whether this is a call to a closure where we // haven't yet decided on whether the closure is fn vs // fnmut vs fnonce. If so, we have to defer further processing. - if self.closure_kind(args).is_none() { + if self.closure_kind(adjusted_ty).is_none() { let closure_sig = args.as_closure().sig(); let closure_sig = self.instantiate_binder_with_fresh_vars( call_expr.span, @@ -160,10 +160,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { DeferredCallResolution { call_expr, callee_expr, - adjusted_ty, + closure_ty: adjusted_ty, adjustments, fn_sig: closure_sig, - closure_args: args, }, ); return Some(CallStep::DeferredClosure(def_id, closure_sig)); @@ -886,10 +885,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub struct DeferredCallResolution<'tcx> { call_expr: &'tcx hir::Expr<'tcx>, callee_expr: &'tcx hir::Expr<'tcx>, - adjusted_ty: Ty<'tcx>, + closure_ty: Ty<'tcx>, adjustments: Vec>, fn_sig: ty::FnSig<'tcx>, - closure_args: GenericArgsRef<'tcx>, } impl<'a, 'tcx> DeferredCallResolution<'tcx> { @@ -898,10 +896,10 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { // we should not be invoked until the closure kind has been // determined by upvar inference - assert!(fcx.closure_kind(self.closure_args).is_some()); + assert!(fcx.closure_kind(self.closure_ty).is_some()); // We may now know enough to figure out fn vs fnmut etc. - match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) { + match fcx.try_overloaded_call_traits(self.call_expr, self.closure_ty, None) { Some((autoref, method_callee)) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index a0ac839f3dd2c..58823ea30ce57 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -133,6 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Adt(..) | ty::Never diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 904961d9eba26..2a1c417a16b9c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -57,6 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.kind() { // Not all of these (e.g., unsafe fns) implement `FnOnce`, // so we look for these beforehand. + // FIXME(async_closures): These don't impl `FnOnce` by default. ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true, // If it's not a simple function, look for things which implement `FnOnce`. _ => { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 864acf51025b5..55ffac8d92f87 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -170,9 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); - let (closure_def_id, args) = match *ty.kind() { - ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args)), - ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args)), + let (closure_def_id, args, infer_kind) = match *ty.kind() { + ty::Closure(def_id, args) => { + (def_id, UpvarArgs::Closure(args), self.closure_kind(ty).is_none()) + } + ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args), false), ty::Error(_) => { // #51714: skip analysis when we have already encountered type errors return; @@ -188,12 +190,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let closure_def_id = closure_def_id.expect_local(); - let infer_kind = if let UpvarArgs::Closure(closure_args) = args { - self.closure_kind(closure_args).is_none().then_some(closure_args) - } else { - None - }; - assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id); let mut delegate = InferBorrowKind { closure_def_id, @@ -308,10 +304,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let before_feature_tys = self.final_upvar_tys(closure_def_id); - if let Some(closure_args) = infer_kind { + if infer_kind { // Unify the (as yet unbound) type variable in the closure // args with the kind we inferred. - let closure_kind_ty = closure_args.as_closure().kind_ty(); + let closure_kind_ty = match args { + UpvarArgs::Closure(args) => args.as_closure().kind_ty(), + UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().kind_ty(), + UpvarArgs::Coroutine(_) => unreachable!("coroutines don't have an inferred kind"), + }; self.demand_eqtype( span, Ty::from_closure_kind(self.tcx, closure_kind), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e4b37f05b778f..d825a2920eefb 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -414,6 +414,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bool diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b8344310d5dfd..cf9d93337839e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2839,7 +2839,11 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => Error0644, + TypeError::CyclicTy(ty) + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => + { + Error0644 + } TypeError::IntrinsicCast => Error0308, _ => Error0308, }, @@ -2886,7 +2890,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => { + TypeError::CyclicTy(ty) + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => + { ObligationCauseFailureCode::ClosureSelfref { span } } TypeError::IntrinsicCast => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 7287fc26053fe..c637ab31cd214 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -883,7 +883,10 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { GenericArgKind::Type(ty) => { if matches!( ty.kind(), - ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Coroutine(..) + ty::Alias(ty::Opaque, ..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) ) { // Opaque types can't be named by the user right now. // diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 0452d4fe6c806..f884ca83073df 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -228,7 +228,10 @@ impl Trait for X { #traits-as-parameters", ); } - (ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => { + ( + ty::Param(p), + ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..), + ) => { let generics = tcx.generics_of(body_owner_def_id); if let Some(param) = generics.opt_type_param(p, tcx) { let p_span = tcx.def_span(param.def_id); @@ -497,7 +500,7 @@ impl Trait for X { } CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. - if ty.is_closure() || ty.is_coroutine() { + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() { diag.note( "closures cannot capture themselves or take themselves as argument;\n\ this error may be the result of a recent compiler bug-fix,\n\ diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 0a39fe007fd22..101735b2961f0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1538,9 +1538,13 @@ impl<'tcx> InferCtxt<'tcx> { /// Obtains the latest type of the given closure; this may be a /// closure in the current function, in which case its /// `ClosureKind` may not yet be known. - pub fn closure_kind(&self, closure_args: GenericArgsRef<'tcx>) -> Option { - let closure_kind_ty = closure_args.as_closure().kind_ty(); - let closure_kind_ty = self.shallow_resolve(closure_kind_ty); + pub fn closure_kind(&self, closure_ty: Ty<'tcx>) -> Option { + let unresolved_kind_ty = match *closure_ty.kind() { + ty::Closure(_, args) => args.as_closure().kind_ty(), + ty::CoroutineClosure(_, args) => args.as_coroutine_closure().kind_ty(), + _ => bug!("unexpected type {closure_ty}"), + }; + let closure_kind_ty = self.shallow_resolve(unresolved_kind_ty); closure_kind_ty.to_opt_closure_kind() } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index db46b39ce25fc..5ee0a606a5f57 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -456,6 +456,17 @@ where args.as_closure().sig_as_fn_ptr_ty().visit_with(self); } + ty::CoroutineClosure(_, args) => { + // Skip lifetime parameters of the enclosing item(s) + + for upvar in args.as_coroutine_closure().upvar_tys() { + upvar.visit_with(self); + } + + // FIXME(async_closures): Is this the right signature to visit here? + args.as_coroutine_closure().signature_parts_ty().visit_with(self); + } + ty::Coroutine(_, args) => { // Skip lifetime parameters of the enclosing item(s) // Also skip the witness type, because that has no free regions. diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index fc3d8375873b0..7dd1ec3254220 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -103,6 +103,11 @@ fn compute_components<'tcx>( compute_components(tcx, tupled_ty, out, visited); } + ty::CoroutineClosure(_, args) => { + let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); + } + ty::Coroutine(_, args) => { // Same as the closure case let tupled_ty = args.as_coroutine().tupled_upvars_ty(); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index e3d3150b36ef4..1205395b8908d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1435,6 +1435,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ty::Bound(..) | ty::Error(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Placeholder(..) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index ea3747dfac4b3..9f670893b270d 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -355,7 +355,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { Some(len) => is_ty_must_use(cx, ty, expr, span) .map(|inner| MustUsePath::Array(Box::new(inner), len)), }, - ty::Closure(..) => Some(MustUsePath::Closure(span)), + ty::Closure(..) | ty::CoroutineClosure(..) => Some(MustUsePath::Closure(span)), ty::Coroutine(def_id, ..) => { // async fn should be treated as "implementor of `Future`" let must_use = if cx.tcx.coroutine_is_async(def_id) { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 3b60eba2dfe0a..6f587fdd53c61 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -990,7 +990,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { }) } - AggregateKind::Closure(def_id, args) => ty::tls::with(|tcx| { + AggregateKind::Closure(def_id, args) + | AggregateKind::CoroutineClosure(def_id, args) => ty::tls::with(|tcx| { let name = if tcx.sess.opts.unstable_opts.span_free_formats { let args = tcx.lift(args).unwrap(); format!("{{closure@{}}}", tcx.def_path_str_with_args(def_id, args),) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index a4b6c4f9c3f19..ca56e1fd92c6b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1350,6 +1350,7 @@ pub enum AggregateKind<'tcx> { Closure(DefId, GenericArgsRef<'tcx>), Coroutine(DefId, GenericArgsRef<'tcx>), + CoroutineClosure(DefId, GenericArgsRef<'tcx>), } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 5597609c7d796..4780042a51090 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -202,6 +202,9 @@ impl<'tcx> Rvalue<'tcx> { AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args), AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args), AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args), + AggregateKind::CoroutineClosure(did, args) => { + Ty::new_coroutine_closure(tcx, did, args) + } }, Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 4696f54c89787..591104ecc663d 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -739,6 +739,12 @@ macro_rules! make_mir_visitor { ) => { self.visit_args(coroutine_args, location); } + AggregateKind::CoroutineClosure( + _, + coroutine_closure_args, + ) => { + self.visit_args(coroutine_closure_args, location); + } } for operand in operands { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0d53870a0baf0..14d2a93e16714 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1544,6 +1544,7 @@ impl<'tcx> TyCtxt<'tcx> { CoroutineWitness, Dynamic, Closure, + CoroutineClosure, Tuple, Bound, Param, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 0e44878524bf0..80b763d1469e4 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -299,7 +299,7 @@ impl<'tcx> Ty<'tcx> { }, ty::FnPtr(_) => "fn pointer".into(), ty::Dynamic(..) => "trait object".into(), - ty::Closure(..) => "closure".into(), + ty::Closure(..) | ty::CoroutineClosure(..) => "closure".into(), ty::Coroutine(def_id, ..) => { format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into() } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index b71919adc58fa..adc153c4dfd2d 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -128,7 +128,9 @@ pub fn simplify_type<'tcx>( _ => Some(SimplifiedType::MarkerTraitObject), }, ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)), - ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)), + ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => { + Some(SimplifiedType::Closure(def_id)) + } ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)), ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)), ty::Never => Some(SimplifiedType::Never), @@ -236,6 +238,7 @@ impl DeepRejectCtxt { | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()), ty::FnDef(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Placeholder(..) @@ -312,7 +315,7 @@ impl DeepRejectCtxt { }, // Impls cannot contain these types as these cannot be named directly. - ty::FnDef(..) | ty::Closure(..) | ty::Coroutine(..) => false, + ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false, // Placeholder types don't unify with anything on their own ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0c1d10914146f..deb6e73ea7142 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -136,6 +136,22 @@ impl FlagComputation { self.add_ty(args.tupled_upvars_ty()); } + &ty::CoroutineClosure(_, args) => { + let args = args.as_coroutine_closure(); + let should_remove_further_specializable = + !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_args(args.parent_args()); + if should_remove_further_specializable { + self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; + } + + self.add_ty(args.signature_parts_ty()); + self.add_ty(args.coroutine_witness_ty()); + self.add_ty(args.coroutine_captures_by_ref_ty()); + self.add_ty(args.kind_ty()); + self.add_ty(args.tupled_upvars_ty()); + } + &ty::Bound(debruijn, _) => { self.add_bound_var(debruijn); self.add_flags(TypeFlags::HAS_TY_BOUND); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 69ad6810c6fe0..b9fff660a03b9 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -2,7 +2,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; -use crate::ty::sty::{ClosureArgs, CoroutineArgs, InlineConstArgs}; +use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs}; use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; @@ -288,6 +288,14 @@ impl<'tcx> GenericArgs<'tcx> { ClosureArgs { args: self } } + /// Interpret these generic args as the args of a coroutine-closure type. + /// Coroutine-closure args have a particular structure controlled by the + /// compiler that encodes information like the signature and closure kind; + /// see `ty::CoroutineClosureArgs` struct for more comments. + pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs<'tcx> { + CoroutineClosureArgs { args: self } + } + /// Interpret these generic args as the args of a coroutine type. /// Coroutine args have a particular structure controlled by the /// compiler that encodes information like the signature and coroutine kind; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 73b0e324f13ca..8d8d06b7c0b7f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -906,6 +906,12 @@ where i, ), + ty::CoroutineClosure(_, args) => field_ty_or_layout( + TyAndLayout { ty: args.as_coroutine_closure().tupled_upvars_ty(), ..this }, + cx, + i, + ), + ty::Coroutine(def_id, args) => match this.variants { Variants::Single { index } => TyMaybeWithLayout::Ty( args.as_coroutine() diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index f32b7b0852abc..7026d2af29853 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -259,6 +259,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty::FnDef(def_id, _) | ty::Closure(def_id, _) + | ty::CoroutineClosure(def_id, _) | ty::Coroutine(def_id, _) | ty::CoroutineWitness(def_id, _) | ty::Foreign(def_id) => Some(def_id), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index bac5068a69b86..be6b887ba7dc6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -874,6 +874,48 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } p!("}}"); } + ty::CoroutineClosure(did, args) => { + p!(write("{{")); + if !self.should_print_verbose() { + p!(write("coroutine closure")); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + if self.tcx().sess.opts.unstable_opts.span_free_formats { + p!("@", print_def_path(did.to_def_id(), args)); + } else { + let span = self.tcx().def_span(did); + let preference = if with_forced_trimmed_paths() { + FileNameDisplayPreference::Short + } else { + FileNameDisplayPreference::Remapped + }; + p!(write( + "@{}", + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + self.tcx().sess.source_map().span_to_string(span, preference) + )); + } + } else { + p!(write("@"), print_def_path(did, args)); + } + } else { + p!(print_def_path(did, args)); + p!( + " closure_kind_ty=", + print(args.as_coroutine_closure().kind_ty()), + " signature_parts_ty=", + print(args.as_coroutine_closure().signature_parts_ty()), + " upvar_tys=", + print(args.as_coroutine_closure().tupled_upvars_ty()), + " coroutine_captures_by_ref_ty=", + print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + " coroutine_witness_ty=", + print(args.as_coroutine_closure().coroutine_witness_ty()) + ); + } + p!("}}"); + } ty::Array(ty, sz) => p!("[", print(ty), "; ", print(sz), "]"), ty::Slice(ty) => p!("[", print(ty), "]"), } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 8543bd0bbdd96..f2321e7e1d22f 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -481,6 +481,13 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_closure(tcx, a_id, args)) } + (&ty::CoroutineClosure(a_id, a_args), &ty::CoroutineClosure(b_id, b_args)) + if a_id == b_id => + { + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_closure(tcx, a_id, args)) + } + (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; Ok(Ty::new_ptr(tcx, mt)) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 11b579a1f85b6..c6805ba932357 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -584,6 +584,9 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { ty::CoroutineWitness(did, args.try_fold_with(folder)?) } ty::Closure(did, args) => ty::Closure(did, args.try_fold_with(folder)?), + ty::CoroutineClosure(did, args) => { + ty::CoroutineClosure(did, args.try_fold_with(folder)?) + } ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), ty::Bool @@ -632,6 +635,7 @@ impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { ty::Coroutine(_did, ref args) => args.visit_with(visitor), ty::CoroutineWitness(_did, ref args) => args.visit_with(visitor), ty::Closure(_did, ref args) => args.visit_with(visitor), + ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor), ty::Alias(_, ref data) => data.visit_with(visitor), ty::Bool diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f5fdf210592e8..c047f6a052151 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -269,6 +269,97 @@ impl<'tcx> ClosureArgs<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)] +pub struct CoroutineClosureArgs<'tcx> { + pub args: GenericArgsRef<'tcx>, +} + +pub struct CoroutineClosureArgsParts<'tcx> { + pub parent_args: &'tcx [GenericArg<'tcx>], + pub closure_kind_ty: Ty<'tcx>, + pub signature_parts_ty: Ty<'tcx>, + pub tupled_upvars_ty: Ty<'tcx>, + pub coroutine_captures_by_ref_ty: Ty<'tcx>, + pub coroutine_witness_ty: Ty<'tcx>, +} + +impl<'tcx> CoroutineClosureArgs<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + parts: CoroutineClosureArgsParts<'tcx>, + ) -> CoroutineClosureArgs<'tcx> { + CoroutineClosureArgs { + args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ + parts.closure_kind_ty.into(), + parts.signature_parts_ty.into(), + parts.tupled_upvars_ty.into(), + parts.coroutine_captures_by_ref_ty.into(), + parts.coroutine_witness_ty.into(), + ])), + } + } + + fn split(self) -> CoroutineClosureArgsParts<'tcx> { + match self.args[..] { + [ + ref parent_args @ .., + closure_kind_ty, + signature_parts_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + coroutine_witness_ty, + ] => CoroutineClosureArgsParts { + parent_args, + closure_kind_ty: closure_kind_ty.expect_ty(), + signature_parts_ty: signature_parts_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), + coroutine_witness_ty: coroutine_witness_ty.expect_ty(), + }, + _ => bug!("closure args missing synthetics"), + } + } + + pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { + self.split().parent_args + } + + #[inline] + pub fn upvar_tys(self) -> &'tcx List> { + match self.tupled_upvars_ty().kind() { + TyKind::Error(_) => ty::List::empty(), + TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(), + TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), + ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), + } + } + + #[inline] + pub fn tupled_upvars_ty(self) -> Ty<'tcx> { + self.split().tupled_upvars_ty + } + + pub fn kind_ty(self) -> Ty<'tcx> { + self.split().closure_kind_ty + } + + pub fn kind(self) -> ty::ClosureKind { + self.kind_ty().to_opt_closure_kind().unwrap() + } + + pub fn signature_parts_ty(self) -> Ty<'tcx> { + self.split().signature_parts_ty + } + + pub fn coroutine_captures_by_ref_ty(self) -> Ty<'tcx> { + self.split().coroutine_captures_by_ref_ty + } + + pub fn coroutine_witness_ty(self) -> Ty<'tcx> { + self.split().coroutine_witness_ty + } +} + /// Similar to `ClosureArgs`; see the above documentation for more. #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] pub struct CoroutineArgs<'tcx> { @@ -479,6 +570,7 @@ impl<'tcx> CoroutineArgs<'tcx> { pub enum UpvarArgs<'tcx> { Closure(GenericArgsRef<'tcx>), Coroutine(GenericArgsRef<'tcx>), + CoroutineClosure(GenericArgsRef<'tcx>), } impl<'tcx> UpvarArgs<'tcx> { @@ -490,6 +582,7 @@ impl<'tcx> UpvarArgs<'tcx> { let tupled_tys = match self { UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(), UpvarArgs::Coroutine(args) => args.as_coroutine().tupled_upvars_ty(), + UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().tupled_upvars_ty(), }; match tupled_tys.kind() { @@ -505,6 +598,7 @@ impl<'tcx> UpvarArgs<'tcx> { match self { UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(), UpvarArgs::Coroutine(args) => args.as_coroutine().tupled_upvars_ty(), + UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().tupled_upvars_ty(), } } } @@ -1393,6 +1487,20 @@ impl<'tcx> Ty<'tcx> { Ty::new(tcx, Closure(def_id, closure_args)) } + #[inline] + pub fn new_coroutine_closure( + tcx: TyCtxt<'tcx>, + def_id: DefId, + closure_args: GenericArgsRef<'tcx>, + ) -> Ty<'tcx> { + debug_assert_eq!( + closure_args.len(), + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, + "closure constructed with incorrect substitutions" + ); + Ty::new(tcx, CoroutineClosure(def_id, closure_args)) + } + #[inline] pub fn new_coroutine( tcx: TyCtxt<'tcx>, @@ -1795,7 +1903,7 @@ impl<'tcx> Ty<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if let ty::Closure(_, _) = t.kind() { + if let ty::Closure(..) = t.kind() { ControlFlow::Break(()) } else { t.super_visit_with(self) @@ -1942,6 +2050,7 @@ impl<'tcx> Ty<'tcx> { | ty::FnPtr(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) @@ -1980,6 +2089,7 @@ impl<'tcx> Ty<'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Error(_) // Extern types have metadata = (). @@ -2077,6 +2187,7 @@ impl<'tcx> Ty<'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Error(_) => true, @@ -2140,7 +2251,7 @@ impl<'tcx> Ty<'tcx> { ty::Coroutine(..) | ty::CoroutineWitness(..) => false, // Might be, but not "trivial" so just giving the safe answer. - ty::Adt(..) | ty::Closure(..) => false, + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) => false, // Needs normalization or revealing to determine, so no is the safe answer. ty::Alias(..) => false, @@ -2212,6 +2323,7 @@ impl<'tcx> Ty<'tcx> { | FnPtr(_) | Dynamic(_, _, _) | Closure(_, _) + | CoroutineClosure(_, _) | Coroutine(_, _) | CoroutineWitness(..) | Never diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 8cc8abbe718d1..4feaeb0dd0523 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1119,6 +1119,7 @@ impl<'tcx> Ty<'tcx> { ty::Adt(..) | ty::Bound(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Dynamic(..) | ty::Foreign(_) | ty::Coroutine(..) @@ -1158,6 +1159,7 @@ impl<'tcx> Ty<'tcx> { ty::Adt(..) | ty::Bound(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Dynamic(..) | ty::Foreign(_) | ty::Coroutine(..) @@ -1280,7 +1282,11 @@ impl<'tcx> Ty<'tcx> { // Conservatively return `false` for all others... // Anonymous function types - ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Coroutine(..) => false, + ty::FnDef(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Dynamic(..) + | ty::Coroutine(..) => false, // Generic or inferred types // @@ -1424,6 +1430,7 @@ pub fn needs_drop_components<'tcx>( | ty::Placeholder(..) | ty::Infer(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => Ok(smallvec![ty]), } @@ -1456,7 +1463,11 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { // Not trivial because they have components, and instead of looking inside, // we'll just perform trait selection. - ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Adt(..) => false, + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Adt(..) => false, ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 9050716db9d38..46c26241c3e78 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -189,6 +189,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } ty::Adt(_, args) | ty::Closure(_, args) + | ty::CoroutineClosure(_, args) | ty::Coroutine(_, args) | ty::CoroutineWitness(_, args) | ty::FnDef(_, args) => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 6e8af7bb6df6c..c77f4a06d0569 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -483,6 +483,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { UpvarArgs::Closure(args) => { Box::new(AggregateKind::Closure(closure_id.to_def_id(), args)) } + UpvarArgs::CoroutineClosure(args) => { + Box::new(AggregateKind::CoroutineClosure(closure_id.to_def_id(), args)) + } }; block.and(Rvalue::Aggregate(result, operands)) } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 714c5f2686eb5..9bcfe9fbc33e6 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -495,7 +495,7 @@ fn construct_fn<'tcx>( args.as_coroutine().yield_ty(), args.as_coroutine().resume_ty(), ))), - ty::Closure(..) | ty::FnDef(..) => None, + ty::Closure(..) | ty::CoroutineClosure(..) | ty::FnDef(..) => None, ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"), }; diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 862876f53c76c..1b2f2cd9477fc 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -861,6 +861,9 @@ where let ty = self.place_ty(self.place); match ty.kind() { ty::Closure(_, args) => self.open_drop_for_tuple(args.as_closure().upvar_tys()), + ty::CoroutineClosure(_, args) => { + self.open_drop_for_tuple(args.as_coroutine_closure().upvar_tys()) + } // Note that `elaborate_drops` only drops the upvars of a coroutine, // and this is ok because `open_drop` here can only be reached // within that own coroutine's resume function. diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 38ee26c5a876e..30dd915521cd2 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -154,7 +154,8 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -177,7 +178,10 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { union_path.get_or_insert(base); } } - ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (), + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(_, _) + | ty::Tuple(_) => (), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index dfc7a9891f921..451d3be255fdf 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -39,6 +39,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { let body_abi = match body_ty.kind() { ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), ty::Closure(..) => Abi::RustCall, + ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), }; diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 6c4c3917cb5ec..fbb626953835e 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -128,7 +128,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { ), } } - &AggregateKind::Closure(def_id, _) | &AggregateKind::Coroutine(def_id, _) => { + &AggregateKind::Closure(def_id, _) + | &AggregateKind::CoroutineClosure(def_id, _) + | &AggregateKind::Coroutine(def_id, _) => { let def_id = def_id.expect_local(); let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = self.tcx.mir_unsafety_check_result(def_id); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index ad12bce9b0232..6a37047a69387 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -696,6 +696,7 @@ fn try_write_constant<'tcx>( | ty::Bound(..) | ty::Placeholder(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"), diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index db7dfc5b43efa..b0d758bcbfe3b 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -57,6 +57,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let body_abi = match body_ty.kind() { ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), ty::Closure(..) => Abi::RustCall, + ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), }; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 390ec3e1a36ac..f9798bc4e70e6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -861,9 +861,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let tcx = self.tcx; if fields.is_empty() { let is_zst = match *kind { - AggregateKind::Array(..) | AggregateKind::Tuple | AggregateKind::Closure(..) => { - true - } + AggregateKind::Array(..) + | AggregateKind::Tuple + | AggregateKind::Closure(..) + | AggregateKind::CoroutineClosure(..) => true, // Only enums can be non-ZST. AggregateKind::Adt(did, ..) => tcx.def_kind(did) != DefKind::Enum, // Coroutines are never ZST, as they at least contain the implicit states. @@ -885,7 +886,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { assert!(!fields.is_empty()); (AggregateTy::Tuple, FIRST_VARIANT) } - AggregateKind::Closure(did, substs) | AggregateKind::Coroutine(did, substs) => { + AggregateKind::Closure(did, substs) + | AggregateKind::CoroutineClosure(did, substs) + | AggregateKind::Coroutine(did, substs) => { (AggregateTy::Def(did, substs), FIRST_VARIANT) } AggregateKind::Adt(did, variant_index, substs, _, None) => { diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 34d57a45301d7..9a94cae338288 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -46,6 +46,7 @@ fn maybe_zst(ty: Ty<'_>) -> bool { ty::Adt(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Tuple(..) | ty::Alias(ty::Opaque, ..) => true, // definitely ZST diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index db1aee1190359..42edbeaa622c2 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -332,7 +332,8 @@ impl, I: Interner> TypeFolder | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 99f8186d5543b..f7c382bcd7a40 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -719,6 +719,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ty::ClosureKind::FnMut => {} ty::ClosureKind::FnOnce => return succ, }, + ty::CoroutineClosure(_def_id, args) => match args.as_coroutine_closure().kind() { + ty::ClosureKind::Fn => {} + ty::ClosureKind::FnMut => {} + ty::ClosureKind::FnOnce => return succ, + }, ty::Coroutine(..) => return succ, _ => { span_bug!( diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index c02a24048f9bd..b60f32f71c2f1 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -423,7 +423,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::Alias(_, _) | ty::Param(_) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index a64b06e70d6bc..a37d8822480af 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -182,6 +182,7 @@ where | ty::Foreign(def_id) | ty::FnDef(def_id, ..) | ty::Closure(def_id, ..) + | ty::CoroutineClosure(def_id, ..) | ty::Coroutine(def_id, ..) => { self.def_id_visitor.visit_def_id(def_id, "type", &ty)?; if V::SHALLOW { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index e433460e2ad9d..65ff85a96695b 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -538,6 +538,9 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { tables.tcx.coroutine_movability(*def_id).stable(tables), ) } + mir::AggregateKind::CoroutineClosure(..) => { + todo!("FIXME(async_closure): Lower these to SMIR") + } } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index ba957843bb079..e3fd64eb1891e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -383,6 +383,7 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { tables.closure_def(*def_id), generic_args.stable(tables), )), + ty::CoroutineClosure(..) => todo!("/* TODO */"), ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine( tables.coroutine_def(*def_id), generic_args.stable(tables), diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 4a5f58443bc29..5af9503087ab9 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -211,6 +211,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args), // The `pretty_print_type` formatting of array size depends on @@ -281,7 +282,11 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { // Similar to `pretty_path_qualified`, but for the other // types that are printed as paths (see `print_type` above). match self_ty.kind() { - ty::FnDef(..) | ty::Alias(..) | ty::Closure(..) | ty::Coroutine(..) + ty::FnDef(..) + | ty::Alias(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) if trait_ref.is_none() => { self.print_type(self_ty) diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 0cc82ac7506cb..9d1b92e106803 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -628,7 +628,9 @@ fn encode_ty<'tcx>( } // Function types - ty::FnDef(def_id, args) | ty::Closure(def_id, args) => { + ty::FnDef(def_id, args) + | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) => { // u[IE], where is , // as vendor extended type. let mut s = String::new(); @@ -895,6 +897,10 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, options)); } + ty::CoroutineClosure(def_id, args) => { + ty = Ty::new_coroutine_closure(tcx, *def_id, transform_args(tcx, args, options)); + } + ty::Coroutine(def_id, args) => { ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, options)); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 16ebda55a7a51..d380cb9a19b78 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -386,6 +386,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args) | ty::Coroutine(def_id, args) => { self.print_def_path(def_id, args)?; } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 915d722dd0206..e1c68039e79fb 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -340,7 +340,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::Never | ty::Tuple(_) => { @@ -538,6 +539,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::FnPtr(_) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never @@ -694,6 +696,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::FnPtr(_) | ty::Alias(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 274a75a125c58..3c571e1d96f34 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -57,6 +57,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), + ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]), + ty::Coroutine(_, args) => { let coroutine_args = args.as_coroutine(); Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()]) @@ -128,6 +130,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => Ok(vec![]), @@ -193,6 +196,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), + ty::CoroutineClosure(..) => Err(NoSolution), + ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { @@ -267,6 +272,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } Ok(Some(closure_args.sig().map_bound(|sig| (sig.inputs()[0], sig.output())))) } + + // Coroutine closures don't implement `Fn` traits the normal way. + ty::CoroutineClosure(..) => Err(NoSolution), + ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 9f1b4a09a20ba..e1c6f67f05eb0 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -391,6 +391,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | ty::Coroutine(..) | ty::CoroutineWitness(..) @@ -627,6 +628,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | ty::Coroutine(..) | ty::CoroutineWitness(..) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index b185e4e5f8eb0..efaad47b6ddff 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -950,7 +950,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::FnPtr(_) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index c49185a52c7ef..4b20de2621924 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -863,7 +863,7 @@ where } } ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - ty::Closure(did, ..) | ty::Coroutine(did, ..) => { + ty::Closure(did, ..) | ty::CoroutineClosure(did, ..) | ty::Coroutine(did, ..) => { if self.def_id_is_local(did) { ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) } else { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index d57d9f58333c9..1ac0f172ef4c3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -959,9 +959,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation: &PredicateObligation<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Option { - if let ty::Closure(closure_def_id, closure_args) = *trait_ref.self_ty().skip_binder().kind() + let self_ty = trait_ref.self_ty().skip_binder(); + if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind() && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) - && let Some(found_kind) = self.closure_kind(closure_args) + && let Some(found_kind) = self.closure_kind(self_ty) && !found_kind.extends(expected_kind) && let sig = closure_args.as_closure().sig() && self.can_sub( @@ -1875,6 +1876,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Coroutine(..) => Some(18), ty::Foreign(..) => Some(19), ty::CoroutineWitness(..) => Some(20), + ty::CoroutineClosure(..) => Some(21), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index abbc2066eac16..a960befcd4ba8 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1854,6 +1854,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::FnPtr(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never @@ -1903,6 +1904,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::FnPtr(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 79f03242c5876..6c8834f11f1eb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -48,7 +48,11 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // (T1..Tn) and closures have same properties as T1..Tn -- // check if *all* of them are trivial. ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), + ty::Closure(_, args) => trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()), + ty::CoroutineClosure(_, args) => { + trivial_dropck_outlives(tcx, args.as_coroutine_closure().tupled_upvars_ty()) + } ty::Adt(def, _) => { if Some(def.did()) == tcx.lang_items().manually_drop() { @@ -239,6 +243,22 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( Ok::<_, NoSolution>(()) })?, + ty::CoroutineClosure(_, args) => { + rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in args.as_coroutine_closure().upvar_tys() { + dtorck_constraint_for_ty_inner( + tcx, + param_env, + span, + depth + 1, + ty, + constraints, + )?; + } + Ok::<_, NoSolution>(()) + })? + } + ty::Coroutine(_, args) => { // rust-lang/rust#49918: types can be constructed, stored // in the interior, and sit idle when coroutine yields 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 12aea88e9b6a2..b354ebf111f4c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -306,11 +306,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the args on closure types never // touch bound regions, they just capture the in-scope // type/region parameters - match *obligation.self_ty().skip_binder().kind() { - ty::Closure(def_id, closure_args) => { + let self_ty = obligation.self_ty().skip_binder(); + match *self_ty.kind() { + ty::Closure(def_id, _) => { let is_const = self.tcx().is_const_fn_raw(def_id); debug!(?kind, ?obligation, "assemble_unboxed_candidates"); - match self.infcx.closure_kind(closure_args) { + match self.infcx.closure_kind(self_ty) { Some(closure_kind) => { debug!(?closure_kind, "assemble_unboxed_candidates"); if closure_kind.extends(kind) { @@ -488,7 +489,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Slice(_) | ty::RawPtr(_) | ty::Ref(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -623,7 +625,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(..) | ty::FnDef(..) | ty::FnPtr(_) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Never | ty::Tuple(_) @@ -1000,6 +1003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Array(..) | ty::Slice(_) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Tuple(_) | ty::CoroutineWitness(..) => { @@ -1076,7 +1080,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) - | ty::Closure(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) | ty::Never @@ -1139,6 +1144,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Placeholder(..) | ty::Dynamic(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6a6adcbb680ea..e79277b89c4ae 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2106,6 +2106,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { @@ -2227,6 +2228,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } + // FIXME(async_closures): These are never clone, for now. + ty::CoroutineClosure(_, _) => None, + ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { // Fallback to whatever user-defined impls exist in this case. None @@ -2305,6 +2309,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { t.rebind(vec![ty]) } + ty::CoroutineClosure(_, args) => { + let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); + t.rebind(vec![ty]) + } + ty::Coroutine(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index d5a37e63d8765..89459f377dd2b 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -79,6 +79,9 @@ impl<'tcx> TypeVisitor> for Search<'tcx> { ty::Closure(..) => { return ControlFlow::Break(ty); } + ty::CoroutineClosure(..) => { + return ControlFlow::Break(ty); + } ty::Coroutine(..) | ty::CoroutineWitness(..) => { return ControlFlow::Break(ty); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 0f8d9c6bf4bdb..88584a61b13de 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -727,6 +727,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend(obligations); } + ty::CoroutineClosure(did, args) => { + // See the above comments. + walker.skip_current_subtree(); + self.compute(args.as_coroutine_closure().tupled_upvars_ty().into()); + let obligations = self.nominal_obligations(did, args); + self.out.extend(obligations); + } + ty::FnPtr(_) => { // let the loop iterate into the argument/return // types appearing in the fn signature diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 2d76cf994e437..a5a2c53c7321b 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -215,6 +215,7 @@ fn resolve_associated_item<'tcx>( ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Tuple(..) => {} _ => return Ok(None), }; diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 2fc4bfd4aa31c..f20ded355b1cd 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -328,6 +328,17 @@ fn layout_of_uncached<'tcx>( )? } + ty::CoroutineClosure(_, args) => { + let tys = args.as_coroutine_closure().upvar_tys(); + univariant( + &tys.iter() + .map(|ty| Ok(cx.layout_of(ty)?.layout)) + .try_collect::>()?, + &ReprOptions::default(), + StructKind::AlwaysSized, + )? + } + ty::Tuple(tys) => { let kind = if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 08e5476ae43b7..7b3d2ab22cfa4 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -172,6 +172,12 @@ where } } + ty::CoroutineClosure(_, args) => { + for upvar in args.as_coroutine_closure().upvar_tys() { + queue_type(self, upvar); + } + } + // Check for a `Drop` impl and whether this is a union or // `ManuallyDrop`. If it's a struct or enum without a `Drop` // impl then check whether the field types need `Drop`. diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2158aacab03d8..60b1bbe8c2a5f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -18,7 +18,9 @@ fn sized_constraint_for_ty<'tcx>( let result = match ty.kind() { Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) - | FnPtr(_) | Array(..) | Closure(..) | Coroutine(..) | Never => vec![], + | FnPtr(_) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..) | Never => { + vec![] + } Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | CoroutineWitness(..) => { // these are never sized - return the target type diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 859000fb6cb18..5941fce88250a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -202,6 +202,9 @@ pub enum TyKind { /// `ClosureArgs` for more details. Closure(I::DefId, I::GenericArgs), + /// TODO + CoroutineClosure(I::DefId, I::GenericArgs), + /// The anonymous type of a coroutine. Used to represent the type of /// `|a| yield a`. /// @@ -317,16 +320,17 @@ const fn tykind_discriminant(value: &TyKind) -> usize { FnPtr(_) => 13, Dynamic(..) => 14, Closure(_, _) => 15, - Coroutine(_, _) => 16, - CoroutineWitness(_, _) => 17, - Never => 18, - Tuple(_) => 19, - Alias(_, _) => 20, - Param(_) => 21, - Bound(_, _) => 22, - Placeholder(_) => 23, - Infer(_) => 24, - Error(_) => 25, + CoroutineClosure(_, _) => 16, + Coroutine(_, _) => 17, + CoroutineWitness(_, _) => 18, + Never => 19, + Tuple(_) => 20, + Alias(_, _) => 21, + Param(_) => 22, + Bound(_, _) => 23, + Placeholder(_) => 24, + Infer(_) => 25, + Error(_) => 26, } } @@ -356,6 +360,7 @@ impl PartialEq for TyKind { a_p == b_p && a_r == b_r && a_repr == b_repr } (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s, + (CoroutineClosure(a_d, a_s), CoroutineClosure(b_d, b_s)) => a_d == b_d && a_s == b_s, (Coroutine(a_d, a_s), Coroutine(b_d, b_s)) => a_d == b_d && a_s == b_s, (CoroutineWitness(a_d, a_s), CoroutineWitness(b_d, b_s)) => a_d == b_d && a_s == b_s, (Tuple(a_t), Tuple(b_t)) => a_t == b_t, @@ -430,6 +435,9 @@ impl DebugWithInfcx for TyKind { } }, Closure(d, s) => f.debug_tuple("Closure").field(d).field(&this.wrap(s)).finish(), + CoroutineClosure(d, s) => { + f.debug_tuple("CoroutineClosure").field(d).field(&this.wrap(s)).finish() + } Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).finish(), CoroutineWitness(d, s) => { f.debug_tuple("CoroutineWitness").field(d).field(&this.wrap(s)).finish() diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bd1d68e7074e1..3bac71dbc24e2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2286,6 +2286,7 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Closure(..) => panic!("Closure"), + ty::CoroutineClosure(..) => panic!("CoroutineClosure"), ty::Coroutine(..) => panic!("Coroutine"), ty::Placeholder(..) => panic!("Placeholder"), ty::CoroutineWitness(..) => panic!("CoroutineWitness"), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a75d9bee30490..fe02611b5d449 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -503,6 +503,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } ty::Alias(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Dynamic(..) diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 8ff54dfcfa0dc..194cf69ea7ed0 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -881,6 +881,7 @@ impl TyCoercionStability { | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Never | ty::Tuple(_) | ty::Alias(ty::Projection, _) => Self::Deref, diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index b26ebe5cee321..288df0fd663f0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -490,6 +490,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})") }, }, + ClosureKind::CoroutineClosure(desugaring) => format!( + "ClosureKind::CoroutineClosure(CoroutineDesugaring::{desugaring:?})" + ), }; let ret_ty = match fn_decl.output { diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 8c4d71e68f80f..579f137f861e1 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind { // report your lint here } -if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = expr.kind +if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::CoroutineClosure(CoroutineDesugaring::Async), .. } = expr.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output && expr1 = &cx.tcx.hir().body(body_id).value - && let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind + && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind && let FnRetTy::DefaultReturn(_) = fn_decl1.output && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs index ae7f341fe4e33..cce223c77bbab 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -29,6 +29,7 @@ fn main() { TyKind::FnPtr(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Dynamic(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::CoroutineClosure(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Coroutine(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::CoroutineWitness(..) => (), //~ ERROR usage of `ty::TyKind::` TyKind::Never => (), //~ ERROR usage of `ty::TyKind::` diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr index 45b7c26faad07..2ff5aad95dd87 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -109,71 +109,77 @@ LL | TyKind::Closure(..) => (), error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:32:9 | -LL | TyKind::Coroutine(..) => (), +LL | TyKind::CoroutineClosure(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:33:9 | -LL | TyKind::CoroutineWitness(..) => (), +LL | TyKind::Coroutine(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:34:9 | -LL | TyKind::Never => (), +LL | TyKind::CoroutineWitness(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:35:9 | -LL | TyKind::Tuple(..) => (), +LL | TyKind::Never => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:36:9 | -LL | TyKind::Alias(..) => (), +LL | TyKind::Tuple(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:37:9 | -LL | TyKind::Param(..) => (), +LL | TyKind::Alias(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:38:9 | -LL | TyKind::Bound(..) => (), +LL | TyKind::Param(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:39:9 | -LL | TyKind::Placeholder(..) => (), +LL | TyKind::Bound(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:40:9 | -LL | TyKind::Infer(..) => (), +LL | TyKind::Placeholder(..) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` --> $DIR/ty_tykind_usage.rs:41:9 | +LL | TyKind::Infer(..) => (), + | ^^^^^^ help: try using `ty::` directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:42:9 + | LL | TyKind::Error(_) => (), | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind::` - --> $DIR/ty_tykind_usage.rs:46:12 + --> $DIR/ty_tykind_usage.rs:47:12 | LL | if let TyKind::Int(int_ty) = kind {} | ^^^^^^ help: try using `ty::` directly: `ty` error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:48:24 + --> $DIR/ty_tykind_usage.rs:49:24 | LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} | ^^^^^^^^^^ @@ -181,7 +187,7 @@ LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:50:37 + --> $DIR/ty_tykind_usage.rs:51:37 | LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { | ^^^^^^^^^^^ @@ -189,7 +195,7 @@ LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:50:53 + --> $DIR/ty_tykind_usage.rs:51:53 | LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { | ^^^^^^^^^^^ @@ -197,12 +203,12 @@ LL | fn ir_ty_kind(bad: IrTyKind) -> IrTyKind { = help: try using `Ty` instead error: usage of `ty::TyKind::` - --> $DIR/ty_tykind_usage.rs:53:9 + --> $DIR/ty_tykind_usage.rs:54:9 | LL | IrTyKind::Bool | --------^^^^^^ | | | help: try using `ty::` directly: `ty` -error: aborting due to 32 previous errors +error: aborting due to 33 previous errors From a82bae2172499864c12a1d0b412931ad884911f7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 24 Jan 2024 22:27:25 +0000 Subject: [PATCH 063/101] Teach typeck/borrowck/solvers how to deal with async closures --- compiler/rustc_ast_lowering/src/expr.rs | 8 + .../src/diagnostics/region_name.rs | 21 +- compiler/rustc_borrowck/src/lib.rs | 1 + .../src/type_check/input_output.rs | 70 ++++++- compiler/rustc_borrowck/src/type_check/mod.rs | 15 +- .../rustc_borrowck/src/universal_regions.rs | 58 +++++- .../src/transform/validate.rs | 1 + compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_hir_analysis/src/collect.rs | 31 +++ compiler/rustc_hir_typeck/src/callee.rs | 85 +++++--- compiler/rustc_hir_typeck/src/closure.rs | 87 ++++++++- compiler/rustc_hir_typeck/src/upvar.rs | 64 +++++- .../rustc_middle/src/middle/lang_items.rs | 15 +- compiler/rustc_middle/src/query/mod.rs | 5 + compiler/rustc_middle/src/traits/select.rs | 7 + compiler/rustc_middle/src/ty/mod.rs | 7 +- compiler/rustc_middle/src/ty/sty.rs | 128 +++++++++++- compiler/rustc_mir_build/src/build/mod.rs | 1 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 + compiler/rustc_mir_build/src/thir/cx/mod.rs | 18 +- .../rustc_mir_dataflow/src/value_analysis.rs | 3 + .../src/const_prop_lint.rs | 3 +- .../src/coverage/spans/from_mir.rs | 4 +- compiler/rustc_span/src/symbol.rs | 4 + .../src/solve/assembly/mod.rs | 18 ++ .../src/solve/assembly/structural_traits.rs | 111 ++++++++++- .../src/solve/normalizes_to/mod.rs | 113 +++++++++++ .../src/solve/trait_goals.rs | 60 ++++++ .../src/traits/project.rs | 182 +++++++++++++++++- .../src/traits/select/candidate_assembly.rs | 46 +++++ .../src/traits/select/confirmation.rs | 50 +++++ .../src/traits/select/mod.rs | 12 ++ compiler/rustc_ty_utils/src/abi.rs | 36 ++++ compiler/rustc_ty_utils/src/instance.rs | 11 ++ library/core/src/ops/async_function.rs | 8 + 35 files changed, 1221 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2241b4cd8e504..9990d526bf732 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,3 +1,5 @@ +use std::assert_matches::assert_matches; + use super::errors::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, @@ -1027,6 +1029,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); + assert_matches!( + coroutine_kind, + CoroutineKind::Async { .. }, + "only async closures are supported currently" + ); + let body = self.with_new_scopes(fn_decl_span, |this| { let inner_decl = FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index fc52306e10d0b..c91b8eaab055f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -324,9 +324,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ty::BoundRegionKind::BrEnv => { let def_ty = self.regioncx.universal_regions().defining_ty; - let DefiningTy::Closure(_, args) = def_ty else { - // Can't have BrEnv in functions, constants or coroutines. - bug!("BrEnv outside of closure."); + let closure_kind = match def_ty { + DefiningTy::Closure(_, args) => args.as_closure().kind(), + DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().kind(), + _ => { + // Can't have BrEnv in functions, constants or coroutines. + bug!("BrEnv outside of closure."); + } }; let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) = tcx.hir().expect_expr(self.mir_hir_id()).kind @@ -334,21 +338,18 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { bug!("Closure is not defined by a closure expr"); }; let region_name = self.synthesize_region_name(); - - let closure_kind_ty = args.as_closure().kind_ty(); - let note = match closure_kind_ty.to_opt_closure_kind() { - Some(ty::ClosureKind::Fn) => { + let note = match closure_kind { + ty::ClosureKind::Fn => { "closure implements `Fn`, so references to captured variables \ can't escape the closure" } - Some(ty::ClosureKind::FnMut) => { + ty::ClosureKind::FnMut => { "closure implements `FnMut`, so references to captured variables \ can't escape the closure" } - Some(ty::ClosureKind::FnOnce) => { + ty::ClosureKind::FnOnce => { bug!("BrEnv in a `FnOnce` closure"); } - None => bug!("Closure kind not inferred in borrow check"), }; Some(RegionName { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index eaf9fc4583720..bb64571889bae 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -3,6 +3,7 @@ #![allow(internal_features)] #![feature(rustdoc_internals)] #![doc(rust_logo)] +#![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(let_chains)] diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 59518f68ab149..a3e5088ee09aa 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,13 +7,18 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). +use std::assert_matches::assert_matches; + use itertools::Itertools; -use rustc_infer::infer::BoundRegionConversionTime; +use rustc_hir as hir; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use crate::universal_regions::UniversalRegions; +use crate::renumber::RegionCtxt; +use crate::universal_regions::{DefiningTy, UniversalRegions}; use super::{Locations, TypeChecker}; @@ -23,9 +28,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self, body), level = "debug")] pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { let mir_def_id = body.source.def_id().expect_local(); + if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) { return; } + let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); // Instantiate the canonicalized variables from user-provided signature @@ -34,12 +41,69 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // so that they represent the view from "inside" the closure. let user_provided_sig = self .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig); - let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( + let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( body.span, BoundRegionConversionTime::FnCall, user_provided_sig, ); + // FIXME(async_closures): We must apply the same transformation to our + // signature here as we do during closure checking. + if let DefiningTy::CoroutineClosure(_, args) = + self.borrowck_context.universal_regions.defining_ty + { + assert_matches!( + self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure + )), + "this needs to be modified if we're lowering non-async closures" + ); + let args = args.as_coroutine_closure(); + let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( + self.tcx(), + args.kind(), + Ty::new_tup(self.tcx(), user_provided_sig.inputs()), + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || { + RegionCtxt::Unknown + }), + ); + + let next_ty_var = || { + self.infcx.next_ty_var(TypeVariableOrigin { + span: body.span, + kind: TypeVariableOriginKind::MiscVariable, + }) + }; + let output_ty = Ty::new_coroutine( + self.tcx(), + self.tcx().coroutine_for_closure(mir_def_id), + ty::CoroutineArgs::new( + self.tcx(), + ty::CoroutineArgsParts { + parent_args: args.parent_args(), + resume_ty: next_ty_var(), + yield_ty: next_ty_var(), + witness: next_ty_var(), + return_ty: user_provided_sig.output(), + tupled_upvars_ty: tupled_upvars_ty, + }, + ) + .args, + ); + + user_provided_sig = self.tcx().mk_fn_sig( + user_provided_sig.inputs().iter().copied(), + output_ty, + user_provided_sig.c_variadic, + user_provided_sig.unsafety, + user_provided_sig.abi, + ); + } + let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id()) && user_provided_sig.inputs().is_empty(); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 90a9844fda9e4..cdb187e07760a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2773,15 +2773,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id); let parent_args = match tcx.def_kind(def_id) { + // We don't want to dispatch on 3 different kind of closures here, so take + // advantage of the fact that the `parent_args` is the same length as the + // `typeck_root_args`. DefKind::Closure => { - // FIXME(async_closures): It's kind of icky to access HIR here. - match tcx.hir_node_by_def_id(def_id).expect_closure().kind { - hir::ClosureKind::Closure => args.as_closure().parent_args(), - hir::ClosureKind::Coroutine(_) => args.as_coroutine().parent_args(), - hir::ClosureKind::CoroutineClosure(_) => { - args.as_coroutine_closure().parent_args() - } - } + // FIXME(async_closures): It may be useful to add a debug assert here + // to actually call `type_of` and check the `parent_args` are the same + // length as the `typeck_root_args`. + &args[..typeck_root_args.len()] } DefKind::InlineConst => args.as_inline_const().parent_args(), other => bug!("unexpected item {:?}", other), diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index ae8a135f09059..9c266d123b338 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -97,6 +97,10 @@ pub enum DefiningTy<'tcx> { /// `ClosureArgs::coroutine_return_ty`. Coroutine(DefId, GenericArgsRef<'tcx>), + /// The MIR is a special kind of closure that returns coroutines. + /// TODO: describe how to make the sig... + CoroutineClosure(DefId, GenericArgsRef<'tcx>), + /// The MIR is a fn item with the given `DefId` and args. The signature /// of the function can be bound then with the `fn_sig` query. FnDef(DefId, GenericArgsRef<'tcx>), @@ -119,6 +123,7 @@ impl<'tcx> DefiningTy<'tcx> { pub fn upvar_tys(self) -> &'tcx ty::List> { match self { DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(), + DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(), DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(), DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { ty::List::empty() @@ -131,7 +136,9 @@ impl<'tcx> DefiningTy<'tcx> { /// user's code. pub fn implicit_inputs(self) -> usize { match self { - DefiningTy::Closure(..) | DefiningTy::Coroutine(..) => 1, + DefiningTy::Closure(..) + | DefiningTy::CoroutineClosure(..) + | DefiningTy::Coroutine(..) => 1, DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, } } @@ -147,6 +154,7 @@ impl<'tcx> DefiningTy<'tcx> { pub fn def_id(&self) -> DefId { match *self { DefiningTy::Closure(def_id, ..) + | DefiningTy::CoroutineClosure(def_id, ..) | DefiningTy::Coroutine(def_id, ..) | DefiningTy::FnDef(def_id, ..) | DefiningTy::Const(def_id, ..) @@ -355,6 +363,9 @@ impl<'tcx> UniversalRegions<'tcx> { err.note(format!("late-bound region is {:?}", self.to_region_vid(r))); }); } + DefiningTy::CoroutineClosure(..) => { + todo!() + } DefiningTy::Coroutine(def_id, args) => { let v = with_no_trimmed_paths!( args[tcx.generics_of(def_id).parent_count..] @@ -568,6 +579,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { match *defining_ty.kind() { ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args), ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args), + ty::CoroutineClosure(def_id, args) => { + DefiningTy::CoroutineClosure(def_id, args) + } ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args), _ => span_bug!( tcx.def_span(self.mir_def), @@ -623,6 +637,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); let fr_args = match defining_ty { DefiningTy::Closure(_, args) + | DefiningTy::CoroutineClosure(_, args) | DefiningTy::Coroutine(_, args) | DefiningTy::InlineConst(_, args) => { // In the case of closures, we rely on the fact that @@ -702,6 +717,47 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ty::Binder::dummy(inputs_and_output) } + DefiningTy::CoroutineClosure(def_id, args) => { + assert_eq!(self.mir_def.to_def_id(), def_id); + let closure_sig = args.as_coroutine_closure().coroutine_closure_sig(); + let bound_vars = tcx.mk_bound_variable_kinds_from_iter( + closure_sig + .bound_vars() + .iter() + .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BrEnv, + }; + let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + let closure_kind = args.as_coroutine_closure().kind(); + + let closure_ty = tcx.closure_env_ty( + Ty::new_coroutine_closure(tcx, def_id, args), + closure_kind, + env_region, + ); + + let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields(); + let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars( + tcx, + args.as_coroutine_closure().parent_args(), + tcx.coroutine_for_closure(def_id), + closure_kind, + env_region, + args.as_coroutine_closure().tupled_upvars_ty(), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + ); + + ty::Binder::bind_with_vars( + tcx.mk_type_list_from_iter( + iter::once(closure_ty).chain(inputs).chain(iter::once(output)), + ), + bound_vars, + ) + } + DefiningTy::FnDef(def_id, _) => { let sig = tcx.fn_sig(def_id).instantiate_identity(); let sig = indices.fold_to_region_vids(tcx, sig); diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index d3230a2455df3..c4542aaa7b2fb 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -58,6 +58,7 @@ impl<'tcx> MirPass<'tcx> for Validator { let body_abi = match body_ty.kind() { ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), ty::Closure(..) => Abi::RustCall, + ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, _ => { span_bug!(body.span, "unexpected body ty: {:?} phase {:?}", body_ty, mir_phase) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 8e327c029dffc..9c9e72d6e6512 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -209,6 +209,7 @@ language_item_table! { AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnKindHelper, sym::async_fn_kind_helper,async_fn_kind_helper, Target::Trait, GenericRequirement::Exact(1); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8d862d5eb715f..8fdd3cfe3cf88 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -81,6 +81,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_ref, impl_polarity, coroutine_kind, + coroutine_for_closure, collect_mod_item_types, is_type_alias_impl_trait, ..*providers @@ -1531,6 +1532,36 @@ fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> DefId { + let Node::Expr(&hir::Expr { + kind: + hir::ExprKind::Closure(&rustc_hir::Closure { + kind: hir::ClosureKind::CoroutineClosure(_), + body, + .. + }), + .. + }) = tcx.hir_node_by_def_id(def_id) + else { + bug!() + }; + + let &hir::Expr { + kind: + hir::ExprKind::Closure(&rustc_hir::Closure { + def_id, + kind: hir::ClosureKind::Coroutine(_), + .. + }), + .. + } = tcx.hir().body(body).value + else { + bug!() + }; + + def_id.to_def_id() +} + fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { match tcx.hir_node_by_def_id(def_id) { Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 80650dcb53c3f..1858b2770cdbc 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -141,32 +141,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Some(CallStep::Builtin(adjusted_ty)); } - ty::Closure(def_id, args) => { + // Check whether this is a call to a closure where we + // haven't yet decided on whether the closure is fn vs + // fnmut vs fnonce. If so, we have to defer further processing. + ty::Closure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => { let def_id = def_id.expect_local(); + let closure_sig = args.as_closure().sig(); + let closure_sig = self.instantiate_binder_with_fresh_vars( + call_expr.span, + infer::FnCall, + closure_sig, + ); + let adjustments = self.adjust_steps(autoderef); + self.record_deferred_call_resolution( + def_id, + DeferredCallResolution { + call_expr, + callee_expr, + closure_ty: adjusted_ty, + adjustments, + fn_sig: closure_sig, + }, + ); + return Some(CallStep::DeferredClosure(def_id, closure_sig)); + } - // Check whether this is a call to a closure where we - // haven't yet decided on whether the closure is fn vs - // fnmut vs fnonce. If so, we have to defer further processing. - if self.closure_kind(adjusted_ty).is_none() { - let closure_sig = args.as_closure().sig(); - let closure_sig = self.instantiate_binder_with_fresh_vars( - call_expr.span, - infer::FnCall, - closure_sig, - ); - let adjustments = self.adjust_steps(autoderef); - self.record_deferred_call_resolution( - def_id, - DeferredCallResolution { - call_expr, - callee_expr, - closure_ty: adjusted_ty, - adjustments, - fn_sig: closure_sig, - }, - ); - return Some(CallStep::DeferredClosure(def_id, closure_sig)); - } + ty::CoroutineClosure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => { + let def_id = def_id.expect_local(); + let closure_args = args.as_coroutine_closure(); + let coroutine_closure_sig = self.instantiate_binder_with_fresh_vars( + call_expr.span, + infer::FnCall, + closure_args.coroutine_closure_sig(), + ); + let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: callee_expr.span, + }); + let call_sig = self.tcx.mk_fn_sig( + [coroutine_closure_sig.tupled_inputs_ty], + coroutine_closure_sig.to_coroutine( + self.tcx, + closure_args.parent_args(), + self.tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ), + coroutine_closure_sig.c_variadic, + coroutine_closure_sig.unsafety, + coroutine_closure_sig.abi, + ); + let adjustments = self.adjust_steps(autoderef); + self.record_deferred_call_resolution( + def_id, + DeferredCallResolution { + call_expr, + callee_expr, + closure_ty: adjusted_ty, + adjustments, + fn_sig: call_sig, + }, + ); + return Some(CallStep::DeferredClosure(def_id, call_sig)); } // Hack: we know that there are traits implementing Fn for &F @@ -935,7 +970,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { span_bug!( self.call_expr.span, "Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for `{}`", - self.adjusted_ty + self.closure_ty ) } } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 18dff5188af94..1d024efdd499f 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -63,7 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => (None, None), }; - let ClosureSignatures { bound_sig, liberated_sig } = + let ClosureSignatures { bound_sig, mut liberated_sig } = self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig); debug!(?bound_sig, ?liberated_sig); @@ -125,7 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) | hir::CoroutineKind::Coroutine(_) => { let yield_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, + kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, }); self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); @@ -137,7 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // not a problem. hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { let yield_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, + kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, }); self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); @@ -166,8 +166,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); let interior = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: body.value.span, + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, }); self.deferred_coroutine_interiors.borrow_mut().push(( expr_def_id, @@ -192,7 +192,82 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(CoroutineTypes { resume_ty, yield_ty }), ) } - hir::ClosureKind::CoroutineClosure(_) => todo!(), + hir::ClosureKind::CoroutineClosure(kind) => { + let (bound_return_ty, bound_yield_ty) = match kind { + hir::CoroutineDesugaring::Async => { + (bound_sig.skip_binder().output(), tcx.types.unit) + } + hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen => { + todo!("`gen` and `async gen` closures not supported yet") + } + }; + let resume_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let interior = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let closure_kind_ty = self.next_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish closure kind inference variables from the rest. + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + let closure_args = ty::CoroutineClosureArgs::new( + tcx, + ty::CoroutineClosureArgsParts { + parent_args, + closure_kind_ty, + signature_parts_ty: Ty::new_fn_ptr( + tcx, + bound_sig.map_bound(|sig| { + tcx.mk_fn_sig( + [ + resume_ty, + Ty::new_tup_from_iter(tcx, sig.inputs().iter().copied()), + ], + Ty::new_tup(tcx, &[bound_yield_ty, bound_return_ty]), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }), + ), + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + coroutine_witness_ty: interior, + }, + ); + + let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + liberated_sig = tcx.mk_fn_sig( + liberated_sig.inputs().iter().copied(), + tcx.liberate_late_bound_regions( + expr_def_id.to_def_id(), + closure_args.coroutine_closure_sig().map_bound(|sig| { + sig.to_coroutine( + tcx, + parent_args, + tcx.coroutine_for_closure(expr_def_id), + coroutine_upvars_ty, + ) + }), + ), + liberated_sig.c_variadic, + liberated_sig.unsafety, + liberated_sig.abi, + ); + + (Ty::new_coroutine_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None) + } }; check_fn( diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 55ffac8d92f87..b087d6d9e570d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -174,6 +174,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Closure(def_id, args) => { (def_id, UpvarArgs::Closure(args), self.closure_kind(ty).is_none()) } + ty::CoroutineClosure(def_id, args) => { + (def_id, UpvarArgs::CoroutineClosure(args), self.closure_kind(ty).is_none()) + } ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args), false), ty::Error(_) => { // #51714: skip analysis when we have already encountered type errors @@ -333,6 +336,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + if let UpvarArgs::CoroutineClosure(args) = args { + let closure_env_region: ty::Region<'_> = ty::Region::new_bound( + self.tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(0), + kind: ty::BoundRegionKind::BrEnv, + }, + ); + let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter( + self.tcx, + self.typeck_results + .borrow() + .closure_min_captures_flattened( + self.tcx.coroutine_for_closure(closure_def_id).expect_local(), + ) + // Skip the captures that are just moving the closure's args + // into the coroutine. These are always by move. + .skip( + args.as_coroutine_closure() + .coroutine_closure_sig() + .skip_binder() + .tupled_inputs_ty + .tuple_fields() + .len(), + ) + .map(|captured_place| { + let upvar_ty = captured_place.place.ty(); + let capture = captured_place.info.capture_kind; + apply_capture_kind_on_capture_ty( + self.tcx, + upvar_ty, + capture, + Some(closure_env_region), + ) + }), + ); + let coroutine_captures_by_ref_ty = Ty::new_fn_ptr( + self.tcx, + ty::Binder::bind_with_vars( + self.tcx.mk_fn_sig( + [], + tupled_upvars_ty_for_borrow, + false, + hir::Unsafety::Normal, + rustc_target::spec::abi::Abi::Rust, + ), + self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region( + ty::BoundRegionKind::BrEnv, + )]), + ), + ); + self.demand_eqtype( + span, + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + coroutine_captures_by_ref_ty, + ); + } + self.log_closure_min_capture_info(closure_def_id, span); // Now that we've analyzed the closure, we know how each @@ -602,7 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Go through each entry in the current list of min_captures - // - if ancestor is found, update it's capture kind to account for current place's + // - if ancestor is found, update its capture kind to account for current place's // capture information. // // - if descendant is found, remove it from the list, and update the current place's diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index f92c72c8a588c..a4e193ba2c942 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Given a [`DefId`] of a [`Fn`], [`FnMut`] or [`FnOnce`] traits, + /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits, /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option { @@ -36,6 +36,19 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Given a [`DefId`] of one of the `AsyncFn`, `AsyncFnMut` or `AsyncFnOnce` traits, + /// returns a corresponding [`ty::ClosureKind`]. + /// For any other [`DefId`] return `None`. + pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option { + let items = self.lang_items(); + match Some(id) { + x if x == items.async_fn_trait() => Some(ty::ClosureKind::Fn), + x if x == items.async_fn_mut_trait() => Some(ty::ClosureKind::FnMut), + x if x == items.async_fn_once_trait() => Some(ty::ClosureKind::FnOnce), + _ => None, + } + } + /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family /// trait, if it is defined. pub fn fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2438f826441d2..f9ab32b16f534 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -755,6 +755,11 @@ rustc_queries! { separate_provide_extern } + query coroutine_for_closure(def_id: DefId) -> DefId { + desc { |_tcx| "TODO" } + separate_provide_extern + } + /// Gets a map with the variance of every item; use `variances_of` instead. query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> { arena_cache diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 64f4af08e12ed..4e11575cf9800 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -134,6 +134,13 @@ pub enum SelectionCandidate<'tcx> { is_const: bool, }, + /// Implementation of an `AsyncFn`-family trait by one of the anonymous types + /// generated for an `async ||` expression. + AsyncClosureCandidate, + + // TODO: + AsyncFnKindHelperCandidate, + /// Implementation of a `Coroutine` trait by one of the anonymous types /// generated for a coroutine. CoroutineCandidate, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8e51db82f95ae..4348d01eff58c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -105,9 +105,10 @@ pub use self::region::{ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, - ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, FnSig, GenSig, - InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, - UpvarArgs, VarianceDiagInfo, + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, + CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs, + InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c047f6a052151..e2a2e24f06dd8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -36,6 +36,7 @@ use rustc_type_ir::TyKind as IrTyKind; use rustc_type_ir::TyKind::*; use rustc_type_ir::TypeAndMut as IrTypeAndMut; +use super::fold::FnMutDelegate; use super::GenericParamDefKind; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here @@ -351,6 +352,27 @@ impl<'tcx> CoroutineClosureArgs<'tcx> { self.split().signature_parts_ty } + pub fn coroutine_closure_sig(self) -> ty::Binder<'tcx, CoroutineClosureSignature<'tcx>> { + let interior = self.coroutine_witness_ty(); + let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() }; + sig.map_bound(|sig| { + let [resume_ty, tupled_inputs_ty] = *sig.inputs() else { + bug!(); + }; + let [yield_ty, return_ty] = **sig.output().tuple_fields() else { bug!() }; + CoroutineClosureSignature { + interior, + tupled_inputs_ty, + resume_ty, + yield_ty, + return_ty, + c_variadic: sig.c_variadic, + unsafety: sig.unsafety, + abi: sig.abi, + } + }) + } + pub fn coroutine_captures_by_ref_ty(self) -> Ty<'tcx> { self.split().coroutine_captures_by_ref_ty } @@ -360,6 +382,103 @@ impl<'tcx> CoroutineClosureArgs<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] +pub struct CoroutineClosureSignature<'tcx> { + pub interior: Ty<'tcx>, + pub tupled_inputs_ty: Ty<'tcx>, + pub resume_ty: Ty<'tcx>, + pub yield_ty: Ty<'tcx>, + pub return_ty: Ty<'tcx>, + pub c_variadic: bool, + pub unsafety: hir::Unsafety, + pub abi: abi::Abi, +} + +impl<'tcx> CoroutineClosureSignature<'tcx> { + pub fn to_coroutine( + self, + tcx: TyCtxt<'tcx>, + parent_args: &'tcx [GenericArg<'tcx>], + coroutine_def_id: DefId, + tupled_upvars_ty: Ty<'tcx>, + ) -> Ty<'tcx> { + let coroutine_args = ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args, + resume_ty: self.resume_ty, + yield_ty: self.yield_ty, + return_ty: self.return_ty, + witness: self.interior, + tupled_upvars_ty, + }, + ); + + Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) + } + + pub fn to_coroutine_given_kind_and_upvars( + self, + tcx: TyCtxt<'tcx>, + parent_args: &'tcx [GenericArg<'tcx>], + coroutine_def_id: DefId, + closure_kind: ty::ClosureKind, + env_region: ty::Region<'tcx>, + closure_tupled_upvars_ty: Ty<'tcx>, + coroutine_captures_by_ref_ty: Ty<'tcx>, + ) -> Ty<'tcx> { + let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( + tcx, + closure_kind, + self.tupled_inputs_ty, + closure_tupled_upvars_ty, + coroutine_captures_by_ref_ty, + env_region, + ); + + self.to_coroutine(tcx, parent_args, coroutine_def_id, tupled_upvars_ty) + } + + /// Given a closure kind, compute the tupled upvars that the given coroutine would return. + pub fn tupled_upvars_by_closure_kind( + tcx: TyCtxt<'tcx>, + kind: ty::ClosureKind, + tupled_inputs_ty: Ty<'tcx>, + closure_tupled_upvars_ty: Ty<'tcx>, + coroutine_captures_by_ref_ty: Ty<'tcx>, + env_region: ty::Region<'tcx>, + ) -> Ty<'tcx> { + match kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { + let ty::FnPtr(sig) = *coroutine_captures_by_ref_ty.kind() else { + bug!(); + }; + let coroutine_captures_by_ref_ty = tcx.replace_escaping_bound_vars_uncached( + sig.output().skip_binder(), + FnMutDelegate { + consts: &mut |c, t| ty::Const::new_bound(tcx, ty::INNERMOST, c, t), + types: &mut |t| Ty::new_bound(tcx, ty::INNERMOST, t), + regions: &mut |_| env_region, + }, + ); + Ty::new_tup_from_iter( + tcx, + tupled_inputs_ty + .tuple_fields() + .iter() + .chain(coroutine_captures_by_ref_ty.tuple_fields()), + ) + } + ty::ClosureKind::FnOnce => Ty::new_tup_from_iter( + tcx, + tupled_inputs_ty + .tuple_fields() + .iter() + .chain(closure_tupled_upvars_ty.tuple_fields()), + ), + } + } +} /// Similar to `ClosureArgs`; see the above documentation for more. #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] pub struct CoroutineArgs<'tcx> { @@ -1495,7 +1614,7 @@ impl<'tcx> Ty<'tcx> { ) -> Ty<'tcx> { debug_assert_eq!( closure_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, "closure constructed with incorrect substitutions" ); Ty::new(tcx, CoroutineClosure(def_id, closure_args)) @@ -1835,6 +1954,11 @@ impl<'tcx> Ty<'tcx> { matches!(self.kind(), Coroutine(..)) } + #[inline] + pub fn is_coroutine_closure(self) -> bool { + matches!(self.kind(), CoroutineClosure(..)) + } + #[inline] pub fn is_integral(self) -> bool { matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_)) @@ -2144,7 +2268,7 @@ impl<'tcx> Ty<'tcx> { // "Bound" types appear in canonical queries when the // closure type is not yet known - Bound(..) | Infer(_) => None, + Bound(..) | Param(_) | Infer(_) => None, Error(_) => Some(ty::ClosureKind::Fn), diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 9bcfe9fbc33e6..9a2f2ceced1ed 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -822,6 +822,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let upvar_args = match closure_ty.kind() { ty::Closure(_, args) => ty::UpvarArgs::Closure(args), ty::Coroutine(_, args) => ty::UpvarArgs::Coroutine(args), + ty::CoroutineClosure(_, args) => ty::UpvarArgs::CoroutineClosure(args), _ => return, }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 22094c112fc18..35adcc33480ca 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -556,6 +556,9 @@ impl<'tcx> Cx<'tcx> { ty::Coroutine(def_id, args) => { (def_id, UpvarArgs::Coroutine(args), Some(tcx.coroutine_movability(def_id))) } + ty::CoroutineClosure(def_id, args) => { + (def_id, UpvarArgs::CoroutineClosure(args), None) + } _ => { span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5d0bb3954ccc6..f4f591d15b933 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -127,10 +127,24 @@ impl<'tcx> Cx<'tcx> { ty::Coroutine(..) => { Param { ty: closure_ty, pat: None, ty_span: None, self_kind: None, hir_id: None } } - ty::Closure(_, closure_args) => { + ty::Closure(_, args) => { let closure_env_ty = self.tcx.closure_env_ty( closure_ty, - closure_args.as_closure().kind(), + args.as_closure().kind(), + self.tcx.lifetimes.re_erased, + ); + Param { + ty: closure_env_ty, + pat: None, + ty_span: None, + self_kind: None, + hir_id: None, + } + } + ty::CoroutineClosure(_, args) => { + let closure_env_ty = self.tcx.closure_env_ty( + closure_ty, + args.as_coroutine_closure().kind(), self.tcx.lifetimes.re_erased, ); Param { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 2802f5491be03..a85e53ff241d5 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1149,6 +1149,9 @@ pub fn iter_fields<'tcx>( ty::Closure(_, args) => { iter_fields(args.as_closure().tupled_upvars_ty(), tcx, param_env, f); } + ty::CoroutineClosure(_, args) => { + iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, param_env, f); + } _ => (), } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index aa22b8c7c58e0..f2448ee3d44af 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -607,7 +607,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { AggregateKind::Array(_) | AggregateKind::Tuple | AggregateKind::Closure(_, _) - | AggregateKind::Coroutine(_, _) => VariantIdx::new(0), + | AggregateKind::Coroutine(_, _) + | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0), }, }, 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 5b4d58836b486..01fae7c0bec86 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -156,7 +156,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( fn is_closure_or_coroutine(statement: &Statement<'_>) -> bool { match statement.kind { StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind { - AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _) => true, + AggregateKind::Closure(_, _) + | AggregateKind::Coroutine(_, _) + | AggregateKind::CoroutineClosure(..) => true, _ => false, }, _ => false, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dbfc89c2d496e..587eb1c7cc5ae 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -167,6 +167,9 @@ symbols! { Break, C, CStr, + CallFuture, + CallMutFuture, + CallOnceFuture, Capture, Center, Cleanup, @@ -420,6 +423,7 @@ symbols! { async_closure, async_fn, async_fn_in_trait, + async_fn_kind_helper, async_fn_mut, async_fn_once, async_fn_track_caller, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index e1c68039e79fb..8451fbcc434cd 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -182,6 +182,20 @@ pub(super) trait GoalKind<'tcx>: kind: ty::ClosureKind, ) -> QueryResult<'tcx>; + /// An async closure is known to implement the `AsyncFn` family of traits + /// where `A` is given by the signature of the type. + fn consider_builtin_async_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + kind: ty::ClosureKind, + ) -> QueryResult<'tcx>; + + /// TODO: + fn consider_builtin_async_fn_kind_helper_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, @@ -461,6 +475,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) + } else if let Some(kind) = self.tcx().async_fn_trait_kind_from_def_id(trait_def_id) { + G::consider_builtin_async_fn_trait_candidates(self, goal, kind) + } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + G::consider_builtin_async_fn_kind_helper_candidate(self, goal) } else if lang_items.tuple_trait() == Some(trait_def_id) { G::consider_builtin_tuple_candidate(self, goal) } else if lang_items.pointee_trait() == Some(trait_def_id) { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 3c571e1d96f34..c35134c78eb16 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -1,11 +1,12 @@ //! Code which is used by built-in goals that match "structurally", such a auto //! traits, `Copy`/`Clone`. use rustc_data_structures::fx::FxHashMap; +use rustc_hir::LangItem; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use crate::solve::EvalCtxt; @@ -306,6 +307,114 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } } +// Returns a binder of the tupled inputs types, output type, and coroutine type +// from a builtin async closure type. +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>( + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + goal_kind: ty::ClosureKind, + env_region: ty::Region<'tcx>, +) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec>), NoSolution> +{ + match *self_ty.kind() { + ty::CoroutineClosure(def_id, args) => { + let args = args.as_coroutine_closure(); + let kind_ty = args.kind_ty(); + + if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + if !closure_kind.extends(goal_kind) { + return Err(NoSolution); + } + Ok(( + args.coroutine_closure_sig().map_bound(|sig| { + let coroutine_ty = sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + goal_kind, + env_region, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ); + (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) + }), + vec![], + )) + } else { + let helper_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + // FIXME(async_closures): Make this into a lang item. + let upvars_projection_def_id = tcx + .associated_items(helper_trait_def_id) + .in_definition_order() + .next() + .unwrap() + .def_id; + Ok(( + args.coroutine_closure_sig().map_bound(|sig| { + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + let coroutine_ty = sig.to_coroutine( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ); + (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) + }), + vec![ + ty::TraitRef::new( + tcx, + helper_trait_def_id, + [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], + ) + .to_predicate(tcx), + ], + )) + } + } + + ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution), + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::Dynamic(_, _, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => Err(NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected type `{self_ty}`") + } + } +} + /// Assemble a list of predicates that would be present on a theoretical /// user impl for an object type. These predicates must be checked any time /// we assemble a built-in object candidate for an object type, since they diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index e1c6f67f05eb0..47ba549022d9b 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -366,6 +366,119 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) } + fn consider_builtin_async_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + goal_kind: ty::ClosureKind, + ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); + + let env_region = match goal_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), + // Doesn't matter what this region is + ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, + }; + let (tupled_inputs_and_output_and_coroutine, nested_preds) = + structural_traits::extract_tupled_inputs_and_output_from_async_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + env_region, + )?; + let output_is_sized_pred = + tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| { + ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) + }); + + let pred = tupled_inputs_and_output_and_coroutine + .map_bound(|(inputs, output, coroutine)| { + let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) { + sym::CallOnceFuture => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), inputs], + ), + coroutine.into(), + ), + sym::CallMutFuture | sym::CallFuture => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [ + ty::GenericArg::from(goal.predicate.self_ty()), + inputs.into(), + env_region.into(), + ], + ), + coroutine.into(), + ), + sym::Output => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [ty::GenericArg::from(goal.predicate.self_ty()), inputs.into()], + ), + output.into(), + ), + name => bug!("no such associated type: {name}"), + }; + ty::ProjectionPredicate { projection_ty, term } + }) + .to_predicate(tcx); + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + Self::consider_implied_clause( + ecx, + goal, + pred, + [goal.with(tcx, output_is_sized_pred)] + .into_iter() + .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))), + ) + } + + fn consider_builtin_async_fn_kind_helper_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let [ + closure_fn_kind_ty, + goal_kind_ty, + borrow_region, + tupled_inputs_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + ] = **goal.predicate.alias.args + else { + bug!(); + }; + + let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { + // We don't need to worry about the self type being an infer var. + return Err(NoSolution); + }; + let Some(goal_kind) = goal_kind_ty.expect_ty().to_opt_closure_kind() else { + return Err(NoSolution); + }; + if !closure_kind.extends(goal_kind) { + return Err(NoSolution); + } + + let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( + ecx.tcx(), + goal_kind, + tupled_inputs_ty.expect_ty(), + tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty.expect_ty(), + borrow_region.expect_region(), + ); + + ecx.eq(goal.param_env, goal.predicate.term.ty().unwrap(), upvars_ty)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + fn consider_builtin_tuple_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index efaad47b6ddff..fd09a6b671dad 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -303,6 +303,66 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) } + fn consider_builtin_async_fn_trait_candidates( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + goal_kind: ty::ClosureKind, + ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + + let tcx = ecx.tcx(); + let (tupled_inputs_and_output_and_coroutine, nested_preds) = + structural_traits::extract_tupled_inputs_and_output_from_async_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + // This region doesn't matter because we're throwing away the coroutine type + tcx.lifetimes.re_static, + )?; + let output_is_sized_pred = + tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| { + ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) + }); + + let pred = tupled_inputs_and_output_and_coroutine + .map_bound(|(inputs, _, _)| { + ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + }) + .to_predicate(tcx); + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + Self::consider_implied_clause( + ecx, + goal, + pred, + [goal.with(tcx, output_is_sized_pred)] + .into_iter() + .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))), + ) + } + + fn consider_builtin_async_fn_kind_helper_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { + bug!(); + }; + + let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { + // We don't need to worry about the self type being an infer var. + return Err(NoSolution); + }; + let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(); + if closure_kind.extends(goal_kind) { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } + fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a960befcd4ba8..648f14beaa7a3 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1833,10 +1833,28 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( lang_items.fn_trait(), lang_items.fn_mut_trait(), lang_items.fn_once_trait(), + lang_items.async_fn_trait(), + lang_items.async_fn_mut_trait(), + lang_items.async_fn_once_trait(), ].contains(&Some(trait_ref.def_id)) { true - }else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { + } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) { + // FIXME(async_closures): Validity constraints here could be cleaned up. + if obligation.predicate.args.type_at(0).is_ty_var() + || obligation.predicate.args.type_at(4).is_ty_var() + || obligation.predicate.args.type_at(5).is_ty_var() + { + candidate_set.mark_ambiguous(); + true + } else if obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() + && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() + { + true + } else { + false + } + } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { match self_ty.kind() { ty::Bool | ty::Char @@ -2061,6 +2079,10 @@ fn confirm_select_candidate<'cx, 'tcx>( } else { confirm_fn_pointer_candidate(selcx, obligation, data) } + } else if selcx.tcx().async_fn_trait_kind_from_def_id(trait_def_id).is_some() { + confirm_async_closure_candidate(selcx, obligation, data) + } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + confirm_async_fn_kind_helper_candidate(selcx, obligation, data) } else { confirm_builtin_candidate(selcx, obligation, data) } @@ -2421,6 +2443,164 @@ fn confirm_callable_candidate<'cx, 'tcx>( confirm_param_env_candidate(selcx, obligation, predicate, true) } +fn confirm_async_closure_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + mut nested: Vec>, +) -> Progress<'tcx> { + let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else { + unreachable!( + "expected coroutine-closure self type for coroutine-closure candidate, found {self_ty}" + ) + }; + let args = args.as_coroutine_closure(); + let kind_ty = args.kind_ty(); + + let tcx = selcx.tcx(); + let goal_kind = + tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap(); + + let helper_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + nested.push(obligation.with( + tcx, + ty::TraitRef::new( + tcx, + helper_trait_def_id, + [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], + ), + )); + + let env_region = match goal_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2), + ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, + }; + + // FIXME(async_closures): Make this into a lang item. + let upvars_projection_def_id = + tcx.associated_items(helper_trait_def_id).in_definition_order().next().unwrap().def_id; + + // FIXME(async_closures): Confirmation is kind of a mess here. Ideally, + // we'd short-circuit when we know that the goal_kind >= closure_kind, and not + // register a nested predicate or create a new projection ty here. But I'm too + // lazy to make this more efficient atm, and we can always tweak it later, + // since all this does is make the solver do more work. + // + // The code duplication due to the different length args is kind of weird, too. + let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| { + let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) { + sym::CallOnceFuture => { + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + let coroutine_ty = sig.to_coroutine( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ); + ( + ty::AliasTy::new( + tcx, + obligation.predicate.def_id, + [self_ty, sig.tupled_inputs_ty], + ), + coroutine_ty.into(), + ) + } + sym::CallMutFuture | sym::CallFuture => { + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + let coroutine_ty = sig.to_coroutine( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ); + ( + ty::AliasTy::new( + tcx, + obligation.predicate.def_id, + [ + ty::GenericArg::from(self_ty), + sig.tupled_inputs_ty.into(), + env_region.into(), + ], + ), + coroutine_ty.into(), + ) + } + sym::Output => ( + ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty]), + sig.return_ty.into(), + ), + name => bug!("no such associated type: {name}"), + }; + ty::ProjectionPredicate { projection_ty, term } + }); + + confirm_param_env_candidate(selcx, obligation, poly_cache_entry, true) + .with_addl_obligations(nested) +} + +fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + nested: Vec>, +) -> Progress<'tcx> { + let [ + // We already checked that the goal_kind >= closure_kind + _closure_kind_ty, + goal_kind_ty, + borrow_region, + tupled_inputs_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + ] = **obligation.predicate.args + else { + bug!(); + }; + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new( + selcx.tcx(), + obligation.predicate.def_id, + obligation.predicate.args, + ), + term: ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( + selcx.tcx(), + goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(), + tupled_inputs_ty.expect_ty(), + tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty.expect_ty(), + borrow_region.expect_region(), + ) + .into(), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) + .with_addl_obligations(nested) +} + fn confirm_param_env_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, 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 b354ebf111f4c..75aedd5cd22ca 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -117,9 +117,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_iterator_candidates(obligation, &mut candidates); } else if lang_items.async_iterator_trait() == Some(def_id) { self.assemble_async_iterator_candidates(obligation, &mut candidates); + } else if lang_items.async_fn_kind_helper() == Some(def_id) { + self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates); } self.assemble_closure_candidates(obligation, &mut candidates); + self.assemble_async_closure_candidates(obligation, &mut candidates); self.assemble_fn_pointer_candidates(obligation, &mut candidates); self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_from_object_ty(obligation, &mut candidates); @@ -335,6 +338,49 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_async_closure_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let Some(goal_kind) = + self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()) + else { + return; + }; + + match *obligation.self_ty().skip_binder().kind() { + ty::CoroutineClosure(_, args) => { + if let Some(closure_kind) = + args.as_coroutine_closure().kind_ty().to_opt_closure_kind() + && !closure_kind.extends(goal_kind) + { + return; + } + candidates.vec.push(AsyncClosureCandidate); + } + ty::Infer(ty::TyVar(_)) => { + candidates.ambiguous = true; + } + _ => {} + } + } + + fn assemble_async_fn_kind_helper_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if let Some(closure_kind) = obligation.self_ty().skip_binder().to_opt_closure_kind() + && let Some(goal_kind) = + obligation.predicate.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind() + { + if closure_kind.extends(goal_kind) { + candidates.vec.push(AsyncFnKindHelperCandidate); + } + } + } + /// Implements one of the `Fn()` family for a fn pointer. fn assemble_fn_pointer_candidates( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 74f388e53a3c9..79336a9d4e8f0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -83,6 +83,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) } + AsyncClosureCandidate => { + let vtable_closure = self.confirm_async_closure_candidate(obligation)?; + ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) + } + + AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]), + CoroutineCandidate => { let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?; ImplSource::Builtin(BuiltinImplSource::Misc, vtable_coroutine) @@ -869,6 +876,49 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(nested) } + #[instrument(skip(self), level = "debug")] + fn confirm_async_closure_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + // Okay to skip binder because the args on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let ty::CoroutineClosure(closure_def_id, args) = *self_ty.kind() else { + bug!("async closure candidate for non-coroutine-closure {:?}", obligation); + }; + + let trait_ref = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { + ty::TraitRef::new( + self.tcx(), + obligation.predicate.def_id(), + [self_ty, sig.tupled_inputs_ty], + ) + }); + + let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + + let goal_kind = + self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); + nested.push(obligation.with( + self.tcx(), + ty::TraitRef::from_lang_item( + self.tcx(), + LangItem::AsyncFnKindHelper, + obligation.cause.span, + [ + args.as_coroutine_closure().kind_ty(), + Ty::from_closure_kind(self.tcx(), goal_kind), + ], + ), + )); + + debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); + + Ok(nested) + } + /// In the case of closure types and fn pointers, /// we currently treat the input type parameters on the trait as /// outputs. This means that when we have a match we have only diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e79277b89c4ae..7f41c73b72f0d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1864,6 +1864,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -1894,6 +1896,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(_) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -1930,6 +1934,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -1946,6 +1952,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -2054,6 +2062,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ImplCandidate(_) | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate @@ -2066,6 +2076,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitAliasCandidate, ImplCandidate(_) | ClosureCandidate { .. } + | AsyncClosureCandidate + | AsyncFnKindHelperCandidate | CoroutineCandidate | FutureCandidate | IteratorCandidate diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index af26616831fd0..8d1bdec66848c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -101,6 +101,42 @@ fn fn_sig_for_fn_abi<'tcx>( bound_vars, ) } + ty::CoroutineClosure(def_id, args) => { + let sig = args.as_coroutine_closure().coroutine_closure_sig(); + let bound_vars = tcx.mk_bound_variable_kinds_from_iter( + sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BoundRegionKind::BrEnv, + }; + let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + let env_ty = tcx.closure_env_ty( + Ty::new_coroutine_closure(tcx, def_id, args), + args.as_coroutine_closure().kind(), + env_region, + ); + + let sig = sig.skip_binder(); + ty::Binder::bind_with_vars( + tcx.mk_fn_sig( + iter::once(env_ty).chain([sig.tupled_inputs_ty]), + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.as_coroutine_closure().parent_args(), + tcx.coroutine_for_closure(def_id), + args.as_coroutine_closure().kind(), + env_region, + args.as_coroutine_closure().tupled_upvars_ty(), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + ), + sig.c_variadic, + sig.unsafety, + sig.abi, + ), + bound_vars, + ) + } ty::Coroutine(did, args) => { let coroutine_kind = tcx.coroutine_kind(did).unwrap(); let sig = args.as_coroutine().sig(); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index a5a2c53c7321b..50d27ed4cedbd 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -38,6 +38,7 @@ fn resolve_instance<'tcx>( debug!(" => nontrivial drop glue"); match *ty.kind() { ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Tuple(..) | ty::Adt(..) @@ -282,6 +283,16 @@ fn resolve_associated_item<'tcx>( tcx.item_name(trait_item_id) ), } + } else if tcx.async_fn_trait_kind_from_def_id(trait_ref.def_id).is_some() { + match *rcvr_args.type_at(0).kind() { + ty::CoroutineClosure(closure_def_id, args) => { + Some(Instance::new(closure_def_id, args)) + } + _ => bug!( + "no built-in definition for `{trait_ref}::{}` for non-lending-closure type", + tcx.item_name(trait_item_id) + ), + } } else { Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) } diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 965873f163eff..b11d5643990de 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -106,3 +106,11 @@ mod impls { } } } + +mod internal_implementation_detail { + // TODO: needs a detailed explanation + #[cfg_attr(not(bootstrap), lang = "async_fn_kind_helper")] + trait AsyncFnKindHelper { + type Assoc<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>; + } +} From fc4fff40385252212b9921928927568f233ba02f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 25 Jan 2024 00:30:55 +0000 Subject: [PATCH 064/101] Build a shim to call async closures with different AsyncFn trait kinds --- .../src/interpret/terminator.rs | 1 + compiler/rustc_middle/src/mir/mono.rs | 1 + compiler/rustc_middle/src/mir/visit.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 23 +++- compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_mir_transform/src/inline.rs | 1 + .../rustc_mir_transform/src/inline/cycle.rs | 1 + compiler/rustc_mir_transform/src/shim.rs | 121 +++++++++++++++++- compiler/rustc_monomorphize/src/collector.rs | 1 + .../rustc_monomorphize/src/partitioning.rs | 2 + .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 + compiler/rustc_ty_utils/src/abi.rs | 15 ++- compiler/rustc_ty_utils/src/instance.rs | 17 ++- 13 files changed, 175 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index b7ffb4a16fc31..4c8f68b25b55d 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -545,6 +545,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 91fdf0b312991..4a29171d8bf72 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -402,6 +402,7 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 591104ecc663d..6bc58adea0f83 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -345,6 +345,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | + ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 293fdb026b685..41ae136851ec1 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -82,11 +82,25 @@ pub enum InstanceDef<'tcx> { /// details on that). Virtual(DefId, usize), - /// `<[FnMut closure] as FnOnce>::call_once`. + /// `<[FnMut/Fn closure] as FnOnce>::call_once`. /// /// The `DefId` is the ID of the `call_once` method in `FnOnce`. + /// + /// This generates a body that will just borrow the (owned) self type, + /// and dispatch to the `FnMut::call_mut` instance for the closure. ClosureOnceShim { call_once: DefId, track_caller: bool }, + /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` or + /// `<[Fn coroutine-closure] as FnMut>::call_mut`. + /// + /// The body generated here differs significantly from the `ClosureOnceShim`, + /// since we need to generate a distinct coroutine type that will move the + /// closure's upvars *out* of the closure. + ConstructCoroutineInClosureShim { + coroutine_closure_def_id: DefId, + target_kind: ty::ClosureKind, + }, + /// Compiler-generated accessor for thread locals which returns a reference to the thread local /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking /// native support. @@ -168,6 +182,10 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(def_id) | InstanceDef::ThreadLocalShim(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } + | ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id: def_id, + target_kind: _, + } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, @@ -187,6 +205,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => None, @@ -282,6 +301,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(..) | InstanceDef::DropGlue(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::Item(_) | InstanceDef::Intrinsic(..) @@ -319,6 +339,7 @@ fn fmt_instance( InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"), InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), + InstanceDef::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4348d01eff58c..05875a9798bd8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1680,6 +1680,7 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 67668a216dee3..7c731b070a748 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -317,6 +317,7 @@ impl<'tcx> Inliner<'tcx> { | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index d30e0bad81301..3f3dc9145b632 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -87,6 +87,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::ThreadLocalShim { .. } | InstanceDef::CloneShim(..) => {} diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 89414ce940e05..29b83f58ef5db 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -3,8 +3,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{GenericArgs, CAPTURE_STRUCT_LOCAL}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_index::{Idx, IndexVec}; @@ -66,6 +66,21 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } + ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind, + } => match target_kind { + ty::ClosureKind::Fn => unreachable!("shouldn't be building shim for Fn"), + ty::ClosureKind::FnMut => { + let body = build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id); + // No need to optimize the body, it has already been optimized. + return body; + } + ty::ClosureKind::FnOnce => { + build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id) + } + }, + ty::InstanceDef::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? @@ -981,3 +996,107 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t let source = MirSource::from_instance(ty::InstanceDef::FnPtrAddrShim(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } + +fn build_construct_coroutine_by_move_shim<'tcx>( + tcx: TyCtxt<'tcx>, + coroutine_closure_def_id: DefId, +) -> Body<'tcx> { + let self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); + let ty::CoroutineClosure(_, args) = *self_ty.kind() else { + bug!(); + }; + + let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { + tcx.mk_fn_sig( + [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()), + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.as_coroutine_closure().parent_args(), + tcx.coroutine_for_closure(coroutine_closure_def_id), + ty::ClosureKind::FnOnce, + tcx.lifetimes.re_erased, + args.as_coroutine_closure().tupled_upvars_ty(), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + ), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }); + let sig = tcx.liberate_late_bound_regions(coroutine_closure_def_id, poly_sig); + let ty::Coroutine(coroutine_def_id, coroutine_args) = *sig.output().kind() else { + bug!(); + }; + + let span = tcx.def_span(coroutine_closure_def_id); + let locals = local_decls_for_sig(&sig, span); + + let mut fields = vec![]; + for idx in 1..sig.inputs().len() { + fields.push(Operand::Move(Local::from_usize(idx + 1).into())); + } + for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() { + fields.push(Operand::Move(tcx.mk_place_field( + Local::from_usize(1).into(), + FieldIdx::from_usize(idx), + ty, + ))); + } + + let source_info = SourceInfo::outermost(span); + let rvalue = Rvalue::Aggregate( + Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)), + IndexVec::from_raw(fields), + ); + let stmt = Statement { + source_info, + kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + }; + let statements = vec![stmt]; + let start_block = BasicBlockData { + statements, + terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), + is_cleanup: false, + }; + + let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind: ty::ClosureKind::FnOnce, + }); + + new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) +} + +fn build_construct_coroutine_by_mut_shim<'tcx>( + tcx: TyCtxt<'tcx>, + coroutine_closure_def_id: DefId, +) -> Body<'tcx> { + let mut body = tcx.optimized_mir(coroutine_closure_def_id).clone(); + let coroutine_closure_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); + let ty::CoroutineClosure(_, args) = *coroutine_closure_ty.kind() else { + bug!(); + }; + let args = args.as_coroutine_closure(); + + body.local_decls[RETURN_PLACE].ty = + tcx.instantiate_bound_regions_with_erased(args.coroutine_closure_sig().map_bound(|sig| { + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(coroutine_closure_def_id), + ty::ClosureKind::FnMut, + tcx.lifetimes.re_erased, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ) + })); + body.local_decls[CAPTURE_STRUCT_LOCAL].ty = + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_closure_ty); + + body.source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind: ty::ClosureKind::FnMut, + }); + + body +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b86244e5a4bfd..698fd63411412 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -983,6 +983,7 @@ fn visit_instance_use<'tcx>( | ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 7ff182381b835..46bd33c89e7e9 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -620,6 +620,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::Virtual(..) @@ -783,6 +784,7 @@ fn mono_item_visibility<'tcx>( | InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index e3fd64eb1891e..e0e9815cf40cd 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -799,6 +799,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrAddrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 8d1bdec66848c..3ea48ee824d47 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -111,11 +111,14 @@ fn fn_sig_for_fn_abi<'tcx>( kind: ty::BoundRegionKind::BrEnv, }; let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - let env_ty = tcx.closure_env_ty( - Ty::new_coroutine_closure(tcx, def_id, args), - args.as_coroutine_closure().kind(), - env_region, - ); + + let mut kind = args.as_coroutine_closure().kind(); + if let InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } = instance.def { + kind = target_kind; + } + + let env_ty = + tcx.closure_env_ty(Ty::new_coroutine_closure(tcx, def_id, args), kind, env_region); let sig = sig.skip_binder(); ty::Binder::bind_with_vars( @@ -125,7 +128,7 @@ fn fn_sig_for_fn_abi<'tcx>( tcx, args.as_coroutine_closure().parent_args(), tcx.coroutine_for_closure(def_id), - args.as_coroutine_closure().kind(), + kind, env_region, args.as_coroutine_closure().tupled_upvars_ty(), args.as_coroutine_closure().coroutine_captures_by_ref_ty(), diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 50d27ed4cedbd..fc224d242db6d 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -283,10 +283,21 @@ fn resolve_associated_item<'tcx>( tcx.item_name(trait_item_id) ), } - } else if tcx.async_fn_trait_kind_from_def_id(trait_ref.def_id).is_some() { + } else if let Some(target_kind) = tcx.async_fn_trait_kind_from_def_id(trait_ref.def_id) + { match *rcvr_args.type_at(0).kind() { - ty::CoroutineClosure(closure_def_id, args) => { - Some(Instance::new(closure_def_id, args)) + ty::CoroutineClosure(coroutine_closure_def_id, args) => { + if target_kind > args.as_coroutine_closure().kind() { + Some(Instance { + def: ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind, + }, + args, + }) + } else { + Some(Instance::new(coroutine_closure_def_id, args)) + } } _ => bug!( "no built-in definition for `{trait_ref}::{}` for non-lending-closure type", From 427896dd7e39f1aaf3e3cbc15e5ddf77d45a6aec Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 24 Jan 2024 23:38:33 +0000 Subject: [PATCH 065/101] Construct body for by-move coroutine closure output --- .../src/type_check/input_output.rs | 1 + .../src/interpret/terminator.rs | 1 + compiler/rustc_hir_typeck/src/callee.rs | 1 + compiler/rustc_hir_typeck/src/closure.rs | 11 ++ compiler/rustc_hir_typeck/src/upvar.rs | 10 ++ compiler/rustc_middle/src/mir/mod.rs | 5 + compiler/rustc_middle/src/mir/mono.rs | 1 + compiler/rustc_middle/src/mir/visit.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 21 +++- compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_middle/src/ty/sty.rs | 47 ++++++-- compiler/rustc_mir_transform/src/coroutine.rs | 3 + .../src/coroutine/by_move_body.rs | 108 ++++++++++++++++++ compiler/rustc_mir_transform/src/inline.rs | 1 + .../rustc_mir_transform/src/inline/cycle.rs | 1 + compiler/rustc_mir_transform/src/lib.rs | 4 + .../rustc_mir_transform/src/pass_manager.rs | 6 + compiler/rustc_mir_transform/src/shim.rs | 12 ++ compiler/rustc_monomorphize/src/collector.rs | 3 +- .../rustc_monomorphize/src/partitioning.rs | 4 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 + .../src/solve/assembly/structural_traits.rs | 1 + .../src/traits/project.rs | 2 + ...await.b-{closure#0}.coroutine_resume.0.mir | 2 + 24 files changed, 233 insertions(+), 15 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/coroutine/by_move_body.rs diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index a3e5088ee09aa..ace9c5ae71d6e 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -85,6 +85,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.tcx(), ty::CoroutineArgsParts { parent_args: args.parent_args(), + kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()), resume_ty: next_ty_var(), yield_ty: next_ty_var(), witness: next_ty_var(), diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 4c8f68b25b55d..b8d6836da14a8 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -546,6 +546,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineByMoveShim { .. } | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 1858b2770cdbc..730a475f63049 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -183,6 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coroutine_closure_sig.to_coroutine( self.tcx, closure_args.parent_args(), + closure_args.kind_ty(), self.tcx.coroutine_for_closure(def_id), tupled_upvars_ty, ), diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 1d024efdd499f..014293c1f8325 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -175,10 +175,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { interior, )); + let kind_ty = match kind { + hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) => self + .next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + _ => tcx.types.unit, + }; + let coroutine_args = ty::CoroutineArgs::new( tcx, ty::CoroutineArgsParts { parent_args, + kind_ty, resume_ty, yield_ty, return_ty: liberated_sig.output(), @@ -256,6 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sig.to_coroutine( tcx, parent_args, + closure_kind_ty, tcx.coroutine_for_closure(expr_def_id), coroutine_upvars_ty, ) diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index b087d6d9e570d..d4e072976fa69 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -393,6 +393,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args.as_coroutine_closure().coroutine_captures_by_ref_ty(), coroutine_captures_by_ref_ty, ); + + let ty::Coroutine(_, args) = *self.typeck_results.borrow().expr_ty(body.value).kind() + else { + bug!(); + }; + self.demand_eqtype( + span, + args.as_coroutine().kind_ty(), + Ty::from_closure_kind(self.tcx, closure_kind), + ); } self.log_closure_min_capture_info(closure_def_id, span); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c9e69253701c5..d88e9261e5a1b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -262,6 +262,10 @@ pub struct CoroutineInfo<'tcx> { /// Coroutine drop glue. This field is populated after the state transform pass. pub coroutine_drop: Option>, + /// The body of the coroutine, modified to take its upvars by move. + /// TODO: + pub by_move_body: Option>, + /// The layout of a coroutine. This field is populated after the state transform pass. pub coroutine_layout: Option>, @@ -281,6 +285,7 @@ impl<'tcx> CoroutineInfo<'tcx> { coroutine_kind, yield_ty: Some(yield_ty), resume_ty: Some(resume_ty), + by_move_body: None, coroutine_drop: None, coroutine_layout: None, } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 4a29171d8bf72..e6d1535fdf2f6 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -403,6 +403,7 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::Virtual(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineByMoveShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 6bc58adea0f83..ce1859d6adae3 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -346,6 +346,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } | + ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id: _def_id } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 41ae136851ec1..44bf3c32b487d 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -101,6 +101,9 @@ pub enum InstanceDef<'tcx> { target_kind: ty::ClosureKind, }, + /// TODO: + CoroutineByMoveShim { coroutine_def_id: DefId }, + /// Compiler-generated accessor for thread locals which returns a reference to the thread local /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking /// native support. @@ -186,6 +189,7 @@ impl<'tcx> InstanceDef<'tcx> { coroutine_closure_def_id: def_id, target_kind: _, } + | ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id: def_id } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, @@ -206,6 +210,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineByMoveShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => None, @@ -302,6 +307,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::DropGlue(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineByMoveShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::Item(_) | InstanceDef::Intrinsic(..) @@ -340,6 +346,7 @@ fn fmt_instance( InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), InstanceDef::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), + InstanceDef::CoroutineByMoveShim { .. } => write!(f, " - shim"), InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"), @@ -631,7 +638,19 @@ impl<'tcx> Instance<'tcx> { }; if tcx.lang_items().get(coroutine_callable_item) == Some(trait_item_id) { - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args: args }) + let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind() + else { + bug!() + }; + + if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() { + Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) + } else { + Some(Instance { + def: ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id }, + args, + }) + } } else { // All other methods should be defaulted methods of the built-in trait. // This is important for `Iterator`'s combinators, but also useful for diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 05875a9798bd8..9ceb3ec3f615c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1681,6 +1681,7 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineByMoveShim { .. } | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e2a2e24f06dd8..8918a3735d618 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -399,6 +399,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { self, tcx: TyCtxt<'tcx>, parent_args: &'tcx [GenericArg<'tcx>], + kind_ty: Ty<'tcx>, coroutine_def_id: DefId, tupled_upvars_ty: Ty<'tcx>, ) -> Ty<'tcx> { @@ -406,6 +407,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { tcx, ty::CoroutineArgsParts { parent_args, + kind_ty, resume_ty: self.resume_ty, yield_ty: self.yield_ty, return_ty: self.return_ty, @@ -436,7 +438,13 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { env_region, ); - self.to_coroutine(tcx, parent_args, coroutine_def_id, tupled_upvars_ty) + self.to_coroutine( + tcx, + parent_args, + Ty::from_closure_kind(tcx, closure_kind), + coroutine_def_id, + tupled_upvars_ty, + ) } /// Given a closure kind, compute the tupled upvars that the given coroutine would return. @@ -488,6 +496,8 @@ pub struct CoroutineArgs<'tcx> { pub struct CoroutineArgsParts<'tcx> { /// This is the args of the typeck root. pub parent_args: &'tcx [GenericArg<'tcx>], + // TODO: why + pub kind_ty: Ty<'tcx>, pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>, @@ -506,6 +516,7 @@ impl<'tcx> CoroutineArgs<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, parts: CoroutineArgsParts<'tcx>) -> CoroutineArgs<'tcx> { CoroutineArgs { args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ + parts.kind_ty.into(), parts.resume_ty.into(), parts.yield_ty.into(), parts.return_ty.into(), @@ -519,16 +530,23 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The ordering assumed here must match that used by `CoroutineArgs::new` above. fn split(self) -> CoroutineArgsParts<'tcx> { match self.args[..] { - [ref parent_args @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => { - CoroutineArgsParts { - parent_args, - resume_ty: resume_ty.expect_ty(), - yield_ty: yield_ty.expect_ty(), - return_ty: return_ty.expect_ty(), - witness: witness.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - } - } + [ + ref parent_args @ .., + kind_ty, + resume_ty, + yield_ty, + return_ty, + witness, + tupled_upvars_ty, + ] => CoroutineArgsParts { + parent_args, + kind_ty: kind_ty.expect_ty(), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + witness: witness.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + }, _ => bug!("coroutine args missing synthetics"), } } @@ -538,6 +556,11 @@ impl<'tcx> CoroutineArgs<'tcx> { self.split().parent_args } + // TODO: + pub fn kind_ty(self) -> Ty<'tcx> { + self.split().kind_ty + } + /// This describes the types that can be contained in a coroutine. /// It will be a type variable initially and unified in the last stages of typeck of a body. /// It contains a tuple of all the types that could end up on a coroutine frame. @@ -1628,7 +1651,7 @@ impl<'tcx> Ty<'tcx> { ) -> Ty<'tcx> { debug_assert_eq!( coroutine_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6, "coroutine constructed with incorrect number of substitutions" ); Ty::new(tcx, Coroutine(def_id, coroutine_args)) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index bde879f6067c5..297b2fa143de2 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -50,6 +50,9 @@ //! For coroutines with state 1 (returned) and state 2 (poisoned) it does nothing. //! Otherwise it drops all the values in scope at the last suspension point. +mod by_move_body; +pub use by_move_body::ByMoveBody; + use crate::abort_unwinding_calls; use crate::deref_separator::deref_finder; use crate::errors; diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs new file mode 100644 index 0000000000000..4e3e70bdafef1 --- /dev/null +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -0,0 +1,108 @@ +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::{self, MirPass}; +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; +use rustc_target::abi::FieldIdx; + +pub struct ByMoveBody; + +impl<'tcx> MirPass<'tcx> for ByMoveBody { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { + let Some(coroutine_def_id) = body.source.def_id().as_local() else { + return; + }; + let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) = + tcx.coroutine_kind(coroutine_def_id) + else { + return; + }; + let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; + let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!() }; + if args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() == ty::ClosureKind::FnOnce { + return; + } + + let mut by_ref_fields = FxIndexSet::default(); + let by_move_upvars = Ty::new_tup_from_iter( + tcx, + tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| { + if capture.is_by_ref() { + by_ref_fields.insert(FieldIdx::from_usize(idx)); + } + capture.place.ty() + }), + ); + let by_move_coroutine_ty = Ty::new_coroutine( + tcx, + coroutine_def_id.to_def_id(), + ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args: args.as_coroutine().parent_args(), + kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce), + resume_ty: args.as_coroutine().resume_ty(), + yield_ty: args.as_coroutine().yield_ty(), + return_ty: args.as_coroutine().return_ty(), + witness: args.as_coroutine().witness(), + tupled_upvars_ty: by_move_upvars, + }, + ) + .args, + ); + + let mut by_move_body = body.clone(); + MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body); + by_move_body.source = mir::MirSource { + instance: InstanceDef::CoroutineByMoveShim { + coroutine_def_id: coroutine_def_id.to_def_id(), + }, + promoted: None, + }; + + body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); + } +} + +struct MakeByMoveBody<'tcx> { + tcx: TyCtxt<'tcx>, + by_ref_fields: FxIndexSet, + by_move_coroutine_ty: Ty<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_place( + &mut self, + place: &mut mir::Place<'tcx>, + context: mir::visit::PlaceContext, + location: mir::Location, + ) { + if place.local == ty::CAPTURE_STRUCT_LOCAL + && !place.projection.is_empty() + && let mir::ProjectionElem::Field(idx, ty) = place.projection[0] + && self.by_ref_fields.contains(&idx) + { + let (begin, end) = place.projection[1..].split_first().unwrap(); + assert_eq!(*begin, mir::ProjectionElem::Deref); + *place = mir::Place { + local: place.local, + projection: self.tcx.mk_place_elems_from_iter( + [mir::ProjectionElem::Field(idx, ty.builtin_deref(true).unwrap().ty)] + .into_iter() + .chain(end.iter().copied()), + ), + }; + } + self.super_place(place, context, location); + } + + fn visit_local_decl(&mut self, local: mir::Local, local_decl: &mut mir::LocalDecl<'tcx>) { + if local == ty::CAPTURE_STRUCT_LOCAL { + local_decl.ty = self.by_move_coroutine_ty; + } + } +} diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 7c731b070a748..24bc84a235c2d 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -318,6 +318,7 @@ impl<'tcx> Inliner<'tcx> { | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineByMoveShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 3f3dc9145b632..77ff780393efb 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -88,6 +88,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineByMoveShim { .. } | InstanceDef::ThreadLocalShim { .. } | InstanceDef::CloneShim(..) => {} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 69f93fa3a0e21..031515ea95828 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -307,6 +307,10 @@ fn mir_const(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), + // If this is an async closure's output coroutine, generate + // by-move and by-mut bodies if needed. We do this first so + // they can be optimized in lockstep with their parent bodies. + &coroutine::ByMoveBody, // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, &rustc_peek::SanityCheck, // Just a lint diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index c1ef2b9f887fb..c7e770904fbb8 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -189,6 +189,12 @@ fn run_passes_inner<'tcx>( body.pass_count = 1; } + + if let Some(coroutine) = body.coroutine.as_mut() + && let Some(by_move_body) = coroutine.by_move_body.as_mut() + { + run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each); + } } pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 29b83f58ef5db..668ccdd873550 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -81,6 +81,18 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' } }, + ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id } => { + return tcx + .optimized_mir(coroutine_def_id) + .coroutine + .as_ref() + .unwrap() + .by_move_body + .as_ref() + .unwrap() + .clone(); + } + ty::InstanceDef::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 698fd63411412..cf3c8e1fdd3b4 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -983,7 +983,8 @@ fn visit_instance_use<'tcx>( | ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineByMoveShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 46bd33c89e7e9..22b35c4344b86 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -620,7 +620,8 @@ fn characteristic_def_id_of_mono_item<'tcx>( | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineByMoveShim { .. } | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::Virtual(..) @@ -785,6 +786,7 @@ fn mono_item_visibility<'tcx>( | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } + | InstanceDef::CoroutineByMoveShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index e0e9815cf40cd..3c1858e920b04 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -800,6 +800,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { | ty::InstanceDef::FnPtrAddrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineByMoveShim { .. } | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index c35134c78eb16..0699026117dae 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -366,6 +366,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc let coroutine_ty = sig.to_coroutine( tcx, args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), tcx.coroutine_for_closure(def_id), tupled_upvars_ty, ); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 648f14beaa7a3..db1e89ae72fdf 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2505,6 +2505,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let coroutine_ty = sig.to_coroutine( tcx, args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), tcx.coroutine_for_closure(def_id), tupled_upvars_ty, ); @@ -2533,6 +2534,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let coroutine_ty = sig.to_coroutine( tcx, args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), tcx.coroutine_for_closure(def_id), tupled_upvars_ty, ); diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 3c0d4008c9018..9c8cf8763fdf1 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -5,6 +5,7 @@ ty: Coroutine( DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), [ + (), std::future::ResumeTy, (), (), @@ -22,6 +23,7 @@ ty: Coroutine( DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), [ + (), std::future::ResumeTy, (), (), From 881b6b5149e882434a8df80a829bcfde0a2e9d37 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 25 Jan 2024 03:50:23 +0000 Subject: [PATCH 066/101] Bless tests, add comments --- .../src/type_check/input_output.rs | 5 +- .../rustc_borrowck/src/universal_regions.rs | 5 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 12 ++- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/select.rs | 4 +- compiler/rustc_middle/src/ty/instance.rs | 5 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 36 +++++++- .../rustc_smir/src/rustc_smir/convert/mir.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + .../src/solve/assembly/mod.rs | 4 +- .../src/solve/assembly/structural_traits.rs | 13 +-- .../src/traits/project.rs | 14 +-- compiler/rustc_type_ir/src/ty_kind.rs | 6 +- library/core/src/ops/async_function.rs | 21 ++++- .../async-borrowck-escaping-closure-error.rs | 3 +- ...ync-borrowck-escaping-closure-error.stderr | 28 +++--- .../async-closures/higher-ranked.rs | 4 +- .../async-closures/higher-ranked.stderr | 17 ---- .../issue-74072-lifetime-name-annotations.rs | 6 +- ...sue-74072-lifetime-name-annotations.stderr | 90 +++++++++++++------ .../binder/async-closure-with-binder.rs | 7 +- .../binder/async-closure-with-binder.stderr | 16 ---- ...rg-where-it-should-have-been-called.stderr | 12 +-- tests/ui/symbol-names/basic.legacy.stderr | 4 +- .../ui/symbol-names/issue-60925.legacy.stderr | 4 +- 28 files changed, 201 insertions(+), 126 deletions(-) delete mode 100644 tests/ui/async-await/async-closures/higher-ranked.stderr delete mode 100644 tests/ui/closures/binder/async-closure-with-binder.stderr diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index ace9c5ae71d6e..46fd0ce2b39a0 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -47,8 +47,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { user_provided_sig, ); - // FIXME(async_closures): We must apply the same transformation to our - // signature here as we do during closure checking. + // FIXME(async_closures): It's kind of wacky that we must apply this + // transformation here, since we do the same thing in HIR typeck. + // Maybe we could just fix up the canonicalized signature during HIR typeck? if let DefiningTy::CoroutineClosure(_, args) = self.borrowck_context.universal_regions.defining_ty { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9c266d123b338..d696e624823af 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -98,7 +98,10 @@ pub enum DefiningTy<'tcx> { Coroutine(DefId, GenericArgsRef<'tcx>), /// The MIR is a special kind of closure that returns coroutines. - /// TODO: describe how to make the sig... + /// + /// See the documentation on `CoroutineClosureSignature` for details + /// on how to construct the callable signature of the coroutine from + /// its args. CoroutineClosure(DefId, GenericArgsRef<'tcx>), /// The MIR is a fn item with the given `DefId` and args. The signature diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d30c7a4fb3899..23fb7eba65606 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -335,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - // For this check, we do *not* want to treat async coroutine closures (async blocks) + // For this check, we do *not* want to treat async coroutine-closures (async blocks) // as proper closures. Doing so would regress type inference when feeding // the return value of an argument-position async block to an argument-position // closure wrapped in a block. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d88e9261e5a1b..3d6c28088ad59 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -262,8 +262,16 @@ pub struct CoroutineInfo<'tcx> { /// Coroutine drop glue. This field is populated after the state transform pass. pub coroutine_drop: Option>, - /// The body of the coroutine, modified to take its upvars by move. - /// TODO: + /// The body of the coroutine, modified to take its upvars by move rather than by ref. + /// + /// This is used by coroutine-closures, which must return a different flavor of coroutine + /// when called using `AsyncFnOnce::call_once`. It is produced by the `ByMoveBody` which + /// is run right after building the initial MIR, and will only be populated for coroutines + /// which come out of the async closure desugaring. + /// + /// This body should be processed in lockstep with the containing body -- any optimization + /// passes, etc, should be applied to this body as well. This is done automatically if + /// using `run_passes`. pub by_move_body: Option>, /// The layout of a coroutine. This field is populated after the state transform pass. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f9ab32b16f534..938fba0ed0981 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -756,7 +756,7 @@ rustc_queries! { } query coroutine_for_closure(def_id: DefId) -> DefId { - desc { |_tcx| "TODO" } + desc { |_tcx| "Given a coroutine-closure def id, return the def id of the coroutine returned by it" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 4e11575cf9800..28eba133c76df 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -138,7 +138,9 @@ pub enum SelectionCandidate<'tcx> { /// generated for an `async ||` expression. AsyncClosureCandidate, - // TODO: + /// Implementation of the the `AsyncFnKindHelper` helper trait, which + /// is used internally to delay computation for async closures until after + /// upvar analysis is performed in HIR typeck. AsyncFnKindHelperCandidate, /// Implementation of a `Coroutine` trait by one of the anonymous types diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 44bf3c32b487d..2c80dd021451f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -101,7 +101,10 @@ pub enum InstanceDef<'tcx> { target_kind: ty::ClosureKind, }, - /// TODO: + /// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce` + /// is called on a coroutine-closure whose closure kind is not `FnOnce`. This + /// will select the body that is produced by the `ByMoveBody` transform, and thus + /// take and use all of its upvars by-move rather than by-ref. CoroutineByMoveShim { coroutine_def_id: DefId }, /// Compiler-generated accessor for thread locals which returns a reference to the thread local diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index be6b887ba7dc6..c0bfd2380ade0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -877,7 +877,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::CoroutineClosure(did, args) => { p!(write("{{")); if !self.should_print_verbose() { - p!(write("coroutine closure")); + p!(write("coroutine-closure")); // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { if self.tcx().sess.opts.unstable_opts.span_free_formats { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8918a3735d618..3bbebaddbdd33 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -276,11 +276,31 @@ pub struct CoroutineClosureArgs<'tcx> { } pub struct CoroutineClosureArgsParts<'tcx> { + /// This is the args of the typeck root. pub parent_args: &'tcx [GenericArg<'tcx>], + /// Represents the maximum calling capability of the closure. pub closure_kind_ty: Ty<'tcx>, + /// Represents all of the relevant parts of the coroutine returned by this + /// coroutine-closure. This signature parts type will have the general + /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where + /// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the + /// coroutine returned by the coroutine-closure. + /// + /// Use `coroutine_closure_sig` to break up this type rather than using it + /// yourself. pub signature_parts_ty: Ty<'tcx>, + /// The upvars captured by the closure. Remains an inference variable + /// until the upvar analysis, which happens late in HIR typeck. pub tupled_upvars_ty: Ty<'tcx>, + /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`. + /// This allows us to represent the binder of the self-captures of the closure. + /// + /// For example, if the coroutine returned by the closure borrows `String` + /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`, + /// while the `tupled_upvars_ty`, representing the by-move version of the same + /// captures, will be `(String,)`. pub coroutine_captures_by_ref_ty: Ty<'tcx>, + /// Witness type returned by the generator produced by this coroutine-closure. pub coroutine_witness_ty: Ty<'tcx>, } @@ -496,15 +516,27 @@ pub struct CoroutineArgs<'tcx> { pub struct CoroutineArgsParts<'tcx> { /// This is the args of the typeck root. pub parent_args: &'tcx [GenericArg<'tcx>], - // TODO: why + + /// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut` + /// implementations must be distinguished since the former takes the closure's + /// upvars by move, and the latter takes the closure's upvars by ref. + /// + /// This field distinguishes these fields so that codegen can select the right + /// body for the coroutine. This has the same type representation as the closure + /// kind: `i8`/`i16`/`i32`. + /// + /// For regular coroutines, this field will always just be `()`. pub kind_ty: Ty<'tcx>, + pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>, + /// The interior type of the coroutine. /// Represents all types that are stored in locals /// in the coroutine's body. pub witness: Ty<'tcx>, + /// The upvars captured by the closure. Remains an inference variable /// until the upvar analysis, which happens late in HIR typeck. pub tupled_upvars_ty: Ty<'tcx>, @@ -556,7 +588,7 @@ impl<'tcx> CoroutineArgs<'tcx> { self.split().parent_args } - // TODO: + // Returns the kind of the coroutine. See docs on the `kind_ty` field. pub fn kind_ty(self) -> Ty<'tcx> { self.split().kind_ty } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 65ff85a96695b..41a4edfc03b58 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -539,7 +539,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { ) } mir::AggregateKind::CoroutineClosure(..) => { - todo!("FIXME(async_closure): Lower these to SMIR") + todo!("FIXME(async_closures): Lower these to SMIR") } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 3c1858e920b04..066348dcb67bc 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -383,7 +383,7 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { tables.closure_def(*def_id), generic_args.stable(tables), )), - ty::CoroutineClosure(..) => todo!("/* TODO */"), + ty::CoroutineClosure(..) => todo!("FIXME(async_closures): Lower these to SMIR"), ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine( tables.coroutine_def(*def_id), generic_args.stable(tables), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 587eb1c7cc5ae..4203cb29db6c5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -321,6 +321,7 @@ symbols! { TyCtxt, TyKind, Unknown, + Upvars, Vec, VecDeque, Wrapper, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 8451fbcc434cd..7052fd776b0f2 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -190,7 +190,9 @@ pub(super) trait GoalKind<'tcx>: kind: ty::ClosureKind, ) -> QueryResult<'tcx>; - /// TODO: + /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which + /// is used internally to delay computation for async closures until after + /// upvar analysis is performed in HIR typeck. fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 0699026117dae..dbf3e4876a960 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -8,6 +8,7 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::ty::{ self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +use rustc_span::sym; use crate::solve::EvalCtxt; @@ -274,7 +275,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( Ok(Some(closure_args.sig().map_bound(|sig| (sig.inputs()[0], sig.output())))) } - // Coroutine closures don't implement `Fn` traits the normal way. + // Coroutine-closures don't implement `Fn` traits the normal way. ty::CoroutineClosure(..) => Err(NoSolution), ty::Bool @@ -341,11 +342,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc vec![], )) } else { - let helper_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); - // FIXME(async_closures): Make this into a lang item. + let async_fn_kind_trait_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); let upvars_projection_def_id = tcx - .associated_items(helper_trait_def_id) - .in_definition_order() + .associated_items(async_fn_kind_trait_def_id) + .filter_by_name_unhygienic(sym::Upvars) .next() .unwrap() .def_id; @@ -375,7 +376,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc vec![ ty::TraitRef::new( tcx, - helper_trait_def_id, + async_fn_kind_trait_def_id, [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], ) .to_predicate(tcx), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index db1e89ae72fdf..a8d6b9812be3a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2461,12 +2461,13 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let goal_kind = tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap(); - let helper_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + let async_fn_kind_helper_trait_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); nested.push(obligation.with( tcx, ty::TraitRef::new( tcx, - helper_trait_def_id, + async_fn_kind_helper_trait_def_id, [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], ), )); @@ -2476,9 +2477,12 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, }; - // FIXME(async_closures): Make this into a lang item. - let upvars_projection_def_id = - tcx.associated_items(helper_trait_def_id).in_definition_order().next().unwrap().def_id; + let upvars_projection_def_id = tcx + .associated_items(async_fn_kind_helper_trait_def_id) + .filter_by_name_unhygienic(sym::Upvars) + .next() + .unwrap() + .def_id; // FIXME(async_closures): Confirmation is kind of a mess here. Ideally, // we'd short-circuit when we know that the goal_kind >= closure_kind, and not diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 5941fce88250a..a4fe572067b03 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -202,7 +202,11 @@ pub enum TyKind { /// `ClosureArgs` for more details. Closure(I::DefId, I::GenericArgs), - /// TODO + /// The anonymous type of a closure. Used to represent the type of `async |a| a`. + /// + /// Coroutine-closure args contain both the - potentially substituted - generic + /// parameters of its parent and some synthetic parameters. See the documentation + /// for `CoroutineClosureArgs` for more details. CoroutineClosure(I::DefId, I::GenericArgs), /// The anonymous type of a coroutine. Used to represent the type of diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index b11d5643990de..efbe9d164c3a7 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -108,9 +108,26 @@ mod impls { } mod internal_implementation_detail { - // TODO: needs a detailed explanation + /// A helper trait that is used to enforce that the `ClosureKind` of a goal + /// is within the capabilities of a `CoroutineClosure`, and which allows us + /// to delay the projection of the tupled upvar types until after upvar + /// analysis is complete. + /// + /// The `Self` type is expected to be the `kind_ty` of the coroutine-closure, + /// and thus either `?0` or `i8`/`i16`/`i32` (see docs for `ClosureKind` + /// for an explanation of that). The `GoalKind` is also the same type, but + /// representing the kind of the trait that the closure is being called with. #[cfg_attr(not(bootstrap), lang = "async_fn_kind_helper")] trait AsyncFnKindHelper { - type Assoc<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>; + // Projects a set of closure inputs (arguments), a region, and a set of upvars + // (by move and by ref) to the upvars that we expect the coroutine to have + // according to the `GoalKind` parameter above. + // + // The `Upvars` parameter should be the upvars of the parent coroutine-closure, + // and the `BorrowedUpvarsAsFnPtr` will be a function pointer that has the shape + // `for<'env> fn() -> (&'env T, ...)`. This allows us to represent the binder + // of the closure's self-capture, and these upvar types will be instantiated with + // the `'closure_env` region provided to the associated type. + type Upvars<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>; } } diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs index c02bac2d7dd49..2a3e382e11868 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -4,7 +4,8 @@ fn foo() -> Box> { let x = 0u32; Box::new((async || x)()) - //~^ ERROR closure may outlive the current function, but it borrows `x`, which is owned by the current function + //~^ ERROR cannot return value referencing local variable `x` + //~| ERROR cannot return value referencing temporary value } fn main() { diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr index 87851e1ae5be5..be67c78221a7c 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr @@ -1,21 +1,21 @@ -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/async-borrowck-escaping-closure-error.rs:6:15 +error[E0515]: cannot return value referencing local variable `x` + --> $DIR/async-borrowck-escaping-closure-error.rs:6:5 | LL | Box::new((async || x)()) - | ^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here + | ^^^^^^^^^------------^^^ + | | | + | | `x` is borrowed here + | returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing temporary value --> $DIR/async-borrowck-escaping-closure-error.rs:6:5 | LL | Box::new((async || x)()) - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | Box::new((async move || x)()) - | ++++ + | ^^^^^^^^^------------^^^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0373`. +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/async-await/async-closures/higher-ranked.rs b/tests/ui/async-await/async-closures/higher-ranked.rs index f0bdcf691ae2f..5bbcc7041a8f8 100644 --- a/tests/ui/async-await/async-closures/higher-ranked.rs +++ b/tests/ui/async-await/async-closures/higher-ranked.rs @@ -1,12 +1,10 @@ // edition:2021 +// check-pass #![feature(async_closure)] fn main() { let x = async move |x: &str| { - //~^ ERROR lifetime may not live long enough - // This error is proof that the `&str` type is higher-ranked. - // This won't work until async closures are fully impl'd. println!("{x}"); }; } diff --git a/tests/ui/async-await/async-closures/higher-ranked.stderr b/tests/ui/async-await/async-closures/higher-ranked.stderr deleted file mode 100644 index fb02a15b079d7..0000000000000 --- a/tests/ui/async-await/async-closures/higher-ranked.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/higher-ranked.rs:6:34 - | -LL | let x = async move |x: &str| { - | ____________________________-___-_^ - | | | | - | | | return type of closure `{async closure body@$DIR/higher-ranked.rs:6:34: 11:6}` contains a lifetime `'2` - | | let's call the lifetime of this reference `'1` -LL | | -LL | | // This error is proof that the `&str` type is higher-ranked. -LL | | // This won't work until async closures are fully impl'd. -LL | | println!("{x}"); -LL | | }; - | |_____^ returning this value requires that `'1` must outlive `'2` - -error: aborting due to 1 previous error - diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs index 2d453e7891e5f..904d28fb0a78d 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs @@ -12,7 +12,8 @@ pub async fn async_fn(x: &mut i32) -> &i32 { pub fn async_closure(x: &mut i32) -> impl Future { (async move || { - //~^ captured variable cannot escape `FnMut` closure body + //~^ ERROR lifetime may not live long enough + //~| ERROR temporary value dropped while borrowed let y = &*x; *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed y @@ -21,7 +22,8 @@ pub fn async_closure(x: &mut i32) -> impl Future { pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future { (async move || -> &i32 { - //~^ captured variable cannot escape `FnMut` closure body + //~^ ERROR lifetime may not live long enough + //~| ERROR temporary value dropped while borrowed let y = &*x; *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed y diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr index 9120d78164e88..bdf2820887c8b 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -11,7 +11,7 @@ LL | y | - returning this value requires that `*x` is borrowed for `'1` error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:17:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:18:9 | LL | let y = &*x; | --- `*x` is borrowed here @@ -22,61 +22,92 @@ LL | y LL | })() | - return type of async closure is &'1 i32 -error: captured variable cannot escape `FnMut` closure body +error: lifetime may not live long enough --> $DIR/issue-74072-lifetime-name-annotations.rs:14:20 | -LL | pub fn async_closure(x: &mut i32) -> impl Future { - | - variable defined here LL | (async move || { - | __________________-_^ - | | | - | | inferred to be a `FnMut` closure + | ______-------------_^ + | | | | + | | | return type of async closure `{async closure body@$DIR/issue-74072-lifetime-name-annotations.rs:14:20: 20:6}` contains a lifetime `'2` + | | lifetime `'1` represents this closure's body +LL | | LL | | LL | | let y = &*x; - | | - variable captured here LL | | *x += 1; LL | | y LL | | })() - | |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + | |_____^ returning this value requires that `'1` must outlive `'2` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure + +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:14:5 | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape +LL | pub fn async_closure(x: &mut i32) -> impl Future { + | - let's call the lifetime of this reference `'1` +LL | // (async move || { +LL | || +LL | || +LL | || let y = &*x; +LL | || *x += 1; +LL | || y +LL | || })() + | ||______^_- argument requires that borrow lasts for `'1` + | |_______| + | creates a temporary value which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:26:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:28:9 | -LL | (async move || -> &i32 { - | - let's call the lifetime of this reference `'1` -LL | LL | let y = &*x; | --- `*x` is borrowed here LL | *x += 1; | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` +LL | })() + | - return type of async closure is &'1 i32 -error: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-74072-lifetime-name-annotations.rs:23:28 +error: lifetime may not live long enough + --> $DIR/issue-74072-lifetime-name-annotations.rs:24:28 | -LL | pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future { - | - variable defined here LL | (async move || -> &i32 { - | __________________________-_^ - | | | - | | inferred to be a `FnMut` closure + | ______---------------------_^ + | | | | + | | | return type of async closure `{async closure body@$DIR/issue-74072-lifetime-name-annotations.rs:24:28: 30:6}` contains a lifetime `'2` + | | lifetime `'1` represents this closure's body +LL | | LL | | LL | | let y = &*x; - | | - variable captured here LL | | *x += 1; LL | | y LL | | })() - | |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + | |_____^ returning this value requires that `'1` must outlive `'2` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure + +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:24:5 | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape +LL | pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future { + | - let's call the lifetime of this reference `'1` +LL | // (async move || -> &i32 { +LL | || +LL | || +LL | || let y = &*x; +LL | || *x += 1; +LL | || y +LL | || })() + | ||______^_- argument requires that borrow lasts for `'1` + | |_______| + | creates a temporary value which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-74072-lifetime-name-annotations.rs:34:9 + --> $DIR/issue-74072-lifetime-name-annotations.rs:36:9 | LL | let y = &*x; | --- `*x` is borrowed here @@ -87,6 +118,7 @@ LL | y LL | } | - return type of async block is &'1 i32 -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0506`. +Some errors have detailed explanations: E0506, E0716. +For more information about an error, try `rustc --explain E0506`. diff --git a/tests/ui/closures/binder/async-closure-with-binder.rs b/tests/ui/closures/binder/async-closure-with-binder.rs index 4fa599d37cbd1..69d30f369e97d 100644 --- a/tests/ui/closures/binder/async-closure-with-binder.rs +++ b/tests/ui/closures/binder/async-closure-with-binder.rs @@ -1,8 +1,9 @@ // edition:2021 +// check-pass + #![feature(closure_lifetime_binder)] #![feature(async_closure)] + fn main() { - for<'a> async || (); - //~^ ERROR `for<...>` binders on `async` closures are not currently supported - //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + for<'a> async || -> () {}; } diff --git a/tests/ui/closures/binder/async-closure-with-binder.stderr b/tests/ui/closures/binder/async-closure-with-binder.stderr deleted file mode 100644 index 1d4628b1a494a..0000000000000 --- a/tests/ui/closures/binder/async-closure-with-binder.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: `for<...>` binders on `async` closures are not currently supported - --> $DIR/async-closure-with-binder.rs:5:5 - | -LL | for<'a> async || (); - | ^^^^^^^ - -error: implicit types in closure signatures are forbidden when `for<...>` is present - --> $DIR/async-closure-with-binder.rs:5:5 - | -LL | for<'a> async || (); - | -------^^^^^^^^^ - | | - | `for<...>` is here - -error: aborting due to 2 previous errors - diff --git a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 3065f83ea3d1b..dc4ec5d3ee28b 100644 --- a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -18,25 +18,21 @@ help: use parentheses to call this function LL | bar(foo()); | ++ -error[E0277]: `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future +error[E0277]: `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9 | LL | bar(async_closure); - | --- ^^^^^^^^^^^^^ `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future + | --- ^^^^^^^^^^^^^ `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future | | | required by a bound introduced by this call | - = help: the trait `Future` is not implemented for closure `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` - = note: {closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited + = help: the trait `Future` is not implemented for `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` + = note: {coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited note: required by a bound in `bar` --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16 | LL | fn bar(f: impl Future) {} | ^^^^^^^^^^^^^^^^^ required by this bound in `bar` -help: use parentheses to call this closure - | -LL | bar(async_closure()); - | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index 61d27ec69f4d2..c1cbefac828d6 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h9308686d0228fa1dE) +error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h9308686d0228fa1d) +error: demangling(basic::main::h6fc0c8d27b1a289f) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index eb65f3b58fff8..7dd68e6e3a8e2 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h84ab5dafbd2a1508E) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo::foo::h84ab5dafbd2a1508) +error: demangling(issue_60925::foo::Foo::foo::hab58a402db4ebf3a) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] From 37184e86ea58bc90b8cd97f877d52ccce8ea02ab Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 25 Jan 2024 17:43:35 +0000 Subject: [PATCH 067/101] Add some tests --- compiler/rustc_hir_typeck/src/upvar.rs | 5 ++-- .../src/traits/select/candidate_assembly.rs | 16 +++++++++--- .../async-closures/arg-mismatch.rs | 15 +++++++++++ .../async-closures/arg-mismatch.stderr | 21 +++++++++++++++ .../async-fn-once-for-async-fn.rs | 23 ++++++++++++++++ .../async-fn-once-for-async-fn.stderr | 2 ++ .../async-closures/auxiliary/block-on.rs | 20 ++++++++++++++ .../await-inference-guidance.rs | 16 ++++++++++++ tests/ui/async-await/async-closures/brand.rs | 26 +++++++++++++++++++ .../async-closures/higher-ranked-return.rs | 18 +++++++++++++ .../higher-ranked-return.stderr | 14 ++++++++++ .../async-closures/higher-ranked.rs | 14 +++++++--- .../async-await/async-closures/is-not-fn.rs | 12 +++++++++ .../async-closures/is-not-fn.stderr | 19 ++++++++++++++ .../async-closures/move-consuming-capture.rs | 20 ++++++++++++++ .../move-consuming-capture.stderr | 17 ++++++++++++ .../async-closures/move-is-async-fn.rs | 21 +++++++++++++++ tests/ui/async-await/async-closures/mutate.rs | 19 ++++++++++++++ .../async-await/async-closures/not-lending.rs | 21 +++++++++++++++ .../async-closures/not-lending.stderr | 24 +++++++++++++++++ .../async-closures/return-type-mismatch.rs | 14 ++++++++++ .../return-type-mismatch.stderr | 14 ++++++++++ .../async-closures/wrong-fn-kind.rs | 18 +++++++++++++ .../async-closures/wrong-fn-kind.stderr | 22 ++++++++++++++++ 24 files changed, 402 insertions(+), 9 deletions(-) create mode 100644 tests/ui/async-await/async-closures/arg-mismatch.rs create mode 100644 tests/ui/async-await/async-closures/arg-mismatch.stderr create mode 100644 tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs create mode 100644 tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr create mode 100644 tests/ui/async-await/async-closures/auxiliary/block-on.rs create mode 100644 tests/ui/async-await/async-closures/await-inference-guidance.rs create mode 100644 tests/ui/async-await/async-closures/brand.rs create mode 100644 tests/ui/async-await/async-closures/higher-ranked-return.rs create mode 100644 tests/ui/async-await/async-closures/higher-ranked-return.stderr create mode 100644 tests/ui/async-await/async-closures/is-not-fn.rs create mode 100644 tests/ui/async-await/async-closures/is-not-fn.stderr create mode 100644 tests/ui/async-await/async-closures/move-consuming-capture.rs create mode 100644 tests/ui/async-await/async-closures/move-consuming-capture.stderr create mode 100644 tests/ui/async-await/async-closures/move-is-async-fn.rs create mode 100644 tests/ui/async-await/async-closures/mutate.rs create mode 100644 tests/ui/async-await/async-closures/not-lending.rs create mode 100644 tests/ui/async-await/async-closures/not-lending.stderr create mode 100644 tests/ui/async-await/async-closures/return-type-mismatch.rs create mode 100644 tests/ui/async-await/async-closures/return-type-mismatch.stderr create mode 100644 tests/ui/async-await/async-closures/wrong-fn-kind.rs create mode 100644 tests/ui/async-await/async-closures/wrong-fn-kind.stderr diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index d4e072976fa69..e8bdf283c4f4d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -394,13 +394,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coroutine_captures_by_ref_ty, ); - let ty::Coroutine(_, args) = *self.typeck_results.borrow().expr_ty(body.value).kind() + let ty::Coroutine(_, coroutine_args) = + *self.typeck_results.borrow().expr_ty(body.value).kind() else { bug!(); }; self.demand_eqtype( span, - args.as_coroutine().kind_ty(), + coroutine_args.as_coroutine().kind_ty(), Ty::from_closure_kind(self.tcx, closure_kind), ); } 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 75aedd5cd22ca..dda68fd424430 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -371,9 +371,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - if let Some(closure_kind) = obligation.self_ty().skip_binder().to_opt_closure_kind() - && let Some(goal_kind) = - obligation.predicate.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind() + let self_ty = obligation.self_ty().skip_binder(); + let target_kind_ty = obligation.predicate.skip_binder().trait_ref.args.type_at(1); + + // `to_opt_closure_kind` is kind of ICEy when it sees non-int types. + if !(self_ty.is_integral() || self_ty.is_ty_var()) { + return; + } + if !(target_kind_ty.is_integral() || self_ty.is_ty_var()) { + return; + } + + if let Some(closure_kind) = self_ty.to_opt_closure_kind() + && let Some(goal_kind) = target_kind_ty.to_opt_closure_kind() { if closure_kind.extends(goal_kind) { candidates.vec.push(AsyncFnKindHelperCandidate); diff --git a/tests/ui/async-await/async-closures/arg-mismatch.rs b/tests/ui/async-await/async-closures/arg-mismatch.rs new file mode 100644 index 0000000000000..650e13677bc95 --- /dev/null +++ b/tests/ui/async-await/async-closures/arg-mismatch.rs @@ -0,0 +1,15 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let c = async |x| {}; + c(1i32).await; + c(2usize).await; + //~^ ERROR mismatched types + }); +} diff --git a/tests/ui/async-await/async-closures/arg-mismatch.stderr b/tests/ui/async-await/async-closures/arg-mismatch.stderr new file mode 100644 index 0000000000000..70853ae28156f --- /dev/null +++ b/tests/ui/async-await/async-closures/arg-mismatch.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/arg-mismatch.rs:12:11 + | +LL | c(2usize).await; + | - ^^^^^^ expected `i32`, found `usize` + | | + | arguments to this function are incorrect + | +note: closure parameter defined here + --> $DIR/arg-mismatch.rs:10:24 + | +LL | let c = async |x| {}; + | ^ +help: change the type of the numeric literal from `usize` to `i32` + | +LL | c(2i32).await; + | ~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs new file mode 100644 index 0000000000000..4afc43fe6bd92 --- /dev/null +++ b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs @@ -0,0 +1,23 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. +// ignore-pass (test emits codegen-time warnings) + +#![feature(async_closure, async_fn_traits)] + +extern crate block_on; + +use std::ops::AsyncFnOnce; + +fn main() { + block_on::block_on(async { + let x = async || {}; + + async fn needs_async_fn_once(x: impl AsyncFnOnce()) { + x().await; + } + needs_async_fn_once(x).await; + }); +} diff --git a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr new file mode 100644 index 0000000000000..9ae4692f003ef --- /dev/null +++ b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr @@ -0,0 +1,2 @@ +WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()])>, found std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()])>.See . +WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected *mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()]), found *mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()]).See . diff --git a/tests/ui/async-await/async-closures/auxiliary/block-on.rs b/tests/ui/async-await/async-closures/auxiliary/block-on.rs new file mode 100644 index 0000000000000..3c27548b865a7 --- /dev/null +++ b/tests/ui/async-await/async-closures/auxiliary/block-on.rs @@ -0,0 +1,20 @@ +// edition: 2021 + +#![feature(async_closure, noop_waker, async_fn_traits)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + // Poll loop, just to test the future... + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match unsafe { fut.as_mut().poll(ctx) } { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} diff --git a/tests/ui/async-await/async-closures/await-inference-guidance.rs b/tests/ui/async-await/async-closures/await-inference-guidance.rs new file mode 100644 index 0000000000000..3702915cbadd1 --- /dev/null +++ b/tests/ui/async-await/async-closures/await-inference-guidance.rs @@ -0,0 +1,16 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async |x: &str| -> String { x.to_owned() }; + let mut s = x("hello, world").await; + s.truncate(4); + println!("{s}"); + }); +} diff --git a/tests/ui/async-await/async-closures/brand.rs b/tests/ui/async-await/async-closures/brand.rs new file mode 100644 index 0000000000000..3bda7737bb406 --- /dev/null +++ b/tests/ui/async-await/async-closures/brand.rs @@ -0,0 +1,26 @@ +// aux-build:block-on.rs +// edition:2021 +// build-pass + +#![feature(async_closure, async_fn_traits)] + +extern crate block_on; + +use std::future::Future; +use std::marker::PhantomData; +use std::ops::AsyncFn; + +struct S; +struct B<'b>(PhantomData<&'b mut &'b mut ()>); + +impl S { + async fn q)>(self, f: F) { + f(B(PhantomData)).await; + } +} + +fn main() { + block_on::block_on(async { + S.q(async |b: B<'_>| { println!("...") }).await; + }); +} diff --git a/tests/ui/async-await/async-closures/higher-ranked-return.rs b/tests/ui/async-await/async-closures/higher-ranked-return.rs new file mode 100644 index 0000000000000..d98779c6ea320 --- /dev/null +++ b/tests/ui/async-await/async-closures/higher-ranked-return.rs @@ -0,0 +1,18 @@ +// aux-build:block-on.rs +// edition:2021 + +// known-bug: unknown +// Borrow checking doesn't like that higher-ranked output... + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async move |x: &str| -> &str { + x + }; + let s = x("hello!").await; + }); +} diff --git a/tests/ui/async-await/async-closures/higher-ranked-return.stderr b/tests/ui/async-await/async-closures/higher-ranked-return.stderr new file mode 100644 index 0000000000000..268631f67cddf --- /dev/null +++ b/tests/ui/async-await/async-closures/higher-ranked-return.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/higher-ranked-return.rs:13:46 + | +LL | let x = async move |x: &str| -> &str { + | ________________________________-________----_^ + | | | | + | | | return type of async closure `{async closure body@$DIR/higher-ranked-return.rs:13:46: 15:10}` contains a lifetime `'2` + | | let's call the lifetime of this reference `'1` +LL | | x +LL | | }; + | |_________^ returning this value requires that `'1` must outlive `'2` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/async-closures/higher-ranked.rs b/tests/ui/async-await/async-closures/higher-ranked.rs index 5bbcc7041a8f8..17b5116cceb02 100644 --- a/tests/ui/async-await/async-closures/higher-ranked.rs +++ b/tests/ui/async-await/async-closures/higher-ranked.rs @@ -1,10 +1,16 @@ +// aux-build:block-on.rs // edition:2021 -// check-pass +// build-pass #![feature(async_closure)] +extern crate block_on; + fn main() { - let x = async move |x: &str| { - println!("{x}"); - }; + block_on::block_on(async { + let x = async move |x: &str| { + println!("{x}"); + }; + x("hello!").await; + }); } diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs new file mode 100644 index 0000000000000..94c8e8563bd9e --- /dev/null +++ b/tests/ui/async-await/async-closures/is-not-fn.rs @@ -0,0 +1,12 @@ +// edition:2021 + +#![feature(async_closure)] + +fn main() { + fn needs_fn(x: impl FnOnce()) {} + needs_fn(async || {}); + //~^ ERROR expected a `FnOnce()` closure, found `{coroutine-closure@ + // FIXME(async_closures): This should explain in more detail how async fns don't + // implement the regular `Fn` traits. Or maybe we should just fix it and make them + // when there are no upvars or whatever. +} diff --git a/tests/ui/async-await/async-closures/is-not-fn.stderr b/tests/ui/async-await/async-closures/is-not-fn.stderr new file mode 100644 index 0000000000000..12da4b1fc6fb7 --- /dev/null +++ b/tests/ui/async-await/async-closures/is-not-fn.stderr @@ -0,0 +1,19 @@ +error[E0277]: expected a `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` + --> $DIR/is-not-fn.rs:7:14 + | +LL | needs_fn(async || {}); + | -------- ^^^^^^^^^^^ expected an `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<()>` is not implemented for `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` + = note: wrap the `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `needs_fn` + --> $DIR/is-not-fn.rs:6:25 + | +LL | fn needs_fn(x: impl FnOnce()) {} + | ^^^^^^^^ required by this bound in `needs_fn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-closures/move-consuming-capture.rs b/tests/ui/async-await/async-closures/move-consuming-capture.rs new file mode 100644 index 0000000000000..b8964c571f92e --- /dev/null +++ b/tests/ui/async-await/async-closures/move-consuming-capture.rs @@ -0,0 +1,20 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +struct NoCopy; + +fn main() { + block_on::block_on(async { + let s = NoCopy; + let x = async move || { + drop(s); + }; + x().await; + x().await; + //~^ ERROR use of moved value: `x` + }); +} diff --git a/tests/ui/async-await/async-closures/move-consuming-capture.stderr b/tests/ui/async-await/async-closures/move-consuming-capture.stderr new file mode 100644 index 0000000000000..2c2a0d1162d17 --- /dev/null +++ b/tests/ui/async-await/async-closures/move-consuming-capture.stderr @@ -0,0 +1,17 @@ +error[E0382]: use of moved value: `x` + --> $DIR/move-consuming-capture.rs:17:9 + | +LL | let x = async move || { + | - move occurs because `x` has type `{coroutine-closure@$DIR/move-consuming-capture.rs:13:17: 13:30}`, which does not implement the `Copy` trait +... +LL | x().await; + | --- `x` moved due to this method call +LL | x().await; + | ^ value used here after move + | +note: `async_call_once` takes ownership of the receiver `self`, which moves `x` + --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/async-await/async-closures/move-is-async-fn.rs b/tests/ui/async-await/async-closures/move-is-async-fn.rs new file mode 100644 index 0000000000000..943c062954185 --- /dev/null +++ b/tests/ui/async-await/async-closures/move-is-async-fn.rs @@ -0,0 +1,21 @@ +// aux-build:block-on.rs +// edition:2021 +// build-pass + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let s = String::from("hello, world"); + let c = async move || { + println!("{s}"); + }; + c().await; + c().await; + + fn is_static(_: T) {} + is_static(c); + }); +} diff --git a/tests/ui/async-await/async-closures/mutate.rs b/tests/ui/async-await/async-closures/mutate.rs new file mode 100644 index 0000000000000..cc1df5f034ff0 --- /dev/null +++ b/tests/ui/async-await/async-closures/mutate.rs @@ -0,0 +1,19 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let mut prefix = String::from("Hello"); + let mut c = async move |x: &str| { + prefix.push(','); + println!("{prefix} {x}!") + }; + c("world").await; + c("rust").await; + }); +} diff --git a/tests/ui/async-await/async-closures/not-lending.rs b/tests/ui/async-await/async-closures/not-lending.rs new file mode 100644 index 0000000000000..90832e1a0745d --- /dev/null +++ b/tests/ui/async-await/async-closures/not-lending.rs @@ -0,0 +1,21 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +// Make sure that we can't make an async closure that evaluates to a self-borrow. +// i.e. that the generator may reference captures, but the future's return type can't. + +fn main() { + block_on::block_on(async { + let s = String::new(); + let x = async move || -> &String { &s }; + //~^ ERROR lifetime may not live long enough + + let s = String::new(); + let x = async move || { &s }; + //~^ ERROR lifetime may not live long enough + }); +} diff --git a/tests/ui/async-await/async-closures/not-lending.stderr b/tests/ui/async-await/async-closures/not-lending.stderr new file mode 100644 index 0000000000000..1713e49b551e6 --- /dev/null +++ b/tests/ui/async-await/async-closures/not-lending.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/not-lending.rs:14:42 + | +LL | let x = async move || -> &String { &s }; + | ------------------------ ^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of async closure `{async closure body@$DIR/not-lending.rs:14:42: 14:48}` contains a lifetime `'2` + | lifetime `'1` represents this closure's body + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure + +error: lifetime may not live long enough + --> $DIR/not-lending.rs:18:31 + | +LL | let x = async move || { &s }; + | ------------- ^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of async closure `{async closure body@$DIR/not-lending.rs:18:31: 18:37}` contains a lifetime `'2` + | lifetime `'1` represents this closure's body + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/async-closures/return-type-mismatch.rs b/tests/ui/async-await/async-closures/return-type-mismatch.rs new file mode 100644 index 0000000000000..9ad6be0b6e61e --- /dev/null +++ b/tests/ui/async-await/async-closures/return-type-mismatch.rs @@ -0,0 +1,14 @@ +// aux-build:block-on.rs +// edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +fn main() { + block_on::block_on(async { + let x = async || -> i32 { 0 }; + let y: usize = x().await; + //~^ ERROR mismatched types + }); +} diff --git a/tests/ui/async-await/async-closures/return-type-mismatch.stderr b/tests/ui/async-await/async-closures/return-type-mismatch.stderr new file mode 100644 index 0000000000000..53841f62777e6 --- /dev/null +++ b/tests/ui/async-await/async-closures/return-type-mismatch.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/return-type-mismatch.rs:11:24 + | +LL | let y: usize = x().await; + | ^^^^^^^^^ expected `usize`, found `i32` + | +help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit + | +LL | let y: usize = x().await.try_into().unwrap(); + | ++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs new file mode 100644 index 0000000000000..248288325319e --- /dev/null +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -0,0 +1,18 @@ +// edition:2021 + +// FIXME(async_closures): This needs a better error message! + +#![feature(async_closure, async_fn_traits)] + +use std::ops::AsyncFn; + +fn main() { + fn needs_async_fn(_: impl AsyncFn()) {} + + let mut x = 1; + needs_async_fn(async || { + //~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper + // FIXME: Should say "closure is AsyncFnMut but it needs AsyncFn" or sth. + x += 1; + }); +} diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr new file mode 100644 index 0000000000000..ef95e6a211c74 --- /dev/null +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not satisfied + --> $DIR/wrong-fn-kind.rs:13:20 + | +LL | needs_async_fn(async || { + | _____--------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | // FIXME: Should say "closure is AsyncFnMut but it needs AsyncFn" or sth. +LL | | x += 1; +LL | | }); + | |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not implemented for `i16` + | +note: required by a bound in `needs_async_fn` + --> $DIR/wrong-fn-kind.rs:10:31 + | +LL | fn needs_async_fn(_: impl AsyncFn()) {} + | ^^^^^^^^^ required by this bound in `needs_async_fn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From c98d6994a390044410c55c45195d330e4c8cd3d7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 25 Jan 2024 19:17:21 +0000 Subject: [PATCH 068/101] More comments, final tweaks --- compiler/rustc_ast_lowering/src/expr.rs | 3 ++ .../src/type_check/input_output.rs | 8 +++- .../rustc_borrowck/src/universal_regions.rs | 8 ++++ compiler/rustc_hir_analysis/src/collect.rs | 11 +---- compiler/rustc_hir_typeck/src/callee.rs | 9 ++++ compiler/rustc_hir_typeck/src/closure.rs | 39 +++++++++++----- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_hir_typeck/src/upvar.rs | 10 ++++- compiler/rustc_middle/src/ty/flags.rs | 6 +-- compiler/rustc_middle/src/ty/instance.rs | 7 +++ compiler/rustc_middle/src/ty/sty.rs | 44 ++++++++++++++++--- .../rustc_mir_dataflow/src/value_analysis.rs | 3 ++ .../src/coroutine/by_move_body.rs | 13 +++++- .../src/solve/assembly/structural_traits.rs | 24 +++++++--- .../src/traits/project.rs | 3 ++ .../src/traits/select/candidate_assembly.rs | 4 ++ .../src/traits/select/confirmation.rs | 2 + .../rustc_trait_selection/src/traits/wf.rs | 2 +- compiler/rustc_ty_utils/src/abi.rs | 6 +++ compiler/rustc_ty_utils/src/instance.rs | 7 +++ 20 files changed, 169 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9990d526bf732..337dd55541ac6 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1074,6 +1074,9 @@ impl<'hir> LoweringContext<'_, 'hir> { body, fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), + // Lower this as a `CoroutineClosure`. That will ensure that HIR typeck + // knows that a `FnDecl` output type like `-> &str` actually means + // "coroutine that returns &str", rather than directly returning a `&str`. kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async), constness: hir::Constness::NotConst, }); diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 46fd0ce2b39a0..a5a7ce4ea3e86 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -61,6 +61,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { )), "this needs to be modified if we're lowering non-async closures" ); + // Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated + // into the type. let args = args.as_coroutine_closure(); let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( self.tcx(), @@ -87,11 +89,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ty::CoroutineArgsParts { parent_args: args.parent_args(), kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()), + return_ty: user_provided_sig.output(), + tupled_upvars_ty, + // For async closures, none of these can be annotated, so just fill + // them with fresh ty vars. resume_ty: next_ty_var(), yield_ty: next_ty_var(), witness: next_ty_var(), - return_ty: user_provided_sig.output(), - tupled_upvars_ty: tupled_upvars_ty, }, ) .args, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index d696e624823af..111eaaf60f7b2 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -720,6 +720,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ty::Binder::dummy(inputs_and_output) } + // Construct the signature of the CoroutineClosure for the purposes of borrowck. + // This is pretty straightforward -- we: + // 1. first grab the `coroutine_closure_sig`, + // 2. compute the self type (`&`/`&mut`/no borrow), + // 3. flatten the tupled_input_tys, + // 4. construct the correct generator type to return with + // `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`. + // Then we wrap it all up into a list of inputs and output. DefiningTy::CoroutineClosure(def_id, args) => { assert_eq!(self.mir_def.to_def_id(), def_id); let closure_sig = args.as_coroutine_closure().coroutine_closure_sig(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8fdd3cfe3cf88..fbcebb7c87c9b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1533,15 +1533,8 @@ fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> DefId { - let Node::Expr(&hir::Expr { - kind: - hir::ExprKind::Closure(&rustc_hir::Closure { - kind: hir::ClosureKind::CoroutineClosure(_), - body, - .. - }), - .. - }) = tcx.hir_node_by_def_id(def_id) + let &rustc_hir::Closure { kind: hir::ClosureKind::CoroutineClosure(_), body, .. } = + tcx.hir_node_by_def_id(def_id).expect_closure() else { bug!() }; diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 730a475f63049..fbe6f454dbc92 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -166,6 +166,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Some(CallStep::DeferredClosure(def_id, closure_sig)); } + // When calling a `CoroutineClosure` that is local to the body, we will + // not know what its `closure_kind` is yet. Instead, just fill in the + // signature with an infer var for the `tupled_upvars_ty` of the coroutine, + // and record a deferred call resolution which will constrain that var + // as part of `AsyncFn*` trait confirmation. ty::CoroutineClosure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => { let def_id = def_id.expect_local(); let closure_args = args.as_coroutine_closure(); @@ -183,6 +188,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coroutine_closure_sig.to_coroutine( self.tcx, closure_args.parent_args(), + // Inherit the kind ty of the closure, since we're calling this + // coroutine with the most relaxed `AsyncFn*` trait that we can. + // We don't necessarily need to do this here, but it saves us + // computing one more infer var that will get constrained later. closure_args.kind_ty(), self.tcx.coroutine_for_closure(def_id), tupled_upvars_ty, diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 014293c1f8325..a985fa201d071 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -175,6 +175,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { interior, )); + // Coroutines that come from coroutine closures have not yet determined + // their kind ty, so make a fresh infer var which will be constrained + // later during upvar analysis. Regular coroutines always have the kind + // ty of `().` let kind_ty = match kind { hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) => self .next_ty_var(TypeVariableOrigin { @@ -203,6 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } hir::ClosureKind::CoroutineClosure(kind) => { + // async closures always return the type ascribed after the `->` (if present), + // and yield `()`. let (bound_return_ty, bound_yield_ty) = match kind { hir::CoroutineDesugaring::Async => { (bound_sig.skip_binder().output(), tcx.types.unit) @@ -211,6 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { todo!("`gen` and `async gen` closures not supported yet") } }; + // Compute all of the variables that will be used to populate the coroutine. let resume_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, @@ -258,20 +265,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, }); + + // We need to turn the liberated signature that we got from HIR, which + // looks something like `|Args...| -> T`, into a signature that is suitable + // for type checking the inner body of the closure, which always returns a + // coroutine. To do so, we use the `CoroutineClosureSignature` to compute + // the coroutine type, filling in the tupled_upvars_ty and kind_ty with infer + // vars which will get constrained during upvar analysis. + let coroutine_output_ty = tcx.liberate_late_bound_regions( + expr_def_id.to_def_id(), + closure_args.coroutine_closure_sig().map_bound(|sig| { + sig.to_coroutine( + tcx, + parent_args, + closure_kind_ty, + tcx.coroutine_for_closure(expr_def_id), + coroutine_upvars_ty, + ) + }), + ); liberated_sig = tcx.mk_fn_sig( liberated_sig.inputs().iter().copied(), - tcx.liberate_late_bound_regions( - expr_def_id.to_def_id(), - closure_args.coroutine_closure_sig().map_bound(|sig| { - sig.to_coroutine( - tcx, - parent_args, - closure_kind_ty, - tcx.coroutine_for_closure(expr_def_id), - coroutine_upvars_ty, - ) - }), - ), + coroutine_output_ty, liberated_sig.c_variadic, liberated_sig.unsafety, liberated_sig.abi, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 23fb7eba65606..d30c7a4fb3899 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -335,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - // For this check, we do *not* want to treat async coroutine-closures (async blocks) + // For this check, we do *not* want to treat async coroutine closures (async blocks) // as proper closures. Doing so would regress type inference when feeding // the return value of an argument-position async block to an argument-position // closure wrapped in a block. diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index e8bdf283c4f4d..c4773a885218a 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -336,6 +336,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // For coroutine-closures, we additionally must compute the + // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref + // version of the coroutine-closure's output coroutine. if let UpvarArgs::CoroutineClosure(args) = args { let closure_env_region: ty::Region<'_> = ty::Region::new_bound( self.tcx, @@ -353,7 +356,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.coroutine_for_closure(closure_def_id).expect_local(), ) // Skip the captures that are just moving the closure's args - // into the coroutine. These are always by move. + // into the coroutine. These are always by move, and we append + // those later in the `CoroutineClosureSignature` helper functions. .skip( args.as_coroutine_closure() .coroutine_closure_sig() @@ -365,6 +369,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|captured_place| { let upvar_ty = captured_place.place.ty(); let capture = captured_place.info.capture_kind; + // Not all upvars are captured by ref, so use + // `apply_capture_kind_on_capture_ty` to ensure that we + // compute the right captured type. apply_capture_kind_on_capture_ty( self.tcx, upvar_ty, @@ -394,6 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coroutine_captures_by_ref_ty, ); + // Additionally, we can now constrain the coroutine's kind type. let ty::Coroutine(_, coroutine_args) = *self.typeck_results.borrow().expr_ty(body.value).kind() else { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index deb6e73ea7142..0f4b5fe228c96 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -145,11 +145,11 @@ impl FlagComputation { self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; } - self.add_ty(args.signature_parts_ty()); - self.add_ty(args.coroutine_witness_ty()); - self.add_ty(args.coroutine_captures_by_ref_ty()); self.add_ty(args.kind_ty()); + self.add_ty(args.signature_parts_ty()); self.add_ty(args.tupled_upvars_ty()); + self.add_ty(args.coroutine_captures_by_ref_ty()); + self.add_ty(args.coroutine_witness_ty()); } &ty::Bound(debruijn, _) => { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 2c80dd021451f..1c9415ef3b093 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -646,9 +646,16 @@ impl<'tcx> Instance<'tcx> { bug!() }; + // If the closure's kind ty disagrees with the identity closure's kind ty, + // then this must be a coroutine generated by one of the `ConstructCoroutineInClosureShim`s. if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() { Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) } else { + assert_eq!( + args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), + ty::ClosureKind::FnOnce, + "FIXME(async_closures): Generate a by-mut body here." + ); Some(Instance { def: ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id }, args, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3bbebaddbdd33..927924452f913 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -275,6 +275,10 @@ pub struct CoroutineClosureArgs<'tcx> { pub args: GenericArgsRef<'tcx>, } +/// See docs for explanation of how each argument is used. +/// +/// See [`CoroutineClosureSignature`] for how these arguments are put together +/// to make a callable [`FnSig`] suitable for typeck and borrowck. pub struct CoroutineClosureArgsParts<'tcx> { /// This is the args of the typeck root. pub parent_args: &'tcx [GenericArg<'tcx>], @@ -409,17 +413,32 @@ pub struct CoroutineClosureSignature<'tcx> { pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>, + + // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types + // never actually differ. But we save them rather than recreating them + // from scratch just for good measure. + /// Always false pub c_variadic: bool, + /// Always [`hir::Unsafety::Normal`] pub unsafety: hir::Unsafety, + /// Always [`abi::Abi::RustCall`] pub abi: abi::Abi, } impl<'tcx> CoroutineClosureSignature<'tcx> { + /// Construct a coroutine from the closure signature. Since a coroutine signature + /// is agnostic to the type of generator that is returned (by-ref/by-move), + /// the caller must specify what "flavor" of generator that they'd like to + /// create. Additionally, they must manually compute the upvars of the closure. + /// + /// This helper is not really meant to be used directly except for early on + /// during typeck, when we want to put inference vars into the kind and upvars tys. + /// When the kind and upvars are known, use the other helper functions. pub fn to_coroutine( self, tcx: TyCtxt<'tcx>, parent_args: &'tcx [GenericArg<'tcx>], - kind_ty: Ty<'tcx>, + coroutine_kind_ty: Ty<'tcx>, coroutine_def_id: DefId, tupled_upvars_ty: Ty<'tcx>, ) -> Ty<'tcx> { @@ -427,7 +446,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { tcx, ty::CoroutineArgsParts { parent_args, - kind_ty, + kind_ty: coroutine_kind_ty, resume_ty: self.resume_ty, yield_ty: self.yield_ty, return_ty: self.return_ty, @@ -439,19 +458,24 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) } + /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine + /// returned by that corresponding async fn trait. + /// + /// This function expects the upvars to have been computed already, and doesn't check + /// that the `ClosureKind` is actually supported by the coroutine-closure. pub fn to_coroutine_given_kind_and_upvars( self, tcx: TyCtxt<'tcx>, parent_args: &'tcx [GenericArg<'tcx>], coroutine_def_id: DefId, - closure_kind: ty::ClosureKind, + goal_kind: ty::ClosureKind, env_region: ty::Region<'tcx>, closure_tupled_upvars_ty: Ty<'tcx>, coroutine_captures_by_ref_ty: Ty<'tcx>, ) -> Ty<'tcx> { let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( tcx, - closure_kind, + goal_kind, self.tupled_inputs_ty, closure_tupled_upvars_ty, coroutine_captures_by_ref_ty, @@ -461,13 +485,21 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { self.to_coroutine( tcx, parent_args, - Ty::from_closure_kind(tcx, closure_kind), + Ty::from_closure_kind(tcx, goal_kind), coroutine_def_id, tupled_upvars_ty, ) } - /// Given a closure kind, compute the tupled upvars that the given coroutine would return. + /// Compute the tupled upvars that a coroutine-closure's output coroutine + /// would return for the given `ClosureKind`. + /// + /// When `ClosureKind` is `FnMut`/`Fn`, then this will use the "captures by ref" + /// to return a set of upvars which are borrowed with the given `env_region`. + /// + /// This ensures that the `AsyncFn::call` will return a coroutine whose upvars' + /// lifetimes are related to the lifetime of the borrow on the closure made for + /// the call. This allows borrowck to enforce the self-borrows correctly. pub fn tupled_upvars_by_closure_kind( tcx: TyCtxt<'tcx>, kind: ty::ClosureKind, diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index a85e53ff241d5..2b2af6ee7da3e 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1149,6 +1149,9 @@ pub fn iter_fields<'tcx>( ty::Closure(_, args) => { iter_fields(args.as_closure().tupled_upvars_ty(), tcx, param_env, f); } + ty::Coroutine(_, args) => { + iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, param_env, f); + } ty::CoroutineClosure(_, args) => { iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, param_env, f); } 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 4e3e70bdafef1..1cc0a5026d14d 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -1,3 +1,8 @@ +//! A MIR pass which duplicates a coroutine's body and removes any derefs which +//! would be present for upvars that are taken by-ref. The result of which will +//! be a coroutine body that takes all of its upvars by-move, and which we stash +//! into the `CoroutineInfo` for all coroutines returned by coroutine-closures. + use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_middle::mir::visit::MutVisitor; @@ -87,11 +92,16 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { && self.by_ref_fields.contains(&idx) { let (begin, end) = place.projection[1..].split_first().unwrap(); + // FIXME(async_closures): I'm actually a bit surprised to see that we always + // initially deref the by-ref upvars. If this is not actually true, then we + // will at least get an ICE that explains why this isn't true :^) assert_eq!(*begin, mir::ProjectionElem::Deref); + // Peel one ref off of the ty. + let peeled_ty = ty.builtin_deref(true).unwrap().ty; *place = mir::Place { local: place.local, projection: self.tcx.mk_place_elems_from_iter( - [mir::ProjectionElem::Field(idx, ty.builtin_deref(true).unwrap().ty)] + [mir::ProjectionElem::Field(idx, peeled_ty)] .into_iter() .chain(end.iter().copied()), ), @@ -101,6 +111,7 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { } fn visit_local_decl(&mut self, local: mir::Local, local_decl: &mut mir::LocalDecl<'tcx>) { + // Replace the type of the self arg. if local == ty::CAPTURE_STRUCT_LOCAL { local_decl.ty = self.by_move_coroutine_ty; } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index dbf3e4876a960..d02578c484649 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -309,14 +309,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } // Returns a binder of the tupled inputs types, output type, and coroutine type -// from a builtin async closure type. +// from a builtin coroutine-closure type. If we don't yet know the closure kind of +// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper` +// which enforces the closure is actually callable with the given trait. When we +// know the kind already, we can short-circuit this check. pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>( tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>, goal_kind: ty::ClosureKind, env_region: ty::Region<'tcx>, -) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec>), NoSolution> -{ +) -> Result< + (ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Option>), + NoSolution, +> { match *self_ty.kind() { ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); @@ -339,7 +344,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ); (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) }), - vec![], + None, )) } else { let async_fn_kind_trait_def_id = @@ -350,6 +355,13 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc .next() .unwrap() .def_id; + // When we don't know the closure kind (and therefore also the closure's upvars, + // which are computed at the same time), we must delay the computation of the + // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait + // goal functions similarly to the old `ClosureKind` predicate, and ensures that + // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars` + // will project to the right upvars for the generator, appending the inputs and + // coroutine upvars respecting the closure kind. Ok(( args.coroutine_closure_sig().map_bound(|sig| { let tupled_upvars_ty = Ty::new_projection( @@ -373,14 +385,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ); (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) }), - vec![ + Some( ty::TraitRef::new( tcx, async_fn_kind_trait_def_id, [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], ) .to_predicate(tcx), - ], + ), )) } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a8d6b9812be3a..955c81eee6be3 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2491,6 +2491,9 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( // since all this does is make the solver do more work. // // The code duplication due to the different length args is kind of weird, too. + // + // See the logic in `structural_traits` in the new solver to understand a bit + // more clearly how this *should* look. let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| { let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) { sym::CallOnceFuture => { 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 dda68fd424430..2258e7961038b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -121,9 +121,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates); } + // FIXME: Put these into `else if` blocks above, since they're built-in. self.assemble_closure_candidates(obligation, &mut candidates); self.assemble_async_closure_candidates(obligation, &mut candidates); self.assemble_fn_pointer_candidates(obligation, &mut candidates); + self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_from_object_ty(obligation, &mut candidates); } @@ -382,6 +384,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } + // Check that the self kind extends the goal kind. If it does, + // then there's nothing else to check. if let Some(closure_kind) = self_ty.to_opt_closure_kind() && let Some(goal_kind) = target_kind_ty.to_opt_closure_kind() { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 79336a9d4e8f0..c9d06b0f67521 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -88,6 +88,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) } + // No nested obligations or confirmation process. The checks that we do in + // candidate assembly are sufficient. AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]), CoroutineCandidate => { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 88584a61b13de..b4f13ee95a652 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -728,7 +728,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } ty::CoroutineClosure(did, args) => { - // See the above comments. + // See the above comments. The same apply to coroutine-closures. walker.skip_current_subtree(); self.compute(args.as_coroutine_closure().tupled_upvars_ty().into()); let obligations = self.nominal_obligations(did, args); diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 3ea48ee824d47..e023283a70957 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -112,6 +112,10 @@ fn fn_sig_for_fn_abi<'tcx>( }; let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + // When this `CoroutineClosure` comes from a `ConstructCoroutineInClosureShim`, + // make sure we respect the `target_kind` in that shim. + // FIXME(async_closures): This shouldn't be needed, and we should be populating + // a separate def-id for these bodies. let mut kind = args.as_coroutine_closure().kind(); if let InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } = instance.def { kind = target_kind; @@ -141,6 +145,8 @@ fn fn_sig_for_fn_abi<'tcx>( ) } ty::Coroutine(did, args) => { + // FIXME(async_closures): This isn't right for `CoroutineByMoveShim`. + let coroutine_kind = tcx.coroutine_kind(did).unwrap(); let sig = args.as_coroutine().sig(); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index fc224d242db6d..9faad10dd14df 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -287,6 +287,13 @@ fn resolve_associated_item<'tcx>( { match *rcvr_args.type_at(0).kind() { ty::CoroutineClosure(coroutine_closure_def_id, args) => { + // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure, + // or `AsyncFnOnce` for a by-mut closure, then construct a new body that + // has the right return types. + // + // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs + // to have its input and output types fixed (`&mut self` and returning + // `i16` coroutine kind). if target_kind > args.as_coroutine_closure().kind() { Some(Instance { def: ty::InstanceDef::ConstructCoroutineInClosureShim { From ca444160232a1bf1914da906da9e061a7636955c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 29 Jan 2024 17:41:51 +0000 Subject: [PATCH 069/101] Fix drop shim for AsyncFnOnce closure, AsyncFnMut shim for AsyncFn closure --- .../src/interpret/terminator.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 18 ++++- compiler/rustc_middle/src/mir/mono.rs | 2 +- compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 26 +++---- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/mod.rs | 21 ++++- .../src/coroutine/by_move_body.rs | 45 ++++++++++- compiler/rustc_mir_transform/src/inline.rs | 2 +- .../rustc_mir_transform/src/inline/cycle.rs | 2 +- .../rustc_mir_transform/src/pass_manager.rs | 11 ++- compiler/rustc_mir_transform/src/shim.rs | 77 +++++++++++++++---- compiler/rustc_monomorphize/src/collector.rs | 2 +- .../rustc_monomorphize/src/partitioning.rs | 4 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 2 +- compiler/rustc_symbol_mangling/src/legacy.rs | 33 +++++--- compiler/rustc_symbol_mangling/src/v0.rs | 7 ++ compiler/rustc_ty_utils/src/abi.rs | 2 +- ...ure#0}.coroutine_by_move.0.panic-abort.mir | 47 +++++++++++ ...re#0}.coroutine_by_move.0.panic-unwind.mir | 47 +++++++++++ ...sure#0}.coroutine_by_mut.0.panic-abort.mir | 47 +++++++++++ ...ure#0}.coroutine_by_mut.0.panic-unwind.mir | 47 +++++++++++ ...oroutine_closure_by_move.0.panic-abort.mir | 10 +++ ...routine_closure_by_move.0.panic-unwind.mir | 10 +++ ...coroutine_closure_by_mut.0.panic-abort.mir | 16 ++++ ...oroutine_closure_by_mut.0.panic-unwind.mir | 16 ++++ tests/mir-opt/async_closure_shims.rs | 46 +++++++++++ .../async-fn-mut-for-async-fn.rs | 23 ++++++ .../async-fn-mut-for-async-fn.stderr | 1 + .../async-fn-once-for-async-fn.stderr | 3 +- .../ui/async-await/async-closures/def-path.rs | 4 +- .../async-closures/def-path.stderr | 4 +- tests/ui/async-await/async-closures/drop.rs | 40 ++++++++++ .../async-closures/drop.run.stdout | 5 ++ tests/ui/async-await/async-closures/mangle.rs | 36 +++++++++ 35 files changed, 595 insertions(+), 67 deletions(-) create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir create mode 100644 tests/mir-opt/async_closure_shims.rs create mode 100644 tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs create mode 100644 tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr create mode 100644 tests/ui/async-await/async-closures/drop.rs create mode 100644 tests/ui/async-await/async-closures/drop.run.stdout create mode 100644 tests/ui/async-await/async-closures/mangle.rs diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index b8d6836da14a8..85a2e4778d252 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -546,7 +546,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineByMoveShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3d6c28088ad59..9475b89aa15c2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -265,7 +265,7 @@ pub struct CoroutineInfo<'tcx> { /// The body of the coroutine, modified to take its upvars by move rather than by ref. /// /// This is used by coroutine-closures, which must return a different flavor of coroutine - /// when called using `AsyncFnOnce::call_once`. It is produced by the `ByMoveBody` which + /// when called using `AsyncFnOnce::call_once`. It is produced by the `ByMoveBody` pass which /// is run right after building the initial MIR, and will only be populated for coroutines /// which come out of the async closure desugaring. /// @@ -274,6 +274,13 @@ pub struct CoroutineInfo<'tcx> { /// using `run_passes`. pub by_move_body: Option>, + /// The body of the coroutine, modified to take its upvars by mutable ref rather than by + /// immutable ref. + /// + /// FIXME(async_closures): This is literally the same body as the parent body. Find a better + /// way to represent the by-mut signature (or cap the closure-kind of the coroutine). + pub by_mut_body: Option>, + /// The layout of a coroutine. This field is populated after the state transform pass. pub coroutine_layout: Option>, @@ -294,6 +301,7 @@ impl<'tcx> CoroutineInfo<'tcx> { yield_ty: Some(yield_ty), resume_ty: Some(resume_ty), by_move_body: None, + by_mut_body: None, coroutine_drop: None, coroutine_layout: None, } @@ -604,6 +612,14 @@ impl<'tcx> Body<'tcx> { self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_drop.as_ref()) } + pub fn coroutine_by_move_body(&self) -> Option<&Body<'tcx>> { + self.coroutine.as_ref()?.by_move_body.as_ref() + } + + pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> { + self.coroutine.as_ref()?.by_mut_body.as_ref() + } + #[inline] pub fn coroutine_kind(&self) -> Option { self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index e6d1535fdf2f6..6937df7bb1897 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -403,7 +403,7 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::Virtual(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineByMoveShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index ce1859d6adae3..2c5ca82a4cd39 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -346,7 +346,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } | - ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id: _def_id } | + ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1c9415ef3b093..9c1f4b20d2c83 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -102,10 +102,12 @@ pub enum InstanceDef<'tcx> { }, /// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce` - /// is called on a coroutine-closure whose closure kind is not `FnOnce`. This - /// will select the body that is produced by the `ByMoveBody` transform, and thus + /// is called on a coroutine-closure whose closure kind greater than `FnOnce`, or + /// similarly for `AsyncFnMut`. + /// + /// This will select the body that is produced by the `ByMoveBody` transform, and thus /// take and use all of its upvars by-move rather than by-ref. - CoroutineByMoveShim { coroutine_def_id: DefId }, + CoroutineKindShim { coroutine_def_id: DefId, target_kind: ty::ClosureKind }, /// Compiler-generated accessor for thread locals which returns a reference to the thread local /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking @@ -192,7 +194,7 @@ impl<'tcx> InstanceDef<'tcx> { coroutine_closure_def_id: def_id, target_kind: _, } - | ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id: def_id } + | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, @@ -213,7 +215,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineByMoveShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => None, @@ -310,7 +312,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::DropGlue(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineByMoveShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::Item(_) | InstanceDef::Intrinsic(..) @@ -349,7 +351,7 @@ fn fmt_instance( InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), InstanceDef::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), - InstanceDef::CoroutineByMoveShim { .. } => write!(f, " - shim"), + InstanceDef::CoroutineKindShim { .. } => write!(f, " - shim"), InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"), @@ -651,13 +653,11 @@ impl<'tcx> Instance<'tcx> { if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() { Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) } else { - assert_eq!( - args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), - ty::ClosureKind::FnOnce, - "FIXME(async_closures): Generate a by-mut body here." - ); Some(Instance { - def: ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id }, + def: ty::InstanceDef::CoroutineKindShim { + coroutine_def_id, + target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), + }, args, }) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9ceb3ec3f615c..c9137f374a238 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1681,7 +1681,7 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineByMoveShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 7026d2af29853..19f8ba124f143 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -3,6 +3,7 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; +use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; @@ -130,8 +131,24 @@ pub trait Printer<'tcx>: Sized { parent_args = &args[..generics.parent_count.min(args.len())]; match key.disambiguated_data.data { - // Closures' own generics are only captures, don't print them. - DefPathData::Closure => {} + DefPathData::Closure => { + // FIXME(async_closures): This is somewhat ugly. + // We need to additionally print the `kind` field of a closure if + // it is desugared from a coroutine-closure. + if let Some(hir::CoroutineKind::Desugared( + _, + hir::CoroutineSource::Closure, + )) = self.tcx().coroutine_kind(def_id) + && args.len() >= parent_args.len() + 1 + { + return self.path_generic_args( + |cx| cx.print_def_path(def_id, parent_args), + &args[..parent_args.len() + 1][..1], + ); + } else { + // Closures' own generics are only captures, don't print them. + } + } // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`. // Anon consts doesn't have their own generics, and inline consts' own // generics are their inferred types, so don't print them. 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 1cc0a5026d14d..fcd4715b9e88c 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::{self, MirPass}; +use rustc_middle::mir::{self, dump_mir, MirPass}; use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; use rustc_target::abi::FieldIdx; @@ -24,7 +24,9 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { }; let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!() }; - if args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() == ty::ClosureKind::FnOnce { + + let coroutine_kind = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(); + if coroutine_kind == ty::ClosureKind::FnOnce { return; } @@ -58,14 +60,49 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { let mut by_move_body = body.clone(); MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body); + dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(())); by_move_body.source = mir::MirSource { - instance: InstanceDef::CoroutineByMoveShim { + instance: InstanceDef::CoroutineKindShim { coroutine_def_id: coroutine_def_id.to_def_id(), + target_kind: ty::ClosureKind::FnOnce, }, promoted: None, }; - body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); + + // If this is coming from an `AsyncFn` coroutine-closure, we must also create a by-mut body. + // This is actually just a copy of the by-ref body, but with a different self type. + // FIXME(async_closures): We could probably unify this with the by-ref body somehow. + if coroutine_kind == ty::ClosureKind::Fn { + let by_mut_coroutine_ty = Ty::new_coroutine( + tcx, + coroutine_def_id.to_def_id(), + ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args: args.as_coroutine().parent_args(), + kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnMut), + resume_ty: args.as_coroutine().resume_ty(), + yield_ty: args.as_coroutine().yield_ty(), + return_ty: args.as_coroutine().return_ty(), + witness: args.as_coroutine().witness(), + tupled_upvars_ty: args.as_coroutine().tupled_upvars_ty(), + }, + ) + .args, + ); + let mut by_mut_body = body.clone(); + by_mut_body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty = by_mut_coroutine_ty; + dump_mir(tcx, false, "coroutine_by_mut", &0, &by_mut_body, |_, _| Ok(())); + by_mut_body.source = mir::MirSource { + instance: InstanceDef::CoroutineKindShim { + coroutine_def_id: coroutine_def_id.to_def_id(), + target_kind: ty::ClosureKind::FnMut, + }, + promoted: None, + }; + body.coroutine.as_mut().unwrap().by_mut_body = Some(by_mut_body); + } } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 24bc84a235c2d..e77553a03d672 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -318,7 +318,7 @@ impl<'tcx> Inliner<'tcx> { | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineByMoveShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 77ff780393efb..5b03bc361dd3c 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -88,7 +88,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineByMoveShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::ThreadLocalShim { .. } | InstanceDef::CloneShim(..) => {} diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index c7e770904fbb8..605e1ad46d775 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -190,10 +190,13 @@ fn run_passes_inner<'tcx>( body.pass_count = 1; } - if let Some(coroutine) = body.coroutine.as_mut() - && let Some(by_move_body) = coroutine.by_move_body.as_mut() - { - run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each); + if let Some(coroutine) = body.coroutine.as_mut() { + if let Some(by_move_body) = coroutine.by_move_body.as_mut() { + run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each); + } + if let Some(by_mut_body) = coroutine.by_mut_body.as_mut() { + run_passes_inner(tcx, by_mut_body, passes, phase_change, validate_each); + } } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 668ccdd873550..7b6de3a543955 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -72,32 +72,70 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' } => match target_kind { ty::ClosureKind::Fn => unreachable!("shouldn't be building shim for Fn"), ty::ClosureKind::FnMut => { - let body = build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id); - // No need to optimize the body, it has already been optimized. - return body; + // No need to optimize the body, it has already been optimized + // since we steal it from the `AsyncFn::call` body and just fix + // the return type. + return build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id); } ty::ClosureKind::FnOnce => { build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id) } }, - ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id } => { - return tcx - .optimized_mir(coroutine_def_id) - .coroutine - .as_ref() - .unwrap() - .by_move_body - .as_ref() - .unwrap() - .clone(); - } + ty::InstanceDef::CoroutineKindShim { coroutine_def_id, target_kind } => match target_kind { + ty::ClosureKind::Fn => unreachable!(), + ty::ClosureKind::FnMut => { + return tcx + .optimized_mir(coroutine_def_id) + .coroutine_by_mut_body() + .unwrap() + .clone(); + } + ty::ClosureKind::FnOnce => { + return tcx + .optimized_mir(coroutine_def_id) + .coroutine_by_move_body() + .unwrap() + .clone(); + } + }, ty::InstanceDef::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? if let Some(ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) { - let body = tcx.optimized_mir(*coroutine_def_id).coroutine_drop().unwrap(); + let coroutine_body = tcx.optimized_mir(*coroutine_def_id); + + let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind() + else { + bug!() + }; + + // If this is a regular coroutine, grab its drop shim. If this is a coroutine + // that comes from a coroutine-closure, and the kind ty differs from the "maximum" + // kind that it supports, then grab the appropriate drop shim. This ensures that + // the future returned by `<[coroutine-closure] as AsyncFnOnce>::call_once` will + // drop the coroutine-closure's upvars. + let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() { + coroutine_body.coroutine_drop().unwrap() + } else { + match args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() { + ty::ClosureKind::Fn => { + unreachable!() + } + ty::ClosureKind::FnMut => coroutine_body + .coroutine_by_mut_body() + .unwrap() + .coroutine_drop() + .unwrap(), + ty::ClosureKind::FnOnce => coroutine_body + .coroutine_by_move_body() + .unwrap() + .coroutine_drop() + .unwrap(), + } + }; + let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args); debug!("make_shim({:?}) = {:?}", instance, body); @@ -1076,7 +1114,11 @@ fn build_construct_coroutine_by_move_shim<'tcx>( target_kind: ty::ClosureKind::FnOnce, }); - new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) + let body = + new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span); + dump_mir(tcx, false, "coroutine_closure_by_move", &0, &body, |_, _| Ok(())); + + body } fn build_construct_coroutine_by_mut_shim<'tcx>( @@ -1110,5 +1152,8 @@ fn build_construct_coroutine_by_mut_shim<'tcx>( target_kind: ty::ClosureKind::FnMut, }); + body.pass_count = 0; + dump_mir(tcx, false, "coroutine_closure_by_mut", &0, &body, |_, _| Ok(())); + body } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index cf3c8e1fdd3b4..3376af986531e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -984,7 +984,7 @@ fn visit_instance_use<'tcx>( | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineByMoveShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 22b35c4344b86..4f6ea66df7be1 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -621,7 +621,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineByMoveShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::Virtual(..) @@ -786,7 +786,7 @@ fn mono_item_visibility<'tcx>( | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineByMoveShim { .. } + | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 066348dcb67bc..959a17d24b7ce 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -800,7 +800,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { | ty::InstanceDef::FnPtrAddrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineByMoveShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 5af9503087ab9..646649293fc76 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -64,16 +64,29 @@ pub(super) fn mangle<'tcx>( ) .unwrap(); - if let ty::InstanceDef::ThreadLocalShim(..) = instance.def { - let _ = printer.write_str("{{tls-shim}}"); - } - - if let ty::InstanceDef::VTableShim(..) = instance.def { - let _ = printer.write_str("{{vtable-shim}}"); - } - - if let ty::InstanceDef::ReifyShim(..) = instance.def { - let _ = printer.write_str("{{reify-shim}}"); + match instance.def { + ty::InstanceDef::ThreadLocalShim(..) => { + printer.write_str("{{tls-shim}}").unwrap(); + } + ty::InstanceDef::VTableShim(..) => { + printer.write_str("{{vtable-shim}}").unwrap(); + } + ty::InstanceDef::ReifyShim(..) => { + printer.write_str("{{reify-shim}}").unwrap(); + } + // FIXME(async_closures): This shouldn't be needed when we fix + // `Instance::ty`/`Instance::def_id`. + ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } + | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { + ty::ClosureKind::Fn => unreachable!(), + ty::ClosureKind::FnMut => { + printer.write_str("{{fn-mut-shim}}").unwrap(); + } + ty::ClosureKind::FnOnce => { + printer.write_str("{{fn-once-shim}}").unwrap(); + } + }, + _ => {} } printer.path.finish(hash) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index d380cb9a19b78..530221555c52e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -46,6 +46,13 @@ pub(super) fn mangle<'tcx>( ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), + ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } + | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { + ty::ClosureKind::Fn => unreachable!(), + ty::ClosureKind::FnMut => Some("fn_mut"), + ty::ClosureKind::FnOnce => Some("fn_once"), + }, + _ => None, }; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index e023283a70957..7b95b4d03a6f3 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -145,7 +145,7 @@ fn fn_sig_for_fn_abi<'tcx>( ) } ty::Coroutine(did, args) => { - // FIXME(async_closures): This isn't right for `CoroutineByMoveShim`. + // FIXME(async_closures): This isn't right for `CoroutineKindShim`. let coroutine_kind = tcx.coroutine_kind(did).unwrap(); let sig = args.as_coroutine().sig(); diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir new file mode 100644 index 0000000000000..1fae40c5f4004 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (_1.1: i32); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(_1.1: i32); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir new file mode 100644 index 0000000000000..1fae40c5f4004 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (_1.1: i32); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(_1.1: i32); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir new file mode 100644 index 0000000000000..9886d6f68a41c --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (*(_1.1: &i32)); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(*(_1.1: &i32)); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir new file mode 100644 index 0000000000000..9886d6f68a41c --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut + +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (*(_1.1: &i32)); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(*(_1.1: &i32)); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir new file mode 100644 index 0000000000000..7df4eb492605b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir @@ -0,0 +1,10 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move + +fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + + bb0: { + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir new file mode 100644 index 0000000000000..7df4eb492605b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir @@ -0,0 +1,10 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move + +fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + + bb0: { + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir new file mode 100644 index 0000000000000..517b8d0dd883b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir @@ -0,0 +1,16 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut + +fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + debug a => _2; + debug b => ((*_1).0: i32); + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + let mut _3: &i32; + + bb0: { + StorageLive(_3); + _3 = &((*_1).0: i32); + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 }; + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir new file mode 100644 index 0000000000000..517b8d0dd883b --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir @@ -0,0 +1,16 @@ +// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut + +fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { + debug a => _2; + debug b => ((*_1).0: i32); + let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; + let mut _3: &i32; + + bb0: { + StorageLive(_3); + _3 = &((*_1).0: i32); + _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 }; + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs new file mode 100644 index 0000000000000..ef3bdaaa145a3 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.rs @@ -0,0 +1,46 @@ +// edition:2021 +// skip-filecheck +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(async_closure, noop_waker, async_fn_traits)] + +use std::future::Future; +use std::ops::{AsyncFnMut, AsyncFnOnce}; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} + +async fn call_mut(f: &mut impl AsyncFnMut(i32)) { + f(0).await; +} + +async fn call_once(f: impl AsyncFnOnce(i32)) { + f(1).await; +} + +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir +fn main() { + block_on(async { + let b = 2i32; + let mut async_closure = async move |a: i32| { + let a = &a; + let b = &b; + }; + call_mut(&mut async_closure).await; + call_once(async_closure).await; + }); +} diff --git a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs new file mode 100644 index 0000000000000..8d7dc6a276b90 --- /dev/null +++ b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs @@ -0,0 +1,23 @@ +// aux-build:block-on.rs +// edition:2021 +// run-pass + +// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. +// ignore-pass (test emits codegen-time warnings) + +#![feature(async_closure, async_fn_traits)] + +extern crate block_on; + +use std::ops::AsyncFnMut; + +fn main() { + block_on::block_on(async { + let x = async || {}; + + async fn needs_async_fn_mut(mut x: impl AsyncFnMut()) { + x().await; + } + needs_async_fn_mut(x).await; + }); +} diff --git a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr new file mode 100644 index 0000000000000..48917e8b23fde --- /dev/null +++ b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr @@ -0,0 +1 @@ +WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), [i16, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>, found std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>.See . diff --git a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr index 9ae4692f003ef..978a5a653f97d 100644 --- a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr +++ b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr @@ -1,2 +1 @@ -WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()])>, found std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()])>.See . -WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected *mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()]), found *mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()]).See . +WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>, found std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>.See . diff --git a/tests/ui/async-await/async-closures/def-path.rs b/tests/ui/async-await/async-closures/def-path.rs index 2883a1715b0ac..87e99ddda64b3 100644 --- a/tests/ui/async-await/async-closures/def-path.rs +++ b/tests/ui/async-await/async-closures/def-path.rs @@ -8,7 +8,7 @@ fn main() { //~^ NOTE the expected `async` closure body let () = x(); //~^ ERROR mismatched types - //~| NOTE this expression has type `{static main::{closure#0}::{closure#0} upvar_tys= + //~| NOTE this expression has type `{static main::{closure#0}::{closure#0}< //~| NOTE expected `async` closure body, found `()` - //~| NOTE expected `async` closure body `{static main::{closure#0}::{closure#0} + //~| NOTE expected `async` closure body `{static main::{closure#0}::{closure#0}< } diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index 4b37e50aac459..dae45825f370d 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?7t witness=?8t}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?15t witness=?6t}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?7t witness=?8t}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?15t witness=?6t}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/async-closures/drop.rs b/tests/ui/async-await/async-closures/drop.rs new file mode 100644 index 0000000000000..1b7f2f8a600d0 --- /dev/null +++ b/tests/ui/async-await/async-closures/drop.rs @@ -0,0 +1,40 @@ +// aux-build:block-on.rs +// edition:2018 +// run-pass +// check-run-results + +#![feature(async_closure, async_fn_traits)] +#![allow(unused)] + +extern crate block_on; + +use std::ops::AsyncFnOnce; + +struct DropMe(i32); + +impl Drop for DropMe { + fn drop(&mut self) { + println!("{} was dropped", self.0); + } +} + +async fn call_once(f: impl AsyncFnOnce()) { + println!("before call"); + let fut = Box::pin(f()); + println!("after call"); + drop(fut); + println!("future dropped"); +} + +fn main() { + block_on::block_on(async { + let d = DropMe(42); + let async_closure = async move || { + let d = &d; + println!("called"); + }; + + call_once(async_closure).await; + println!("after"); + }); +} diff --git a/tests/ui/async-await/async-closures/drop.run.stdout b/tests/ui/async-await/async-closures/drop.run.stdout new file mode 100644 index 0000000000000..ab233f491ba65 --- /dev/null +++ b/tests/ui/async-await/async-closures/drop.run.stdout @@ -0,0 +1,5 @@ +before call +after call +42 was dropped +future dropped +after diff --git a/tests/ui/async-await/async-closures/mangle.rs b/tests/ui/async-await/async-closures/mangle.rs new file mode 100644 index 0000000000000..98065c3c71109 --- /dev/null +++ b/tests/ui/async-await/async-closures/mangle.rs @@ -0,0 +1,36 @@ +// aux-build:block-on.rs +// edition:2021 +// build-pass +// revisions: v0 legacy +//[v0] compile-flags: -Csymbol-mangling-version=v0 +//[legacy] compile-flags: -Csymbol-mangling-version=legacy -Zunstable-options + +// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. +// ignore-pass (test emits codegen-time warnings) + +#![feature(async_closure, noop_waker, async_fn_traits)] + +extern crate block_on; + +use std::future::Future; +use std::ops::{AsyncFnMut, AsyncFnOnce}; +use std::pin::pin; +use std::task::*; + +async fn call_mut(f: &mut impl AsyncFnMut()) { + f().await; +} + +async fn call_once(f: impl AsyncFnOnce()) { + f().await; +} + +fn main() { + block_on::block_on(async { + let mut async_closure = async move || { + println!("called"); + }; + call_mut(&mut async_closure).await; + call_once(async_closure).await; + }); +} From 827bfe4154a9679a173755bb2098b863ef890f70 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 2 Feb 2024 09:25:16 +0000 Subject: [PATCH 070/101] Document `async_fn_traits` --- .../src/library-features/async-fn-traits.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/doc/unstable-book/src/library-features/async-fn-traits.md diff --git a/src/doc/unstable-book/src/library-features/async-fn-traits.md b/src/doc/unstable-book/src/library-features/async-fn-traits.md new file mode 100644 index 0000000000000..e1c3f067e5b2b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/async-fn-traits.md @@ -0,0 +1,13 @@ +# `async_fn_traits` + +See Also: [`fn_traits`](../library-features/fn-traits.md) + +---- + +The `async_fn_traits` feature allows for implementation of the [`AsyncFn*`] traits +for creating custom closure-like types that return futures. + +[`AsyncFn*`]: ../../std/ops/trait.AsyncFn.html + +The main difference to the `Fn*` family of traits is that `AsyncFn` can return a future +that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFn::CallFuture` does). From ed7fca1f8805b4348b801f23f444e0dda42f7aed Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Feb 2024 02:53:06 +0000 Subject: [PATCH 071/101] Fudge coroutine argument for CoroutineKindShim in fn_sig_for_fn_abi --- compiler/rustc_ty_utils/src/abi.rs | 36 +++++++++++++++++-- .../async-fn-mut-for-async-fn.stderr | 1 - .../async-fn-once-for-async-fn.stderr | 1 - 3 files changed, 34 insertions(+), 4 deletions(-) delete mode 100644 tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr delete mode 100644 tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 7b95b4d03a6f3..0542ef4ecf902 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -145,8 +145,6 @@ fn fn_sig_for_fn_abi<'tcx>( ) } ty::Coroutine(did, args) => { - // FIXME(async_closures): This isn't right for `CoroutineKindShim`. - let coroutine_kind = tcx.coroutine_kind(did).unwrap(); let sig = args.as_coroutine().sig(); @@ -157,6 +155,40 @@ fn fn_sig_for_fn_abi<'tcx>( var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, }; + + let mut ty = ty; + // When this `Closure` comes from a `CoroutineKindShim`, + // make sure we respect the `target_kind` in that shim. + // FIXME(async_closures): This shouldn't be needed, and we should be populating + // a separate def-id for these bodies. + if let InstanceDef::CoroutineKindShim { target_kind, .. } = instance.def { + // Grab the parent coroutine-closure. It has the same args for the purposes + // of substitution, so this will be okay to do. + let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx + .instantiate_and_normalize_erasing_regions( + args, + param_env, + tcx.type_of(tcx.parent(did)), + ) + .kind() + else { + bug!("CoroutineKindShim comes from calling a coroutine-closure"); + }; + let coroutine_closure_args = coroutine_closure_args.as_coroutine_closure(); + ty = tcx.instantiate_bound_regions_with_erased( + coroutine_closure_args.coroutine_closure_sig().map_bound(|sig| { + sig.to_coroutine_given_kind_and_upvars( + tcx, + coroutine_closure_args.parent_args(), + did, + target_kind, + tcx.lifetimes.re_erased, + coroutine_closure_args.tupled_upvars_ty(), + coroutine_closure_args.coroutine_captures_by_ref_ty(), + ) + }), + ); + } let env_ty = Ty::new_mut_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); diff --git a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr deleted file mode 100644 index 48917e8b23fde..0000000000000 --- a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.stderr +++ /dev/null @@ -1 +0,0 @@ -WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), [i16, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>, found std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_mut_for_async_fn[3241]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>.See . diff --git a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr deleted file mode 100644 index 978a5a653f97d..0000000000000 --- a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.stderr +++ /dev/null @@ -1 +0,0 @@ -WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>, found std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#0}::{closure#0}), []), ()])>.See . From 0b6af718d85a2639854ad09730f5f39aa5f70f9a Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Mon, 5 Feb 2024 18:53:28 -0800 Subject: [PATCH 072/101] Create helper `maybe_report_similar_assoc_fn` --- .../rustc_hir_analysis/src/astconv/errors.rs | 51 ++++++++++++++++++ .../rustc_hir_analysis/src/astconv/mod.rs | 52 +------------------ tests/ui/suggestions/issue-109195.rs | 10 ++-- tests/ui/suggestions/issue-109195.stderr | 18 +++---- 4 files changed, 66 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 407517b15ef5e..869e218400639 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -14,6 +14,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; +use rustc_middle::query::Key; use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; @@ -859,6 +860,56 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.set_tainted_by_errors(err.emit()); } + + /// On ambiguous associated type, look for an associated function whose name matches the + /// extended path and, if found, emit an E0223 error with a structured suggestion. + /// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195) + pub(crate) fn maybe_report_similar_assoc_fn( + &self, + span: Span, + qself_ty: Ty<'tcx>, + qself: &hir::Ty<'_>, + ) -> Result<(), ErrorGuaranteed> { + let tcx = self.tcx(); + if let Some((_, node)) = tcx.hir().parent_iter(qself.hir_id).skip(1).next() + && let hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::Path(hir::QPath::TypeRelative( + hir::Ty { + kind: + hir::TyKind::Path(hir::QPath::TypeRelative( + _, + hir::PathSegment { ident: ident2, .. }, + )), + .. + }, + hir::PathSegment { ident: ident3, .. }, + )), + .. + }) = node + && let Some(ty_def_id) = qself_ty.ty_def_id() + && let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id) + && let name = format!("{ident2}_{ident3}") + && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx + .associated_items(inherent_impl) + .filter_by_name_unhygienic(Symbol::intern(&name)) + .next() + { + let reported = + struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type") + .with_span_suggestion_verbose( + ident2.span.to(ident3.span), + format!("there is an associated function with a similar name: `{name}`"), + name, + Applicability::MaybeIncorrect, + ) + .emit(); + self.set_tainted_by_errors(reported); + Err(reported) + } else { + Ok(()) + } + } } /// Emits an error regarding forbidden type binding associations diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index d69f366a66c95..cfd38fb48f472 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -29,7 +29,6 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; -use rustc_middle::query::Key; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty, TyCtxt, TypeVisitableExt, @@ -1374,56 +1373,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .emit() // Already reported in an earlier stage. } else { - // suggest methods that look similar to the path - // e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195) - for (_, node) in tcx.hir().parent_iter(qself.hir_id) { - if let hir::Node::Expr(hir::Expr { - kind: - hir::ExprKind::Path(hir::QPath::TypeRelative( - hir::Ty { - kind: - hir::TyKind::Path(hir::QPath::TypeRelative( - _, - hir::PathSegment { ident: ident2, .. }, - )), - .. - }, - hir::PathSegment { ident: ident3, .. }, - )), - .. - }) = node - { - let name = format!("{ident2}_{ident3}"); - if if let Some(ty_def_id) = qself_ty.ty_def_id() - && let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id) - && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx - .associated_items(inherent_impl) - .filter_by_name_unhygienic(Symbol::intern(&name)) - .next() - { - true - } else { - qself_ty.is_str() - && ["from_utf8", "from_utf8_mut"].contains(&name.as_str()) - } { - let reported = struct_span_code_err!( - tcx.dcx(), - span, - E0223, - "ambiguous associated type" - ) - .with_span_suggestion_verbose( - ident2.span.to(ident3.span), - format!("you might have meant to use `{name}`"), - name, - Applicability::MaybeIncorrect, - ) - .emit(); - self.set_tainted_by_errors(reported); - return Err(reported); - } - } - } + self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?; let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); diff --git a/tests/ui/suggestions/issue-109195.rs b/tests/ui/suggestions/issue-109195.rs index badb859dbb701..cc499b0d77618 100644 --- a/tests/ui/suggestions/issue-109195.rs +++ b/tests/ui/suggestions/issue-109195.rs @@ -1,20 +1,20 @@ fn main() { String::from::utf8; //~^ ERROR ambiguous associated type [E0223] - //~| HELP you might have meant to use `from_utf8` + //~| HELP there is an associated function with a similar name: `from_utf8` String::from::utf8(); //~^ ERROR ambiguous associated type [E0223] - //~| HELP you might have meant to use `from_utf8` + //~| HELP there is an associated function with a similar name: `from_utf8` String::from::utf16(); //~^ ERROR ambiguous associated type [E0223] - //~| HELP you might have meant to use `from_utf16` + //~| HELP there is an associated function with a similar name: `from_utf16` String::from::method_that_doesnt_exist(); //~^ ERROR ambiguous associated type [E0223] //~| HELP if there were a trait named `Example` with associated type `from` str::from::utf8(); //~^ ERROR ambiguous associated type [E0223] - //~| HELP you might have meant to use `from_utf8` + //~| HELP if there were a trait named `Example` with associated type `from` str::from::utf8_mut(); //~^ ERROR ambiguous associated type [E0223] - //~| HELP you might have meant to use `from_utf8_mut` + //~| HELP if there were a trait named `Example` with associated type `from` } diff --git a/tests/ui/suggestions/issue-109195.stderr b/tests/ui/suggestions/issue-109195.stderr index 5c9ef9f98f513..10cf9cfd28ca7 100644 --- a/tests/ui/suggestions/issue-109195.stderr +++ b/tests/ui/suggestions/issue-109195.stderr @@ -4,7 +4,7 @@ error[E0223]: ambiguous associated type LL | String::from::utf8; | ^^^^^^^^^^^^ | -help: you might have meant to use `from_utf8` +help: there is an associated function with a similar name: `from_utf8` | LL | String::from_utf8; | ~~~~~~~~~ @@ -15,7 +15,7 @@ error[E0223]: ambiguous associated type LL | String::from::utf8(); | ^^^^^^^^^^^^ | -help: you might have meant to use `from_utf8` +help: there is an associated function with a similar name: `from_utf8` | LL | String::from_utf8(); | ~~~~~~~~~ @@ -26,7 +26,7 @@ error[E0223]: ambiguous associated type LL | String::from::utf16(); | ^^^^^^^^^^^^ | -help: you might have meant to use `from_utf16` +help: there is an associated function with a similar name: `from_utf16` | LL | String::from_utf16(); | ~~~~~~~~~~ @@ -48,10 +48,10 @@ error[E0223]: ambiguous associated type LL | str::from::utf8(); | ^^^^^^^^^ | -help: you might have meant to use `from_utf8` +help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path | -LL | str::from_utf8(); - | ~~~~~~~~~ +LL | ::from::utf8(); + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/issue-109195.rs:17:5 @@ -59,10 +59,10 @@ error[E0223]: ambiguous associated type LL | str::from::utf8_mut(); | ^^^^^^^^^ | -help: you might have meant to use `from_utf8_mut` +help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path | -LL | str::from_utf8_mut(); - | ~~~~~~~~~~~~~ +LL | ::from::utf8_mut(); + | ~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 6 previous errors From a939bad513e6201d7be76c13080fc0cc901bd658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Jan 2024 20:34:29 +0000 Subject: [PATCH 073/101] Suggest turnging `if let` into irrefutable `let` if appropriate When encountering an `if let` tail expression without an `else` arm for an enum with a single variant, suggest writing an irrefutable `let` binding instead. ``` error[E0317]: `if` may be missing an `else` clause --> $DIR/irrefutable-if-let-without-else.rs:8:5 | LL | fn foo(x: Enum) -> i32 { | --- expected `i32` because of this return type LL | / if let Enum::Variant(value) = x { LL | | value LL | | } | |_____^ expected `i32`, found `()` | = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type help: consider using an irrefutable `let` binding instead | LL ~ let Enum::Variant(value) = x; LL ~ value | ``` Fix #61788. --- compiler/rustc_hir_typeck/src/_match.rs | 116 +++++++++++++++--- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../irrefutable-if-let-without-else.fixed | 25 ++++ .../irrefutable-if-let-without-else.rs | 28 +++++ .../irrefutable-if-let-without-else.stderr | 61 +++++++++ 5 files changed, 214 insertions(+), 18 deletions(-) create mode 100644 tests/ui/binding/irrefutable-if-let-without-else.fixed create mode 100644 tests/ui/binding/irrefutable-if-let-without-else.rs create mode 100644 tests/ui/binding/irrefutable-if-let-without-else.stderr diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index cf1f232229d51..7ea0469deddee 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -1,7 +1,11 @@ use crate::coercion::{AsCoercionSite, CoerceMany}; use crate::{Diverges, Expectation, FnCtxt, Needs}; -use rustc_errors::Diagnostic; -use rustc_hir::{self as hir, ExprKind}; +use rustc_errors::{Applicability, Diagnostic}; +use rustc_hir::{ + self as hir, + def::{CtorOf, DefKind, Res}, + ExprKind, PatKind, +}; use rustc_hir_pretty::ty_to_string; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::Obligation; @@ -273,7 +277,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Returns `true` if there was an error forcing the coercion to the `()` type. pub(super) fn if_fallback_coercion( &self, - span: Span, + if_span: Span, + cond_expr: &'tcx hir::Expr<'tcx>, then_expr: &'tcx hir::Expr<'tcx>, coercion: &mut CoerceMany<'tcx, '_, T>, ) -> bool @@ -283,29 +288,106 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If this `if` expr is the parent's function return expr, // the cause of the type coercion is the return type, point at it. (#25228) let hir_id = self.tcx.hir().parent_id(self.tcx.hir().parent_id(then_expr.hir_id)); - let ret_reason = self.maybe_get_coercion_reason(hir_id, span); - let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse); + let ret_reason = self.maybe_get_coercion_reason(hir_id, if_span); + let cause = self.cause(if_span, ObligationCauseCode::IfExpressionWithNoElse); let mut error = false; coercion.coerce_forced_unit( self, &cause, - |err| { - if let Some((span, msg)) = &ret_reason { - err.span_label(*span, msg.clone()); - } else if let ExprKind::Block(block, _) = &then_expr.kind - && let Some(expr) = &block.expr - { - err.span_label(expr.span, "found here"); - } - err.note("`if` expressions without `else` evaluate to `()`"); - err.help("consider adding an `else` block that evaluates to the expected type"); - error = true; - }, + |err| self.explain_if_expr(err, ret_reason, if_span, cond_expr, then_expr, &mut error), false, ); error } + /// Explain why `if` expressions without `else` evaluate to `()` and detect likely irrefutable + /// `if let PAT = EXPR {}` expressions that could be turned into `let PAT = EXPR;`. + fn explain_if_expr( + &self, + err: &mut Diagnostic, + ret_reason: Option<(Span, String)>, + if_span: Span, + cond_expr: &'tcx hir::Expr<'tcx>, + then_expr: &'tcx hir::Expr<'tcx>, + error: &mut bool, + ) { + if let Some((if_span, msg)) = ret_reason { + err.span_label(if_span, msg.clone()); + } else if let ExprKind::Block(block, _) = then_expr.kind + && let Some(expr) = block.expr + { + err.span_label(expr.span, "found here"); + } + err.note("`if` expressions without `else` evaluate to `()`"); + err.help("consider adding an `else` block that evaluates to the expected type"); + *error = true; + if let ExprKind::Let(hir::Let { span, pat, init, .. }) = cond_expr.kind + && let ExprKind::Block(block, _) = then_expr.kind + // Refutability checks occur on the MIR, so we approximate it here by checking + // if we have an enum with a single variant or a struct in the pattern. + && let PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..) = pat.kind + && let hir::QPath::Resolved(_, path) = qpath + { + match path.res { + Res::Def(DefKind::Ctor(CtorOf::Struct, _), _) => { + // Structs are always irrefutable. Their fields might not be, but we + // don't check for that here, it's only an approximation. + } + Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) + if self + .tcx + .adt_def(self.tcx.parent(self.tcx.parent(def_id))) + .variants() + .len() + == 1 => + { + // There's only a single variant in the `enum`, so we can suggest the + // irrefutable `let` instead of `if let`. + } + _ => return, + } + + let mut sugg = vec![ + // Remove the `if` + (if_span.until(*span), String::new()), + ]; + match (block.stmts, block.expr) { + ([first, ..], Some(expr)) => { + let padding = self + .tcx + .sess + .source_map() + .indentation_before(first.span) + .unwrap_or_else(|| String::new()); + sugg.extend([ + (init.span.between(first.span), format!(";\n{padding}")), + (expr.span.shrink_to_hi().with_hi(block.span.hi()), String::new()), + ]); + } + ([], Some(expr)) => { + let padding = self + .tcx + .sess + .source_map() + .indentation_before(expr.span) + .unwrap_or_else(|| String::new()); + sugg.extend([ + (init.span.between(expr.span), format!(";\n{padding}")), + (expr.span.shrink_to_hi().with_hi(block.span.hi()), String::new()), + ]); + } + // If there's no value in the body, then the `if` expression would already + // be of type `()`, so checking for those cases is unnecessary. + (_, None) => return, + } + err.multipart_suggestion( + "consider using an irrefutable `let` binding instead", + sugg, + Applicability::MaybeIncorrect, + ); + } + } + pub fn maybe_get_coercion_reason( &self, hir_id: hir::HirId, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2bbef11fa2450..4f96b1fde1a6d 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1118,7 +1118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); } else { - self.if_fallback_coercion(sp, then_expr, &mut coerce); + self.if_fallback_coercion(sp, cond_expr, then_expr, &mut coerce); // If the condition is false we can't diverge. self.diverges.set(cond_diverges); diff --git a/tests/ui/binding/irrefutable-if-let-without-else.fixed b/tests/ui/binding/irrefutable-if-let-without-else.fixed new file mode 100644 index 0000000000000..3d7f4695ca864 --- /dev/null +++ b/tests/ui/binding/irrefutable-if-let-without-else.fixed @@ -0,0 +1,25 @@ +// run-rustfix +enum Enum { + Variant(i32), +} +struct Struct(i32); + +fn foo(x: Enum) -> i32 { + let Enum::Variant(value) = x; + value +} +fn bar(x: Enum) -> i32 { + let Enum::Variant(value) = x; + let x = value + 1; + x +} +fn baz(x: Struct) -> i32 { + let Struct(value) = x; + let x = value + 1; + x +} +fn main() { + let _ = foo(Enum::Variant(42)); + let _ = bar(Enum::Variant(42)); + let _ = baz(Struct(42)); +} diff --git a/tests/ui/binding/irrefutable-if-let-without-else.rs b/tests/ui/binding/irrefutable-if-let-without-else.rs new file mode 100644 index 0000000000000..5aaf4ace3f821 --- /dev/null +++ b/tests/ui/binding/irrefutable-if-let-without-else.rs @@ -0,0 +1,28 @@ +// run-rustfix +enum Enum { + Variant(i32), +} +struct Struct(i32); + +fn foo(x: Enum) -> i32 { + if let Enum::Variant(value) = x { //~ ERROR `if` may be missing an `else` clause + value + } +} +fn bar(x: Enum) -> i32 { + if let Enum::Variant(value) = x { //~ ERROR `if` may be missing an `else` clause + let x = value + 1; + x + } +} +fn baz(x: Struct) -> i32 { + if let Struct(value) = x { //~ ERROR `if` may be missing an `else` clause + let x = value + 1; + x + } +} +fn main() { + let _ = foo(Enum::Variant(42)); + let _ = bar(Enum::Variant(42)); + let _ = baz(Struct(42)); +} diff --git a/tests/ui/binding/irrefutable-if-let-without-else.stderr b/tests/ui/binding/irrefutable-if-let-without-else.stderr new file mode 100644 index 0000000000000..e234cfdd945f3 --- /dev/null +++ b/tests/ui/binding/irrefutable-if-let-without-else.stderr @@ -0,0 +1,61 @@ +error[E0317]: `if` may be missing an `else` clause + --> $DIR/irrefutable-if-let-without-else.rs:8:5 + | +LL | fn foo(x: Enum) -> i32 { + | --- expected `i32` because of this return type +LL | / if let Enum::Variant(value) = x { +LL | | value +LL | | } + | |_____^ expected `i32`, found `()` + | + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type +help: consider using an irrefutable `let` binding instead + | +LL ~ let Enum::Variant(value) = x; +LL ~ value + | + +error[E0317]: `if` may be missing an `else` clause + --> $DIR/irrefutable-if-let-without-else.rs:13:5 + | +LL | fn bar(x: Enum) -> i32 { + | --- expected `i32` because of this return type +LL | / if let Enum::Variant(value) = x { +LL | | let x = value + 1; +LL | | x +LL | | } + | |_____^ expected `i32`, found `()` + | + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type +help: consider using an irrefutable `let` binding instead + | +LL ~ let Enum::Variant(value) = x; +LL ~ let x = value + 1; +LL ~ x + | + +error[E0317]: `if` may be missing an `else` clause + --> $DIR/irrefutable-if-let-without-else.rs:19:5 + | +LL | fn baz(x: Struct) -> i32 { + | --- expected `i32` because of this return type +LL | / if let Struct(value) = x { +LL | | let x = value + 1; +LL | | x +LL | | } + | |_____^ expected `i32`, found `()` + | + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type +help: consider using an irrefutable `let` binding instead + | +LL ~ let Struct(value) = x; +LL ~ let x = value + 1; +LL ~ x + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0317`. From 25635b9a96ebbbd87bbbfb1d7c31004651179f2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Feb 2024 21:48:58 +0100 Subject: [PATCH 074/101] miri: fix ICE with symbolic alignment check on extern static --- .../src/interpret/validity.rs | 5 +-- src/tools/miri/src/borrow_tracker/mod.rs | 2 +- src/tools/miri/src/machine.rs | 34 +++++++++++-------- src/tools/miri/src/provenance_gc.rs | 1 + src/tools/miri/src/shims/foreign_items.rs | 12 +++---- ...88-ice-symbolic-alignment-extern-static.rs | 12 +++++++ ...ce-symbolic-alignment-extern-static.stderr | 14 ++++++++ .../miri/tests/pass/align_offset_symbolic.rs | 23 ++++++++++++- 8 files changed, 76 insertions(+), 27 deletions(-) create mode 100644 src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs create mode 100644 src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b5cd32595201f..4dbea54e22470 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -992,10 +992,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Complain about any other kind of error -- those are bad because we'd like to // report them in a way that shows *where* in the value the issue lies. Err(err) => { - bug!( - "Unexpected Undefined Behavior error during validation: {}", - self.format_error(err) - ); + bug!("Unexpected error during validation: {}", self.format_error(err)); } } } diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 74ff6ed4e0abe..46f96a715f1c6 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -383,7 +383,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // will never cause UB on the pointer itself. let (_, _, kind) = this.get_alloc_info(*alloc_id); if matches!(kind, AllocKind::LiveData) { - let alloc_extra = this.get_alloc_extra(*alloc_id).unwrap(); + let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static` let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap(); alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?; } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 946887637fff8..40d041c8fdb16 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -2,7 +2,7 @@ //! `Machine` trait. use std::borrow::Cow; -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; use std::collections::hash_map::Entry; use std::fmt; use std::path::Path; @@ -336,20 +336,11 @@ pub struct AllocExtra<'tcx> { /// if this allocation is leakable. The backtrace is not /// pruned yet; that should be done before printing it. pub backtrace: Option>>, - /// An offset inside this allocation that was deemed aligned even for symbolic alignment checks. - /// Invariant: the promised alignment will never be less than the native alignment of this allocation. - pub symbolic_alignment: Cell>, } impl VisitProvenance for AllocExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let AllocExtra { - borrow_tracker, - data_race, - weak_memory, - backtrace: _, - symbolic_alignment: _, - } = self; + let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _ } = self; borrow_tracker.visit_provenance(visit); data_race.visit_provenance(visit); @@ -572,6 +563,14 @@ pub struct MiriMachine<'mir, 'tcx> { /// that is fixed per stack frame; this lets us have sometimes different results for the /// same const while ensuring consistent results within a single call. const_cache: RefCell, usize), OpTy<'tcx, Provenance>>>, + + /// For each allocation, an offset inside that allocation that was deemed aligned even for + /// symbolic alignment checks. This cannot be stored in `AllocExtra` since it needs to be + /// tracked for vtables and function allocations as well as regular allocations. + /// + /// Invariant: the promised alignment will never be less than the native alignment of the + /// allocation. + pub(crate) symbolic_alignment: RefCell>, } impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { @@ -698,6 +697,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { collect_leak_backtraces: config.collect_leak_backtraces, allocation_spans: RefCell::new(FxHashMap::default()), const_cache: RefCell::new(FxHashMap::default()), + symbolic_alignment: RefCell::new(FxHashMap::default()), } } @@ -810,6 +810,7 @@ impl VisitProvenance for MiriMachine<'_, '_> { collect_leak_backtraces: _, allocation_spans: _, const_cache: _, + symbolic_alignment: _, } = self; threads.visit_provenance(visit); @@ -893,9 +894,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { return None; } // Let's see which alignment we have been promised for this allocation. - let alloc_info = ecx.get_alloc_extra(alloc_id).unwrap(); // cannot fail since the allocation is live - let (promised_offset, promised_align) = - alloc_info.symbolic_alignment.get().unwrap_or((Size::ZERO, alloc_align)); + let (promised_offset, promised_align) = ecx + .machine + .symbolic_alignment + .borrow() + .get(&alloc_id) + .copied() + .unwrap_or((Size::ZERO, alloc_align)); if promised_align < align { // Definitely not enough. Some(Misalignment { has: promised_align, required: align }) @@ -1132,7 +1137,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { data_race: race_alloc, weak_memory: buffer_alloc, backtrace, - symbolic_alignment: Cell::new(None), }, |ptr| ecx.global_base_pointer(ptr), )?; diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index ab178f82d9fde..347951ce37270 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -196,6 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); let allocs = LiveAllocs { ecx: this, collected: allocs }; this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id)); + this.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id)); this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs); if let Some(borrow_tracker) = &this.machine.borrow_tracker { borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs); diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index a002f2aad057c..25654248db41a 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -585,17 +585,17 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr) { let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id); - // Not `get_alloc_extra_mut`, need to handle read-only allocations! - let alloc_extra = this.get_alloc_extra(alloc_id)?; // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align - && !alloc_extra + && !this + .machine .symbolic_alignment - .get() - .is_some_and(|(_, old_align)| align <= old_align) + .get_mut() + .get(&alloc_id) + .is_some_and(|&(_, old_align)| align <= old_align) { - alloc_extra.symbolic_alignment.set(Some((offset, align))); + this.machine.symbolic_alignment.get_mut().insert(alloc_id, (offset, align)); } } } diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs new file mode 100644 index 0000000000000..446040749822e --- /dev/null +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs @@ -0,0 +1,12 @@ +//@compile-flags: -Zmiri-symbolic-alignment-check + +extern "C" { + static _dispatch_queue_attr_concurrent: [u8; 0]; +} + +static DISPATCH_QUEUE_CONCURRENT: &'static [u8; 0] = + unsafe { &_dispatch_queue_attr_concurrent }; + +fn main() { + let _val = *DISPATCH_QUEUE_CONCURRENT; //~ERROR: is not supported +} diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr new file mode 100644 index 0000000000000..a4249d2e8816d --- /dev/null +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri + --> $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC + | +LL | let _val = *DISPATCH_QUEUE_CONCURRENT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs index 4df364bac7ad9..e96f11b1efa72 100644 --- a/src/tools/miri/tests/pass/align_offset_symbolic.rs +++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs @@ -1,6 +1,8 @@ //@compile-flags: -Zmiri-symbolic-alignment-check #![feature(strict_provenance)] +use std::mem; + fn test_align_to() { const N: usize = 4; let d = Box::new([0u32; N]); @@ -68,7 +70,7 @@ fn test_u64_array() { #[repr(align(8))] struct AlignToU64(T); - const BYTE_LEN: usize = std::mem::size_of::<[u64; 4]>(); + const BYTE_LEN: usize = mem::size_of::<[u64; 4]>(); type Data = AlignToU64<[u8; BYTE_LEN]>; fn example(data: &Data) { @@ -101,10 +103,29 @@ fn huge_align() { let _ = std::ptr::invalid::(SIZE).align_offset(SIZE); } +// This shows that we cannot store the promised alignment info in `AllocExtra`, +// since vtables do not have an `AllocExtra`. +fn vtable() { + #[cfg(target_pointer_width = "64")] + type TWOPTR = u128; + #[cfg(target_pointer_width = "32")] + type TWOPTR = u64; + + let ptr: &dyn Send = &0; + let parts: (*const (), *const u8) = unsafe { mem::transmute(ptr) }; + let vtable = parts.1 ; + let offset = vtable.align_offset(mem::align_of::()); + let _vtable_aligned = vtable.wrapping_add(offset) as *const [TWOPTR; 0]; + // FIXME: we can't actually do the access since vtable pointers act like zero-sized allocations. + // Enable the next line once https://github.com/rust-lang/rust/issues/117945 is implemented. + //let _place = unsafe { &*vtable_aligned }; +} + fn main() { test_align_to(); test_from_utf8(); test_u64_array(); test_cstr(); huge_align(); + vtable(); } From 2a06b69ba2600dbcd599641923fdc23b66344f9c Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 26 Jan 2024 11:36:56 +0300 Subject: [PATCH 075/101] llvm-wrapper: remove llvm 12 hack effectively reverts https://github.com/rust-lang/rust/commit/9a8acea78355b604dbeb29bc38bd4dbf7bfce95f --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 6114f7c867807..ed7aa437ddd2e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -945,12 +945,7 @@ LLVMRustOptimize( break; case LLVMRustOptStage::PreLinkThinLTO: MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel); - // The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback - // passes may still run afterwards. This means we need to run the buffer passes again. - // FIXME: In LLVM 13, the ThinLTOPreLink pipeline also runs OptimizerLastEPCallbacks - // before the RequiredLTOPreLinkPasses, in which case we can remove these hacks. - if (OptimizerLastEPCallbacks.empty()) - NeedThinLTOBufferPasses = false; + NeedThinLTOBufferPasses = false; for (const auto &C : OptimizerLastEPCallbacks) C(MPM, OptLevel); break; From ca35cfb6defe6bdec8ab0419aa682db780142fb7 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 6 Feb 2024 12:44:40 +0300 Subject: [PATCH 076/101] review --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index ed7aa437ddd2e..3b6bf03686b0d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -934,10 +934,8 @@ LLVMRustOptimize( } else { for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); - if (OptStage != LLVMRustOptStage::PreLinkThinLTO) { - for (const auto &C : OptimizerLastEPCallbacks) - PB.registerOptimizerLastEPCallback(C); - } + for (const auto &C : OptimizerLastEPCallbacks) + PB.registerOptimizerLastEPCallback(C); switch (OptStage) { case LLVMRustOptStage::PreLinkNoLTO: @@ -946,8 +944,6 @@ LLVMRustOptimize( case LLVMRustOptStage::PreLinkThinLTO: MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel); NeedThinLTOBufferPasses = false; - for (const auto &C : OptimizerLastEPCallbacks) - C(MPM, OptLevel); break; case LLVMRustOptStage::PreLinkFatLTO: MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel); From d9cd0d4d1180f09ea67be012848ff295a4681961 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Feb 2024 16:01:54 +0000 Subject: [PATCH 077/101] Don't expect early-bound region to be local in RPITIT well-formedness --- compiler/rustc_middle/src/ty/context.rs | 2 +- .../in-trait/auxiliary/bad-region.rs | 7 +++++++ tests/ui/async-await/in-trait/bad-region.rs | 17 +++++++++++++++++ tests/ui/async-await/in-trait/bad-region.stderr | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/ui/async-await/in-trait/auxiliary/bad-region.rs create mode 100644 tests/ui/async-await/in-trait/bad-region.rs create mode 100644 tests/ui/async-await/in-trait/bad-region.stderr diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0d53870a0baf0..70c6811e539b9 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1193,7 +1193,7 @@ impl<'tcx> TyCtxt<'tcx> { let (suitable_region_binding_scope, bound_region) = loop { let def_id = match region.kind() { ty::ReLateParam(fr) => fr.bound_region.get_id()?.as_local()?, - ty::ReEarlyParam(ebr) => ebr.def_id.expect_local(), + ty::ReEarlyParam(ebr) => ebr.def_id.as_local()?, _ => return None, // not a free region }; let scope = self.local_parent(def_id); diff --git a/tests/ui/async-await/in-trait/auxiliary/bad-region.rs b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs new file mode 100644 index 0000000000000..02dc25aaa16bb --- /dev/null +++ b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs @@ -0,0 +1,7 @@ +// edition:2021 + +#[allow(async_fn_in_trait)] + +pub trait BleRadio<'a> { + async fn transmit(&mut self); +} diff --git a/tests/ui/async-await/in-trait/bad-region.rs b/tests/ui/async-await/in-trait/bad-region.rs new file mode 100644 index 0000000000000..444368e21a497 --- /dev/null +++ b/tests/ui/async-await/in-trait/bad-region.rs @@ -0,0 +1,17 @@ +// aux-build:bad-region.rs +// edition:2021 + +#![allow(async_fn_in_trait)] + +extern crate bad_region as jewel; + +use jewel::BleRadio; + +pub struct Radio {} + +impl BleRadio for Radio { +//~^ ERROR implicit elided lifetime not allowed here + async fn transmit(&mut self) {} +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/bad-region.stderr b/tests/ui/async-await/in-trait/bad-region.stderr new file mode 100644 index 0000000000000..9203fd790af78 --- /dev/null +++ b/tests/ui/async-await/in-trait/bad-region.stderr @@ -0,0 +1,14 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/bad-region.rs:12:6 + | +LL | impl BleRadio for Radio { + | ^^^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | impl BleRadio<'_> for Radio { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0726`. From aef18c9bfb8c7844b95f6d950133f61b0fa2158b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Jan 2024 18:54:29 +0000 Subject: [PATCH 078/101] Mark "unused binding" suggestion as maybe incorrect Ignoring unused bindings should be a determination made by a human, `rustfix` shouldn't auto-apply the suggested change. Fix #54196. --- compiler/rustc_passes/src/errors.rs | 4 ++-- tests/ui/lint/future-incompat-json-test.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 77bfe57e3706f..5db2369ad76c2 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1739,7 +1739,7 @@ pub struct UnusedVariableTryPrefix { #[derive(Subdiagnostic)] pub enum UnusedVariableSugg { - #[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] + #[multipart_suggestion(passes_suggestion, applicability = "maybe-incorrect")] TryPrefixSugg { #[suggestion_part(code = "_{name}")] spans: Vec, @@ -1778,7 +1778,7 @@ pub struct UnusedVarTryIgnore { } #[derive(Subdiagnostic)] -#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(passes_suggestion, applicability = "maybe-incorrect")] pub struct UnusedVarTryIgnoreSugg { #[suggestion_part(code = "{name}: _")] pub shorthands: Vec, diff --git a/tests/ui/lint/future-incompat-json-test.stderr b/tests/ui/lint/future-incompat-json-test.stderr index c4ab5a00d16cc..18fc3f17f0020 100644 --- a/tests/ui/lint/future-incompat-json-test.stderr +++ b/tests/ui/lint/future-incompat-json-test.stderr @@ -1,4 +1,4 @@ -{"$message_type":"future_incompat","future_incompat_report":[{"diagnostic":{"$message_type":"diagnostic","message":"unused variable: `x`","code":{"code":"unused_variables","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`-A unused-variables` implied by `-A unused`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"to override `-A unused` add `#[allow(unused_variables)]`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"if this is intentional, prefix it with an underscore","code":null,"level":"help","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"_x","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: unused variable: `x` +{"$message_type":"future_incompat","future_incompat_report":[{"diagnostic":{"$message_type":"diagnostic","message":"unused variable: `x`","code":{"code":"unused_variables","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`-A unused-variables` implied by `-A unused`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"to override `-A unused` add `#[allow(unused_variables)]`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"if this is intentional, prefix it with an underscore","code":null,"level":"help","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"_x","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: unused variable: `x` --> $DIR/future-incompat-json-test.rs:9:9 | LL | let x = 1; From f1308783b4a7e613d60bddfa0f5474363c198289 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Feb 2024 17:41:48 +0000 Subject: [PATCH 079/101] Make async closures test use async bound modifier --- .../async-closures/async-fn-mut-for-async-fn.rs | 6 ++---- .../async-closures/async-fn-once-for-async-fn.rs | 6 ++---- .../async-await/async-closures/auxiliary/block-on.rs | 2 +- tests/ui/async-await/async-closures/brand.rs | 5 ++--- tests/ui/async-await/async-closures/drop.rs | 6 ++---- tests/ui/async-await/async-closures/mangle.rs | 7 +++---- tests/ui/async-await/async-closures/wrong-fn-kind.rs | 8 +++----- .../ui/async-await/async-closures/wrong-fn-kind.stderr | 10 +++++----- 8 files changed, 20 insertions(+), 30 deletions(-) diff --git a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs index 8d7dc6a276b90..f73b43dd152f0 100644 --- a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs +++ b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs @@ -5,17 +5,15 @@ // FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. // ignore-pass (test emits codegen-time warnings) -#![feature(async_closure, async_fn_traits)] +#![feature(async_closure)] extern crate block_on; -use std::ops::AsyncFnMut; - fn main() { block_on::block_on(async { let x = async || {}; - async fn needs_async_fn_mut(mut x: impl AsyncFnMut()) { + async fn needs_async_fn_mut(mut x: impl async FnMut()) { x().await; } needs_async_fn_mut(x).await; diff --git a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs index 4afc43fe6bd92..0ba323a71cd13 100644 --- a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs +++ b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs @@ -5,17 +5,15 @@ // FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. // ignore-pass (test emits codegen-time warnings) -#![feature(async_closure, async_fn_traits)] +#![feature(async_closure)] extern crate block_on; -use std::ops::AsyncFnOnce; - fn main() { block_on::block_on(async { let x = async || {}; - async fn needs_async_fn_once(x: impl AsyncFnOnce()) { + async fn needs_async_fn_once(x: impl async FnOnce()) { x().await; } needs_async_fn_once(x).await; diff --git a/tests/ui/async-await/async-closures/auxiliary/block-on.rs b/tests/ui/async-await/async-closures/auxiliary/block-on.rs index 3c27548b865a7..902e033cfe711 100644 --- a/tests/ui/async-await/async-closures/auxiliary/block-on.rs +++ b/tests/ui/async-await/async-closures/auxiliary/block-on.rs @@ -1,6 +1,6 @@ // edition: 2021 -#![feature(async_closure, noop_waker, async_fn_traits)] +#![feature(async_closure, noop_waker)] use std::future::Future; use std::pin::pin; diff --git a/tests/ui/async-await/async-closures/brand.rs b/tests/ui/async-await/async-closures/brand.rs index 3bda7737bb406..26d2ed5a6ef65 100644 --- a/tests/ui/async-await/async-closures/brand.rs +++ b/tests/ui/async-await/async-closures/brand.rs @@ -2,19 +2,18 @@ // edition:2021 // build-pass -#![feature(async_closure, async_fn_traits)] +#![feature(async_closure)] extern crate block_on; use std::future::Future; use std::marker::PhantomData; -use std::ops::AsyncFn; struct S; struct B<'b>(PhantomData<&'b mut &'b mut ()>); impl S { - async fn q)>(self, f: F) { + async fn q)>(self, f: F) { f(B(PhantomData)).await; } } diff --git a/tests/ui/async-await/async-closures/drop.rs b/tests/ui/async-await/async-closures/drop.rs index 1b7f2f8a600d0..a243d20774d27 100644 --- a/tests/ui/async-await/async-closures/drop.rs +++ b/tests/ui/async-await/async-closures/drop.rs @@ -3,13 +3,11 @@ // run-pass // check-run-results -#![feature(async_closure, async_fn_traits)] +#![feature(async_closure)] #![allow(unused)] extern crate block_on; -use std::ops::AsyncFnOnce; - struct DropMe(i32); impl Drop for DropMe { @@ -18,7 +16,7 @@ impl Drop for DropMe { } } -async fn call_once(f: impl AsyncFnOnce()) { +async fn call_once(f: impl async FnOnce()) { println!("before call"); let fut = Box::pin(f()); println!("after call"); diff --git a/tests/ui/async-await/async-closures/mangle.rs b/tests/ui/async-await/async-closures/mangle.rs index 98065c3c71109..9d231d551765e 100644 --- a/tests/ui/async-await/async-closures/mangle.rs +++ b/tests/ui/async-await/async-closures/mangle.rs @@ -8,20 +8,19 @@ // FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this. // ignore-pass (test emits codegen-time warnings) -#![feature(async_closure, noop_waker, async_fn_traits)] +#![feature(async_closure, noop_waker)] extern crate block_on; use std::future::Future; -use std::ops::{AsyncFnMut, AsyncFnOnce}; use std::pin::pin; use std::task::*; -async fn call_mut(f: &mut impl AsyncFnMut()) { +async fn call_mut(f: &mut impl async FnMut()) { f().await; } -async fn call_once(f: impl AsyncFnOnce()) { +async fn call_once(f: impl async FnOnce()) { f().await; } diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs index 248288325319e..f86cee3e0709e 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -2,17 +2,15 @@ // FIXME(async_closures): This needs a better error message! -#![feature(async_closure, async_fn_traits)] - -use std::ops::AsyncFn; +#![feature(async_closure)] fn main() { - fn needs_async_fn(_: impl AsyncFn()) {} + fn needs_async_fn(_: impl async Fn()) {} let mut x = 1; needs_async_fn(async || { //~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper - // FIXME: Should say "closure is AsyncFnMut but it needs AsyncFn" or sth. + // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. x += 1; }); } diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index ef95e6a211c74..4ef8484cc34cd 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -1,21 +1,21 @@ error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not satisfied - --> $DIR/wrong-fn-kind.rs:13:20 + --> $DIR/wrong-fn-kind.rs:11:20 | LL | needs_async_fn(async || { | _____--------------_^ | | | | | required by a bound introduced by this call LL | | -LL | | // FIXME: Should say "closure is AsyncFnMut but it needs AsyncFn" or sth. +LL | | // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. LL | | x += 1; LL | | }); | |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not implemented for `i16` | note: required by a bound in `needs_async_fn` - --> $DIR/wrong-fn-kind.rs:10:31 + --> $DIR/wrong-fn-kind.rs:8:31 | -LL | fn needs_async_fn(_: impl AsyncFn()) {} - | ^^^^^^^^^ required by this bound in `needs_async_fn` +LL | fn needs_async_fn(_: impl async Fn()) {} + | ^^^^^^^^^^ required by this bound in `needs_async_fn` error: aborting due to 1 previous error From 8d1c20a539b72abdbe1ede872f19e0a1a6f34be4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 6 Feb 2024 17:13:32 +1100 Subject: [PATCH 080/101] Remove return value from `emit_stashed_diagnostics`. It's never used. --- compiler/rustc_errors/src/lib.rs | 9 +++------ compiler/rustc_session/src/session.rs | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a4112d717d029..7c62e3aa42281 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -708,7 +708,7 @@ impl DiagCtxt { } /// Emit all stashed diagnostics. - pub fn emit_stashed_diagnostics(&self) -> Option { + pub fn emit_stashed_diagnostics(&self) { self.inner.borrow_mut().emit_stashed_diagnostics() } @@ -1216,9 +1216,8 @@ impl DiagCtxt { // `DiagCtxtInner::foo`. impl DiagCtxtInner { /// Emit all stashed diagnostics. - fn emit_stashed_diagnostics(&mut self) -> Option { + fn emit_stashed_diagnostics(&mut self) { let has_errors = self.has_errors(); - let mut reported = None; for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { @@ -1235,10 +1234,8 @@ impl DiagCtxtInner { continue; } } - let reported_this = self.emit_diagnostic(diag); - reported = reported.or(reported_this); + self.emit_diagnostic(diag); } - reported } fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f6af5a4f87e07..ec14385f40c62 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -315,7 +315,7 @@ impl Session { pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { // We must include lint errors here. if let Some(reported) = self.dcx().has_errors_or_lint_errors() { - let _ = self.dcx().emit_stashed_diagnostics(); + self.dcx().emit_stashed_diagnostics(); Err(reported) } else { Ok(()) From 14dda5fdfb81e61b2acc85f27609f879aeaa166d Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 6 Feb 2024 21:03:07 -0500 Subject: [PATCH 081/101] Don't use bashism in checktools.sh --- src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index cc0c658aabd2b..f5c426a717f78 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -30,7 +30,7 @@ python3 "$X_PY" test --stage 2 src/tools/rustfmt # We set the GC interval to the shortest possible value (0 would be off) to increase the chance # that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail. # This significantly increases the runtime of our test suite, or we'd do this in PR CI too. -if [[ -z "${PR_CI_JOB:-}" ]]; then +if [ -z "${PR_CI_JOB:-}" ]; then MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri else python3 "$X_PY" test --stage 2 src/tools/miri From 40878ca6ea79d6e55e430846a2de3350a76cd08f Mon Sep 17 00:00:00 2001 From: r0cky Date: Tue, 2 Jan 2024 00:14:21 +0800 Subject: [PATCH 082/101] Make traits / trait methods detected by the dead code lint! --- compiler/rustc_passes/src/dead.rs | 91 +++++++++++++++++----- tests/ui/lint/dead-code/issue-41883.rs | 29 +++++++ tests/ui/lint/dead-code/issue-41883.stderr | 36 +++++++++ 3 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 tests/ui/lint/dead-code/issue-41883.rs create mode 100644 tests/ui/lint/dead-code/issue-41883.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d19987cb33cf2..e11102c459e42 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -4,6 +4,7 @@ // is dead. use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; +use hir::ItemKind; use rustc_data_structures::unord::UnordSet; use rustc_errors::MultiSpan; use rustc_hir as hir; @@ -14,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; use rustc_span::symbol::{sym, Symbol}; @@ -381,9 +382,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_item(self, item) } hir::ItemKind::ForeignMod { .. } => {} + hir::ItemKind::Trait(..) => { + for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) { + if let Some(local_def_id) = impl_def_id.as_local() + && let ItemKind::Impl(impl_ref) = + self.tcx.hir().expect_item(local_def_id).kind + { + // skip items + // mark dependent traits live + intravisit::walk_generics(self, impl_ref.generics); + // mark dependent parameters live + intravisit::walk_path(self, impl_ref.of_trait.unwrap().path); + } + } + + intravisit::walk_item(self, item) + } _ => intravisit::walk_item(self, item), }, Node::TraitItem(trait_item) => { + // mark corresponing ImplTerm live + let trait_item_id = trait_item.owner_id.to_def_id(); + if let Some(trait_id) = self.tcx.trait_of_item(trait_item_id) { + // mark the trait live + self.check_def_id(trait_id); + + for impl_id in self.tcx.all_impls(trait_id) { + if let Some(local_impl_id) = impl_id.as_local() + && let ItemKind::Impl(impl_ref) = + self.tcx.hir().expect_item(local_impl_id).kind + { + // mark self_ty live + intravisit::walk_ty(self, impl_ref.self_ty); + if let Some(&impl_item_id) = + self.tcx.impl_item_implementor_ids(impl_id).get(&trait_item_id) + { + self.check_def_id(impl_item_id); + } + } + } + } intravisit::walk_trait_item(self, trait_item); } Node::ImplItem(impl_item) => { @@ -636,10 +674,6 @@ fn check_item<'tcx>( } } DefKind::Impl { of_trait } => { - if of_trait { - worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No)); - } - // get DefIds from another query let local_def_ids = tcx .associated_item_def_ids(id.owner_id) @@ -648,7 +682,11 @@ fn check_item<'tcx>( // And we access the Map here to get HirId from LocalDefId for id in local_def_ids { - if of_trait { + // for impl trait blocks, mark associate functions live if the trait is public + if of_trait + && (!matches!(tcx.def_kind(id), DefKind::AssocFn) + || tcx.local_visibility(id) == Visibility::Public) + { worklist.push((id, ComesFromAllowExpect::No)); } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, id) { worklist.push((id, comes_from_allow)); @@ -679,7 +717,7 @@ fn check_trait_item( use hir::TraitItemKind::{Const, Fn}; if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) + if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..)) && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { @@ -948,7 +986,8 @@ impl<'tcx> DeadVisitor<'tcx> { | DefKind::TyAlias | DefKind::Enum | DefKind::Union - | DefKind::ForeignTy => self.warn_dead_code(def_id, "used"), + | DefKind::ForeignTy + | DefKind::Trait => self.warn_dead_code(def_id, "used"), DefKind::Struct => self.warn_dead_code(def_id, "constructed"), DefKind::Variant | DefKind::Field => bug!("should be handled specially"), _ => {} @@ -973,18 +1012,33 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let module_items = tcx.hir_module_items(module); for item in module_items.items() { - if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind { - let mut dead_items = Vec::new(); - for item in impl_item.items { - let def_id = item.id.owner_id.def_id; - if !visitor.is_live_code(def_id) { - let name = tcx.item_name(def_id.to_def_id()); - let level = visitor.def_lint_level(def_id); + let def_kind = tcx.def_kind(item.owner_id); - dead_items.push(DeadItem { def_id, name, level }) + let mut dead_codes = Vec::new(); + // if we have diagnosed the trait, do not diagnose unused methods + if matches!(def_kind, DefKind::Impl { .. }) + || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) + { + for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { + // We have diagnosed unused methods in traits + if matches!(def_kind, DefKind::Impl { of_trait: true }) + && tcx.def_kind(def_id) == DefKind::AssocFn + || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn + { + continue; + } + + if let Some(local_def_id) = def_id.as_local() + && !visitor.is_live_code(local_def_id) + { + let name = tcx.item_name(def_id); + let level = visitor.def_lint_level(local_def_id); + dead_codes.push(DeadItem { def_id: local_def_id, name, level }); } } - visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, ReportOn::NamedField); + } + if !dead_codes.is_empty() { + visitor.warn_multiple(item.owner_id.def_id, "used", dead_codes, ReportOn::NamedField); } if !live_symbols.contains(&item.owner_id.def_id) { @@ -997,7 +1051,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { continue; } - let def_kind = tcx.def_kind(item.owner_id); if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind { let adt = tcx.adt_def(item.owner_id); let mut dead_variants = Vec::new(); @@ -1044,8 +1097,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { for foreign_item in module_items.foreign_items() { visitor.check_definition(foreign_item.owner_id.def_id); } - - // We do not warn trait items. } pub(crate) fn provide(providers: &mut Providers) { diff --git a/tests/ui/lint/dead-code/issue-41883.rs b/tests/ui/lint/dead-code/issue-41883.rs new file mode 100644 index 0000000000000..e165861e893e0 --- /dev/null +++ b/tests/ui/lint/dead-code/issue-41883.rs @@ -0,0 +1,29 @@ +#![deny(dead_code)] + +enum Category { + Dead, //~ ERROR variant `Dead` is never constructed + Used, +} + +trait UnusedTrait { //~ ERROR trait `UnusedTrait` is never used + fn this_is_unused(&self) -> Category { + Category::Dead + } +} + +struct UnusedStruct; //~ ERROR struct `UnusedStruct` is never constructed + +impl UnusedTrait for UnusedStruct { + fn this_is_unused(&self) -> Category { + Category::Used + } +} + +mod private { + #[derive(Debug)] + struct UnusedStruct; //~ ERROR struct `UnusedStruct` is never constructed +} + +fn main() { + let _c = Category::Used; +} diff --git a/tests/ui/lint/dead-code/issue-41883.stderr b/tests/ui/lint/dead-code/issue-41883.stderr new file mode 100644 index 0000000000000..cf079e4dda33a --- /dev/null +++ b/tests/ui/lint/dead-code/issue-41883.stderr @@ -0,0 +1,36 @@ +error: variant `Dead` is never constructed + --> $DIR/issue-41883.rs:4:5 + | +LL | enum Category { + | -------- variant in this enum +LL | Dead, + | ^^^^ + | +note: the lint level is defined here + --> $DIR/issue-41883.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: trait `UnusedTrait` is never used + --> $DIR/issue-41883.rs:8:7 + | +LL | trait UnusedTrait { + | ^^^^^^^^^^^ + +error: struct `UnusedStruct` is never constructed + --> $DIR/issue-41883.rs:14:8 + | +LL | struct UnusedStruct; + | ^^^^^^^^^^^^ + +error: struct `UnusedStruct` is never constructed + --> $DIR/issue-41883.rs:24:12 + | +LL | struct UnusedStruct; + | ^^^^^^^^^^^^ + | + = note: `UnusedStruct` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis + +error: aborting due to 4 previous errors + From c7519d42c2664828c98fdb98acab73e9a39b0b97 Mon Sep 17 00:00:00 2001 From: r0cky Date: Wed, 7 Feb 2024 10:42:01 +0800 Subject: [PATCH 083/101] Update tests --- compiler/rustc_span/src/source_map/tests.rs | 49 +------------------ library/core/tests/macros.rs | 1 + library/std/src/sys_common/mod.rs | 2 + .../tests/fail/dyn-call-trait-mismatch.rs | 1 + .../tests/fail/dyn-upcast-trait-mismatch.rs | 6 +++ .../tests/pass/cast-rfc0401-vtable-kinds.rs | 1 + src/tools/miri/tests/pass/dyn-upcast.rs | 3 ++ src/tools/miri/tests/pass/weak_memory/weak.rs | 1 + src/tools/tidy/src/ui_tests.rs | 5 +- .../instantiation-through-vtable.rs | 4 +- .../trait-method-default-impl.rs | 3 ++ .../codegen-units/item-collection/unsizing.rs | 2 + tests/ui-fulldeps/rustc_encodable_hygiene.rs | 2 +- .../anon-params/anon-params-deprecated.fixed | 1 + .../ui/anon-params/anon-params-deprecated.rs | 1 + .../anon-params/anon-params-deprecated.stderr | 6 +-- .../associated-const-outer-ty-refs.rs | 3 +- .../associated-const-type-parameters.rs | 2 +- .../associated-const-type-parameters.stderr | 10 ++++ .../dyn-impl-trait-type.rs | 2 +- .../dyn-impl-trait-type.stderr | 12 +++++ .../dyn-rpit-and-let.rs | 2 +- .../dyn-rpit-and-let.stderr | 12 +++++ tests/ui/associated-type-bounds/rpit.rs | 2 +- tests/ui/associated-type-bounds/rpit.stderr | 12 +++++ ...ng-assoc-type-because-of-assoc-const.fixed | 1 + ...ining-assoc-type-because-of-assoc-const.rs | 1 + ...g-assoc-type-because-of-assoc-const.stderr | 2 +- .../trait-alias-impl-trait.rs | 1 + .../associated-types-for-unimpl-trait.fixed | 1 + .../associated-types-for-unimpl-trait.rs | 1 + .../associated-types-for-unimpl-trait.stderr | 2 +- .../associated-types-in-bound-type-arg.rs | 2 +- .../associated-types-issue-20220.rs | 2 +- .../associated-types-issue-20220.stderr | 10 ++++ .../associated-types-issue-20371.rs | 2 +- .../associated-types-nested-projections.rs | 2 +- ...associated-types-nested-projections.stderr | 13 +++++ ...sociated-types-normalize-in-bounds-ufcs.rs | 2 +- .../associated-types-normalize-in-bounds.rs | 2 +- ...d-types-projection-bound-in-supertraits.rs | 2 +- ...ypes-projection-from-known-type-in-impl.rs | 2 +- ...-projection-from-known-type-in-impl.stderr | 13 +++++ ...ated-trait-in-method-without-default.fixed | 1 + ...related-trait-in-method-without-default.rs | 1 + ...ted-trait-in-method-without-default.stderr | 2 +- ...ted-types-projection-to-unrelated-trait.rs | 2 +- ...ed-path-with-trait-with-type-parameters.rs | 2 +- .../associated-types-resolve-lifetime.rs | 2 +- .../ui/associated-types/impl-wf-cycle-5.fixed | 2 + tests/ui/associated-types/impl-wf-cycle-5.rs | 2 + .../associated-types/impl-wf-cycle-5.stderr | 4 +- .../ui/associated-types/impl-wf-cycle-6.fixed | 2 + tests/ui/associated-types/impl-wf-cycle-6.rs | 2 + .../associated-types/impl-wf-cycle-6.stderr | 4 +- .../auto-traits/auto-trait-validation.fixed | 1 + tests/ui/auto-traits/auto-trait-validation.rs | 1 + .../auto-traits/auto-trait-validation.stderr | 8 +-- tests/ui/auto-traits/auto-traits.rs | 4 +- tests/ui/auto-traits/auto-traits.stderr | 16 ++++++ .../builtin-superkinds-in-metadata2.rs | 2 +- .../builtin-superkinds-simple2.rs | 2 +- .../builtin-superkinds-typaram.rs | 2 +- tests/ui/cast/cast-rfc0401-vtable-kinds.rs | 2 +- .../ui/cast/cast-rfc0401-vtable-kinds.stderr | 10 ++++ tests/ui/cast/fat-ptr-cast-rpass.rs | 2 +- tests/ui/cast/fat-ptr-cast-rpass.stderr | 12 +++++ tests/ui/coercion/issue-14589.rs | 2 +- tests/ui/coercion/issue-14589.stderr | 12 +++++ .../coherence-multidispatch-tuple.rs | 2 +- .../const-generics/associated-type-bound.rs | 2 +- .../condition-in-trait-const-arg.rs | 2 +- tests/ui/const-generics/dyn-supertraits.rs | 6 +-- .../ui/const-generics/dyn-supertraits.stderr | 22 +++++++++ .../issues/issue-69654-run-pass.rs | 2 +- .../issues/issue-69654-run-pass.stderr | 10 ++++ tests/ui/consts/const-block-item.rs | 2 +- tests/ui/consts/const-block-item.stderr | 10 ++++ tests/ui/consts/underscore_const_names.rs | 4 +- tests/ui/default-method-parsing.rs | 2 +- tests/ui/delegation/target-expr-pass.rs | 6 +-- tests/ui/delegation/target-expr-pass.stderr | 22 ++++++++- tests/ui/deriving/deriving-bounds.rs | 2 +- tests/ui/drop/drop-struct-as-object.rs | 2 +- tests/ui/drop/drop-struct-as-object.stderr | 12 +++++ .../dynamically-sized-types/dst-coercions.rs | 2 +- .../dst-coercions.stderr | 12 +++++ tests/ui/empty-type-parameter-list.rs | 2 +- tests/ui/empty-type-parameter-list.stderr | 10 ++++ .../explicit-call-to-supertrait-dtor.fixed | 1 + .../explicit-call-to-supertrait-dtor.rs | 1 + .../explicit-call-to-supertrait-dtor.stderr | 2 +- tests/ui/extern/no-mangle-associated-fn.rs | 2 +- .../ui/extern/no-mangle-associated-fn.stderr | 10 ++++ .../issue-88360.fixed | 1 + .../generic-associated-types/issue-88360.rs | 1 + .../issue-88360.stderr | 2 +- tests/ui/generics/generic-no-mangle.fixed | 2 +- tests/ui/generics/generic-no-mangle.rs | 2 +- tests/ui/impl-trait/example-st.rs | 2 +- tests/ui/impl-trait/example-st.stderr | 10 ++++ .../in-trait/suggest-missing-item.fixed | 1 + .../in-trait/suggest-missing-item.rs | 1 + .../in-trait/suggest-missing-item.stderr | 2 +- .../ui/impl-trait/type-alias-generic-param.rs | 2 +- .../type-alias-generic-param.stderr | 10 ++++ tests/ui/issues/issue-14399.rs | 2 +- tests/ui/issues/issue-14399.stderr | 12 +++++ tests/ui/issues/issue-15858.rs | 2 +- tests/ui/issues/issue-15858.stderr | 12 +++++ tests/ui/issues/issue-17351.rs | 2 +- tests/ui/issues/issue-17351.stderr | 12 +++++ tests/ui/issues/issue-18173.rs | 2 +- tests/ui/issues/issue-20055-box-trait.rs | 2 +- tests/ui/issues/issue-20055-box-trait.stderr | 12 +++++ tests/ui/issues/issue-21909.rs | 2 +- tests/ui/issues/issue-23485.rs | 2 +- tests/ui/issues/issue-23485.stderr | 13 +++++ tests/ui/issues/issue-2989.rs | 4 +- tests/ui/issues/issue-2989.stderr | 10 ++++ tests/ui/issues/issue-34074.rs | 2 +- tests/ui/issues/issue-34503.rs | 2 +- tests/ui/issues/issue-34503.stderr | 14 ++++++ tests/ui/issues/issue-3563-3.rs | 2 +- tests/ui/issues/issue-3563-3.stderr | 13 +++++ tests/ui/issues/issue-50571.fixed | 1 + tests/ui/issues/issue-50571.rs | 1 + tests/ui/issues/issue-50571.stderr | 2 +- tests/ui/issues/issue-7575.rs | 2 +- tests/ui/issues/issue-7575.stderr | 10 ++++ tests/ui/issues/issue-7911.rs | 2 +- tests/ui/issues/issue-7911.stderr | 12 +++++ tests/ui/issues/issue-8248.rs | 2 +- tests/ui/issues/issue-8248.stderr | 12 +++++ tests/ui/issues/issue-9951.rs | 2 +- tests/ui/issues/issue-9951.stderr | 12 +++++ tests/ui/lint/dead-code/associated-type.rs | 2 +- .../multiple-dead-codes-in-the-same-struct.rs | 2 +- ...tiple-dead-codes-in-the-same-struct.stderr | 12 ++--- tests/ui/lint/issue-20343.rs | 3 ++ tests/ui/macros/issue-22463.rs | 2 +- tests/ui/methods/method-lookup-order.rs | 1 + .../methods/method-recursive-blanket-impl.rs | 2 +- .../method-recursive-blanket-impl.stderr | 10 ++++ .../method-two-trait-defer-resolution-2.rs | 2 +- ...method-two-trait-defer-resolution-2.stderr | 12 +++++ ...o-traits-distinguished-via-where-clause.rs | 2 +- ...aits-distinguished-via-where-clause.stderr | 10 ++++ tests/ui/mir/mir_raw_fat_ptr.rs | 2 +- tests/ui/mir/mir_raw_fat_ptr.stderr | 12 +++++ .../ui/moves/issue-22536-copy-mustnt-zero.rs | 2 +- .../moves/issue-22536-copy-mustnt-zero.stderr | 13 +++++ .../assoc_type_bounds_implicit_sized.fixed | 1 + .../assoc_type_bounds_implicit_sized.rs | 1 + .../assoc_type_bounds_implicit_sized.stderr | 4 +- tests/ui/overloaded/issue-14958.rs | 2 +- tests/ui/overloaded/issue-14958.stderr | 12 +++++ .../overloaded/overloaded-index-in-field.rs | 2 +- .../overloaded-index-in-field.stderr | 15 ++++++ tests/ui/parser/parse-assoc-type-lt.rs | 2 +- tests/ui/parser/suggest-assoc-const.fixed | 1 + tests/ui/parser/suggest-assoc-const.rs | 1 + tests/ui/parser/suggest-assoc-const.stderr | 2 +- ...ing-semicolon-after-impl-trait-items.fixed | 1 + ...moving-semicolon-after-impl-trait-items.rs | 1 + ...ng-semicolon-after-impl-trait-items.stderr | 2 +- tests/ui/pattern/issue-22546.rs | 2 +- tests/ui/pattern/issue-22546.stderr | 10 ++++ .../sealed-traits/re-exported-trait.fixed | 1 + .../sealed-traits/re-exported-trait.rs | 1 + .../sealed-traits/re-exported-trait.stderr | 4 +- ...est-fix-invalid-top-level-macro-attr.fixed | 1 + ...uggest-fix-invalid-top-level-macro-attr.rs | 1 + ...st-fix-invalid-top-level-macro-attr.stderr | 1 + .../regions-no-variance-from-fn-generics.rs | 2 +- ...lid-unused-qualifications-suggestion.fixed | 1 + ...nvalid-unused-qualifications-suggestion.rs | 1 + ...id-unused-qualifications-suggestion.stderr | 6 +-- ...al-self-impl-for-unsafe-obj.current.stderr | 15 ++++++ ...anual-self-impl-for-unsafe-obj.next.stderr | 15 ++++++ .../manual-self-impl-for-unsafe-obj.rs | 2 +- tests/ui/rust-2018/issue-51008-1.rs | 2 +- tests/ui/rust-2018/issue-51008.rs | 2 +- tests/ui/sized/coinductive-2.rs | 2 +- tests/ui/sized/coinductive-2.stderr | 10 ++++ .../ui/specialization/assoc-ty-graph-cycle.rs | 2 +- .../defaultimpl/out-of-order.rs | 2 +- .../defaultimpl/overlap-projection.rs | 2 +- .../specialization-out-of-order.rs | 2 +- .../specialization-overlap-projection.rs | 2 +- .../specialization-supertraits.rs | 2 +- tests/ui/statics/static-impl.rs | 2 +- tests/ui/statics/static-impl.stderr | 13 +++++ tests/ui/stdlib-unit-tests/raw-fat-ptr.rs | 2 +- tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr | 12 +++++ .../ui/structs-enums/enum-null-pointer-opt.rs | 2 +- .../enum-null-pointer-opt.stderr | 12 +++++ tests/ui/suggestions/bound-suggestions.fixed | 5 ++ tests/ui/suggestions/bound-suggestions.rs | 5 ++ tests/ui/suggestions/bound-suggestions.stderr | 10 ++-- tests/ui/suggestions/constrain-trait.fixed | 1 + tests/ui/suggestions/constrain-trait.rs | 1 + tests/ui/suggestions/constrain-trait.stderr | 4 +- .../lifetimes/type-param-bound-scope.fixed | 1 + .../lifetimes/type-param-bound-scope.rs | 1 + .../lifetimes/type-param-bound-scope.stderr | 10 ++-- .../missing-bound-in-manual-copy-impl-2.fixed | 1 + .../missing-bound-in-manual-copy-impl-2.rs | 1 + ...missing-bound-in-manual-copy-impl-2.stderr | 4 +- .../missing-bound-in-manual-copy-impl.fixed | 1 + .../missing-bound-in-manual-copy-impl.rs | 1 + .../missing-bound-in-manual-copy-impl.stderr | 2 +- tests/ui/suggestions/missing-trait-item.fixed | 1 + tests/ui/suggestions/missing-trait-item.rs | 1 + .../ui/suggestions/missing-trait-item.stderr | 4 +- .../ui/threads-sendsync/sync-send-atomics.rs | 2 +- tests/ui/traits/alias/bounds.rs | 2 +- tests/ui/traits/alias/bounds.stderr | 10 ++++ tests/ui/traits/alias/syntax.rs | 2 +- .../bound/impl-comparison-duplicates.rs | 2 +- tests/ui/traits/bound/recursion.rs | 2 +- tests/ui/traits/composition-trivial.rs | 2 +- tests/ui/traits/cycle-generic-bound.rs | 2 +- .../ui/traits/default-method/bound-subst4.rs | 2 +- .../traits/default-method/bound-subst4.stderr | 13 +++++ tests/ui/traits/default-method/mut.rs | 2 +- .../traits/impl-inherent-prefer-over-trait.rs | 2 +- .../impl-inherent-prefer-over-trait.stderr | 12 +++++ .../traits/impl-object-overlap-issue-23853.rs | 2 +- .../impl-object-overlap-issue-23853.stderr | 12 +++++ tests/ui/traits/impl.rs | 2 +- tests/ui/traits/impl.stderr | 12 +++++ tests/ui/traits/issue-38033.rs | 2 +- tests/ui/traits/issue-38033.stderr | 13 +++++ tests/ui/traits/issue-56488.rs | 2 +- tests/ui/traits/issue-59029-2.rs | 2 +- tests/ui/traits/issue-6128.rs | 2 +- tests/ui/traits/issue-6128.stderr | 14 ++++++ ...ispatch-conditional-impl-not-considered.rs | 2 +- ...tch-conditional-impl-not-considered.stderr | 10 ++++ .../multidispatch-infer-convert-target.rs | 2 +- .../multidispatch-infer-convert-target.stderr | 12 +++++ .../negative-specializes-negative.rs | 2 +- tests/ui/traits/trait-upcasting/lifetime.rs | 4 +- .../ui/traits/trait-upcasting/lifetime.stderr | 25 ++++++++++ .../ui/traits/trait-upcasting/replace-vptr.rs | 4 +- .../trait-upcasting/replace-vptr.stderr | 20 ++++++++ tests/ui/traits/use-before-def.rs | 2 +- tests/ui/traits/wf-object/reverse-order.rs | 2 +- tests/ui/trivial_casts-rpass.rs | 2 +- tests/ui/trivial_casts-rpass.stderr | 12 +++++ tests/ui/type-alias-impl-trait/issue-58887.rs | 2 +- ...use-inherent-impl-ampersand-rust2015.fixed | 1 + ...clause-inherent-impl-ampersand-rust2015.rs | 1 + ...se-inherent-impl-ampersand-rust2015.stderr | 2 +- ...use-inherent-impl-ampersand-rust2018.fixed | 1 + ...clause-inherent-impl-ampersand-rust2018.rs | 1 + ...se-inherent-impl-ampersand-rust2018.stderr | 2 +- .../where-clause-trait-impl-region-2015.fixed | 1 + .../where-clause-trait-impl-region-2015.rs | 1 + ...where-clause-trait-impl-region-2015.stderr | 2 +- .../where-clause-trait-impl-region-2018.fixed | 2 + .../where-clause-trait-impl-region-2018.rs | 2 + ...where-clause-trait-impl-region-2018.stderr | 2 +- tests/ui/where-clauses/issue-50825-1.rs | 2 +- .../where-clause-bounds-inconsistency.rs | 2 +- .../where-clause-early-bound-lifetimes.rs | 2 +- .../where-clause-early-bound-lifetimes.stderr | 12 +++++ .../where-clause-method-substituion-rpass.rs | 2 +- ...ere-clause-method-substituion-rpass.stderr | 12 +++++ ...-clause-placement-assoc-type-in-impl.fixed | 2 + ...ere-clause-placement-assoc-type-in-impl.rs | 2 + ...clause-placement-assoc-type-in-impl.stderr | 6 +-- ...clause-placement-assoc-type-in-trait.fixed | 1 + ...re-clause-placement-assoc-type-in-trait.rs | 1 + ...lause-placement-assoc-type-in-trait.stderr | 4 +- 276 files changed, 1049 insertions(+), 234 deletions(-) create mode 100644 tests/ui/associated-consts/associated-const-type-parameters.stderr create mode 100644 tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr create mode 100644 tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr create mode 100644 tests/ui/associated-type-bounds/rpit.stderr create mode 100644 tests/ui/associated-types/associated-types-issue-20220.stderr create mode 100644 tests/ui/associated-types/associated-types-nested-projections.stderr create mode 100644 tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr create mode 100644 tests/ui/auto-traits/auto-traits.stderr create mode 100644 tests/ui/cast/cast-rfc0401-vtable-kinds.stderr create mode 100644 tests/ui/cast/fat-ptr-cast-rpass.stderr create mode 100644 tests/ui/coercion/issue-14589.stderr create mode 100644 tests/ui/const-generics/dyn-supertraits.stderr create mode 100644 tests/ui/const-generics/issues/issue-69654-run-pass.stderr create mode 100644 tests/ui/consts/const-block-item.stderr create mode 100644 tests/ui/drop/drop-struct-as-object.stderr create mode 100644 tests/ui/dynamically-sized-types/dst-coercions.stderr create mode 100644 tests/ui/empty-type-parameter-list.stderr create mode 100644 tests/ui/extern/no-mangle-associated-fn.stderr create mode 100644 tests/ui/impl-trait/example-st.stderr create mode 100644 tests/ui/impl-trait/type-alias-generic-param.stderr create mode 100644 tests/ui/issues/issue-14399.stderr create mode 100644 tests/ui/issues/issue-15858.stderr create mode 100644 tests/ui/issues/issue-17351.stderr create mode 100644 tests/ui/issues/issue-20055-box-trait.stderr create mode 100644 tests/ui/issues/issue-23485.stderr create mode 100644 tests/ui/issues/issue-2989.stderr create mode 100644 tests/ui/issues/issue-34503.stderr create mode 100644 tests/ui/issues/issue-3563-3.stderr create mode 100644 tests/ui/issues/issue-7575.stderr create mode 100644 tests/ui/issues/issue-7911.stderr create mode 100644 tests/ui/issues/issue-8248.stderr create mode 100644 tests/ui/issues/issue-9951.stderr create mode 100644 tests/ui/methods/method-recursive-blanket-impl.stderr create mode 100644 tests/ui/methods/method-two-trait-defer-resolution-2.stderr create mode 100644 tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr create mode 100644 tests/ui/mir/mir_raw_fat_ptr.stderr create mode 100644 tests/ui/moves/issue-22536-copy-mustnt-zero.stderr create mode 100644 tests/ui/overloaded/issue-14958.stderr create mode 100644 tests/ui/overloaded/overloaded-index-in-field.stderr create mode 100644 tests/ui/pattern/issue-22546.stderr create mode 100644 tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr create mode 100644 tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr create mode 100644 tests/ui/sized/coinductive-2.stderr create mode 100644 tests/ui/statics/static-impl.stderr create mode 100644 tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr create mode 100644 tests/ui/structs-enums/enum-null-pointer-opt.stderr create mode 100644 tests/ui/traits/alias/bounds.stderr create mode 100644 tests/ui/traits/default-method/bound-subst4.stderr create mode 100644 tests/ui/traits/impl-inherent-prefer-over-trait.stderr create mode 100644 tests/ui/traits/impl-object-overlap-issue-23853.stderr create mode 100644 tests/ui/traits/impl.stderr create mode 100644 tests/ui/traits/issue-38033.stderr create mode 100644 tests/ui/traits/issue-6128.stderr create mode 100644 tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr create mode 100644 tests/ui/traits/multidispatch-infer-convert-target.stderr create mode 100644 tests/ui/traits/trait-upcasting/lifetime.stderr create mode 100644 tests/ui/traits/trait-upcasting/replace-vptr.stderr create mode 100644 tests/ui/trivial_casts-rpass.stderr create mode 100644 tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr create mode 100644 tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 5788d11ed43ca..51f8aa04e8a7f 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -1,5 +1,7 @@ use super::*; +use rustc_data_structures::sync::FreezeLock; + fn init_source_map() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string()); @@ -263,53 +265,6 @@ fn t10() { ); } -/// Returns the span corresponding to the `n`th occurrence of `substring` in `source_text`. -trait SourceMapExtension { - fn span_substr( - &self, - file: &Lrc, - source_text: &str, - substring: &str, - n: usize, - ) -> Span; -} - -impl SourceMapExtension for SourceMap { - fn span_substr( - &self, - file: &Lrc, - source_text: &str, - substring: &str, - n: usize, - ) -> Span { - eprintln!( - "span_substr(file={:?}/{:?}, substring={:?}, n={})", - file.name, file.start_pos, substring, n - ); - let mut i = 0; - let mut hi = 0; - loop { - let offset = source_text[hi..].find(substring).unwrap_or_else(|| { - panic!( - "source_text `{}` does not have {} occurrences of `{}`, only {}", - source_text, n, substring, i - ); - }); - let lo = hi + offset; - hi = lo + substring.len(); - if i == n { - let span = Span::with_root_ctxt( - BytePos(lo as u32 + file.start_pos.0), - BytePos(hi as u32 + file.start_pos.0), - ); - assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring); - return span; - } - i += 1; - } - } -} - // Takes a unix-style path and returns a platform specific path. fn path(p: &str) -> PathBuf { path_str(p).into() diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs index eb886def164ac..09994fbcbdb78 100644 --- a/library/core/tests/macros.rs +++ b/library/core/tests/macros.rs @@ -1,3 +1,4 @@ +#[allow(dead_code)] trait Trait { fn blah(&self); } diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 851832a377cf8..01f83ecb41452 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -59,12 +59,14 @@ cfg_if::cfg_if! { /// A trait for viewing representations from std types #[doc(hidden)] +#[allow(dead_code)] // not used on all platforms pub trait AsInner { fn as_inner(&self) -> &Inner; } /// A trait for viewing representations from std types #[doc(hidden)] +#[allow(dead_code)] // not used on all platforms pub trait AsInnerMut { fn as_inner_mut(&mut self) -> &mut Inner; } diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs index 0e7c3dbcc040f..13f913454dcdf 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs @@ -1,4 +1,5 @@ trait T1 { + #[allow(dead_code)] fn method1(self: Box); } trait T2 { diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs index 648ac07c43ec9..982f33b0a3102 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs @@ -2,30 +2,36 @@ #![allow(incomplete_features)] trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + #[allow(dead_code)] fn a(&self) -> i32 { 10 } + #[allow(dead_code)] fn z(&self) -> i32 { 11 } + #[allow(dead_code)] fn y(&self) -> i32 { 12 } } trait Bar: Foo { + #[allow(dead_code)] fn b(&self) -> i32 { 20 } + #[allow(dead_code)] fn w(&self) -> i32 { 21 } } trait Baz: Bar { + #[allow(dead_code)] fn c(&self) -> i32 { 30 } diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs index ccf96b9967202..2491bda0917d3 100644 --- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -9,6 +9,7 @@ trait Foo { } } +#[allow(dead_code)] trait Bar { fn bar(&self) { println!("Bar!"); diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index 8432012a9ba52..529b9c471d426 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -383,14 +383,17 @@ fn struct_() { fn replace_vptr() { trait A { + #[allow(dead_code)] fn foo_a(&self); } trait B { + #[allow(dead_code)] fn foo_b(&self); } trait C: A + B { + #[allow(dead_code)] fn foo_c(&self); } diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index 4c3be6b3559ae..e10ccc277f6f1 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -11,6 +11,7 @@ use std::sync::atomic::Ordering::*; use std::sync::atomic::{fence, AtomicUsize}; use std::thread::spawn; +#[allow(dead_code)] #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 094694274269f..e7b1ccf6a0299 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -13,8 +13,9 @@ use std::path::{Path, PathBuf}; // desirable, because large numbers of files are unwieldy in general. See issue // #73494. const ENTRY_LIMIT: usize = 900; -const ISSUES_ENTRY_LIMIT: usize = 1807; -const ROOT_ENTRY_LIMIT: usize = 868; +// FIXME: The following limits should be reduced eventually. +const ISSUES_ENTRY_LIMIT: usize = 1819; +const ROOT_ENTRY_LIMIT: usize = 870; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs index e78226d4083a4..41edab7f8793a 100644 --- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs @@ -26,7 +26,9 @@ fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] //~ MONO_ITEM fn as Trait>::foo //~ MONO_ITEM fn as Trait>::bar - let _ = &s1 as &Trait; + let r1 = &s1 as &Trait; + r1.foo(); + r1.bar(); let s1 = Struct { _a: 0u64 }; //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] diff --git a/tests/codegen-units/item-collection/trait-method-default-impl.rs b/tests/codegen-units/item-collection/trait-method-default-impl.rs index d953582cce9b6..c8a4552b11ac6 100644 --- a/tests/codegen-units/item-collection/trait-method-default-impl.rs +++ b/tests/codegen-units/item-collection/trait-method-default-impl.rs @@ -57,5 +57,8 @@ fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn >::bar::<()> 0u32.bar(0i16, ()); + 0i8.foo(); + 0i32.foo(); + 0 } diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs index 34f52ce4e619e..f578b00f27668 100644 --- a/tests/codegen-units/item-collection/unsizing.rs +++ b/tests/codegen-units/item-collection/unsizing.rs @@ -75,5 +75,7 @@ fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn ::foo let _wrapper_sized = wrapper_sized as Wrapper; + false.foo(); + 0 } diff --git a/tests/ui-fulldeps/rustc_encodable_hygiene.rs b/tests/ui-fulldeps/rustc_encodable_hygiene.rs index bec7930d4622f..36c684a131e65 100644 --- a/tests/ui-fulldeps/rustc_encodable_hygiene.rs +++ b/tests/ui-fulldeps/rustc_encodable_hygiene.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(rustc_private)] diff --git a/tests/ui/anon-params/anon-params-deprecated.fixed b/tests/ui/anon-params/anon-params-deprecated.fixed index c09e20770846e..8ec1d41a70985 100644 --- a/tests/ui/anon-params/anon-params-deprecated.fixed +++ b/tests/ui/anon-params/anon-params-deprecated.fixed @@ -5,6 +5,7 @@ // edition:2015 // run-rustfix +#[allow(dead_code)] trait T { fn foo(_: i32); //~ WARNING anonymous parameters are deprecated //~| WARNING this is accepted in the current edition diff --git a/tests/ui/anon-params/anon-params-deprecated.rs b/tests/ui/anon-params/anon-params-deprecated.rs index 6f7385da040c5..108ba60a02f58 100644 --- a/tests/ui/anon-params/anon-params-deprecated.rs +++ b/tests/ui/anon-params/anon-params-deprecated.rs @@ -5,6 +5,7 @@ // edition:2015 // run-rustfix +#[allow(dead_code)] trait T { fn foo(i32); //~ WARNING anonymous parameters are deprecated //~| WARNING this is accepted in the current edition diff --git a/tests/ui/anon-params/anon-params-deprecated.stderr b/tests/ui/anon-params/anon-params-deprecated.stderr index 691e2c7951249..541cb004b5b2c 100644 --- a/tests/ui/anon-params/anon-params-deprecated.stderr +++ b/tests/ui/anon-params/anon-params-deprecated.stderr @@ -1,5 +1,5 @@ warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/anon-params-deprecated.rs:9:12 + --> $DIR/anon-params-deprecated.rs:10:12 | LL | fn foo(i32); | ^^^ help: try naming the parameter or explicitly ignoring it: `_: i32` @@ -13,7 +13,7 @@ LL | #![warn(anonymous_parameters)] | ^^^^^^^^^^^^^^^^^^^^ warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/anon-params-deprecated.rs:12:30 + --> $DIR/anon-params-deprecated.rs:13:30 | LL | fn bar_with_default_impl(String, String) {} | ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String` @@ -22,7 +22,7 @@ LL | fn bar_with_default_impl(String, String) {} = note: for more information, see issue #41686 warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/anon-params-deprecated.rs:12:38 + --> $DIR/anon-params-deprecated.rs:13:38 | LL | fn bar_with_default_impl(String, String) {} | ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String` diff --git a/tests/ui/associated-consts/associated-const-outer-ty-refs.rs b/tests/ui/associated-consts/associated-const-outer-ty-refs.rs index f32ca0cccfc91..d5e9a2bde0060 100644 --- a/tests/ui/associated-consts/associated-const-outer-ty-refs.rs +++ b/tests/ui/associated-consts/associated-const-outer-ty-refs.rs @@ -1,4 +1,5 @@ -// run-pass +// check-pass + trait Lattice { const BOTTOM: Self; } diff --git a/tests/ui/associated-consts/associated-const-type-parameters.rs b/tests/ui/associated-consts/associated-const-type-parameters.rs index b62d47458be5e..a233b09ff89c6 100644 --- a/tests/ui/associated-consts/associated-const-type-parameters.rs +++ b/tests/ui/associated-consts/associated-const-type-parameters.rs @@ -27,7 +27,7 @@ fn sub() -> i32 { A::X - B::X } -trait Bar: Foo { +trait Bar: Foo { //~ WARN trait `Bar` is never used const Y: i32 = Self::X; } diff --git a/tests/ui/associated-consts/associated-const-type-parameters.stderr b/tests/ui/associated-consts/associated-const-type-parameters.stderr new file mode 100644 index 0000000000000..6ee2a5de1b6ad --- /dev/null +++ b/tests/ui/associated-consts/associated-const-type-parameters.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/associated-const-type-parameters.rs:30:7 + | +LL | trait Bar: Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs b/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs index a3f4717791abd..079c44b3a598d 100644 --- a/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs +++ b/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs @@ -5,7 +5,7 @@ use std::ops::Add; trait Tr1 { type As1; fn mk(&self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used fn assert_copy(x: T) { let _x = x; let _x = x; } fn assert_static(_: T) {} diff --git a/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr b/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr new file mode 100644 index 0000000000000..2e26a434f5d34 --- /dev/null +++ b/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr @@ -0,0 +1,12 @@ +warning: method `tr2` is never used + --> $DIR/dyn-impl-trait-type.rs:8:20 + | +LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs b/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs index 52199124ea3b5..49e5e72f225e2 100644 --- a/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs +++ b/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs @@ -7,7 +7,7 @@ use std::ops::Add; trait Tr1 { type As1; fn mk(&self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used fn assert_copy(x: T) { let _x = x; let _x = x; } fn assert_static(_: T) {} diff --git a/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr b/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr new file mode 100644 index 0000000000000..9eddbe462847d --- /dev/null +++ b/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr @@ -0,0 +1,12 @@ +warning: method `tr2` is never used + --> $DIR/dyn-rpit-and-let.rs:10:20 + | +LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/rpit.rs b/tests/ui/associated-type-bounds/rpit.rs index 59c7733fbe4ba..557e63b5f71fa 100644 --- a/tests/ui/associated-type-bounds/rpit.rs +++ b/tests/ui/associated-type-bounds/rpit.rs @@ -5,7 +5,7 @@ use std::ops::Add; trait Tr1 { type As1; fn mk(self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used fn assert_copy(x: T) { let _x = x; let _x = x; } fn assert_static(_: T) {} diff --git a/tests/ui/associated-type-bounds/rpit.stderr b/tests/ui/associated-type-bounds/rpit.stderr new file mode 100644 index 0000000000000..76bd75bd2cab3 --- /dev/null +++ b/tests/ui/associated-type-bounds/rpit.stderr @@ -0,0 +1,12 @@ +warning: method `tr2` is never used + --> $DIR/rpit.rs:8:20 + | +LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed index b9f26a40219b5..128c7dfdda2ed 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait O { type M; } diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs index abff6af73e24b..6b6478419b4c0 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait O { type M; } diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr index 7ca9aff432279..21bc37bb3ea2d 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21 + --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:13:21 | LL | const N: C::M = 4u8; | ^^^ expected associated type, found `u8` diff --git a/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs b/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs index 93a44c01ce053..60088e443f300 100644 --- a/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs +++ b/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(dead_code)] #![feature(associated_type_bounds)] #![feature(type_alias_impl_trait)] diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed index 80bbef17469db..adfba994f32dc 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #![allow(unused_variables)] trait Get { diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.rs b/tests/ui/associated-types/associated-types-for-unimpl-trait.rs index 0f6cea8e69fcf..50478171d869a 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.rs +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #![allow(unused_variables)] trait Get { diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr index 17941b6bf1eef..27014fa53d8a2 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-for-unimpl-trait.rs:10:40 + --> $DIR/associated-types-for-unimpl-trait.rs:11:40 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` diff --git a/tests/ui/associated-types/associated-types-in-bound-type-arg.rs b/tests/ui/associated-types/associated-types-in-bound-type-arg.rs index 88bb5fe0afeab..05e66a168d9cf 100644 --- a/tests/ui/associated-types/associated-types-in-bound-type-arg.rs +++ b/tests/ui/associated-types/associated-types-in-bound-type-arg.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test the case where we resolve `C::Result` and the trait bound // itself includes a `Self::Item` shorthand. // diff --git a/tests/ui/associated-types/associated-types-issue-20220.rs b/tests/ui/associated-types/associated-types-issue-20220.rs index 19fa7a6085a56..89efce198340f 100644 --- a/tests/ui/associated-types/associated-types-issue-20220.rs +++ b/tests/ui/associated-types/associated-types-issue-20220.rs @@ -4,7 +4,7 @@ use std::vec; -trait IntoIteratorX { +trait IntoIteratorX { //~ WARN trait `IntoIteratorX` is never used type Item; type IntoIter: Iterator; diff --git a/tests/ui/associated-types/associated-types-issue-20220.stderr b/tests/ui/associated-types/associated-types-issue-20220.stderr new file mode 100644 index 0000000000000..c682f46e1409b --- /dev/null +++ b/tests/ui/associated-types/associated-types-issue-20220.stderr @@ -0,0 +1,10 @@ +warning: trait `IntoIteratorX` is never used + --> $DIR/associated-types-issue-20220.rs:7:7 + | +LL | trait IntoIteratorX { + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-types/associated-types-issue-20371.rs b/tests/ui/associated-types/associated-types-issue-20371.rs index ae8a8767d2746..cbec83d45b29d 100644 --- a/tests/ui/associated-types/associated-types-issue-20371.rs +++ b/tests/ui/associated-types/associated-types-issue-20371.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that we are able to have an impl that defines an associated type // before the actual trait. diff --git a/tests/ui/associated-types/associated-types-nested-projections.rs b/tests/ui/associated-types/associated-types-nested-projections.rs index 76ba7496250cc..440f35c8bdef4 100644 --- a/tests/ui/associated-types/associated-types-nested-projections.rs +++ b/tests/ui/associated-types/associated-types-nested-projections.rs @@ -13,7 +13,7 @@ impl<'a> Bound for &'a i32 {} trait IntoIterator { type Iter: Iterator; - fn into_iter(self) -> Self::Iter; + fn into_iter(self) -> Self::Iter; //~ WARN method `into_iter` is never used } impl<'a, T> IntoIterator for &'a [T; 3] { diff --git a/tests/ui/associated-types/associated-types-nested-projections.stderr b/tests/ui/associated-types/associated-types-nested-projections.stderr new file mode 100644 index 0000000000000..97d5a7585736c --- /dev/null +++ b/tests/ui/associated-types/associated-types-nested-projections.stderr @@ -0,0 +1,13 @@ +warning: method `into_iter` is never used + --> $DIR/associated-types-nested-projections.rs:16:8 + | +LL | trait IntoIterator { + | ------------ method in this trait +... +LL | fn into_iter(self) -> Self::Iter; + | ^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs index e09aa3663c6e5..6612598b1b8b4 100644 --- a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs +++ b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Test that we normalize associated types that appear in bounds; if // we didn't, the call to `self.split2()` fails to type check. diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs index dcfae0f37e1da..df0a82ee7ceb0 100644 --- a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs +++ b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Test that we normalize associated types that appear in bounds; if // we didn't, the call to `self.split2()` fails to type check. diff --git a/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs b/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs index 107e6b4ce0ca0..e99d0112ec4fd 100644 --- a/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs +++ b/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Test that we correctly handle projection bounds appearing in the // supertrait list (and in conjunction with overloaded operators). In diff --git a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs index a59c327be2101..e172c6e5611d3 100644 --- a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs +++ b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs @@ -6,7 +6,7 @@ trait Int { type T; - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } trait NonZero diff --git a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr new file mode 100644 index 0000000000000..c26ed79a026e4 --- /dev/null +++ b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr @@ -0,0 +1,13 @@ +warning: method `dummy` is never used + --> $DIR/associated-types-projection-from-known-type-in-impl.rs:9:8 + | +LL | trait Int + | --- method in this trait +... +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed index 9bc308465ebdd..01f49d52ee212 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed @@ -2,6 +2,7 @@ // Check that we get an error when you use `::Value` in // the trait definition even if there is no default method. +#![allow(dead_code)] trait Get { type Value; } diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs index 549fc8fc618e0..7068a754a12c1 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs @@ -2,6 +2,7 @@ // Check that we get an error when you use `::Value` in // the trait definition even if there is no default method. +#![allow(dead_code)] trait Get { type Value; } diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index 64a88525af8d4..79200dc3acc24 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40 + --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:11:40 | LL | fn okay(&self, foo: U, bar: ::Value); | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs index 3b8c8c019e50b..a2d6c9ff5a45b 100644 --- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs +++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Check that we do not get an error when you use `::Value` in // the trait definition if there is no default method and for every impl, // `Self` does implement `Get`. diff --git a/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs b/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs index 3c830d37060ab..1768fd1687b4e 100644 --- a/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs +++ b/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/associated-types/associated-types-resolve-lifetime.rs b/tests/ui/associated-types/associated-types-resolve-lifetime.rs index 52f2324d72ab7..563d0c1182211 100644 --- a/tests/ui/associated-types/associated-types-resolve-lifetime.rs +++ b/tests/ui/associated-types/associated-types-resolve-lifetime.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Get { diff --git a/tests/ui/associated-types/impl-wf-cycle-5.fixed b/tests/ui/associated-types/impl-wf-cycle-5.fixed index bff6ca90975d2..2b8f1e0d865ee 100644 --- a/tests/ui/associated-types/impl-wf-cycle-5.fixed +++ b/tests/ui/associated-types/impl-wf-cycle-5.fixed @@ -1,9 +1,11 @@ // run-rustfix +#[allow(dead_code)] trait Baz {} impl Baz for () {} impl Baz for (T,) {} +#[allow(dead_code)] trait Fiz {} impl Fiz for bool {} diff --git a/tests/ui/associated-types/impl-wf-cycle-5.rs b/tests/ui/associated-types/impl-wf-cycle-5.rs index a822e1fb0081b..e6de292ca5c91 100644 --- a/tests/ui/associated-types/impl-wf-cycle-5.rs +++ b/tests/ui/associated-types/impl-wf-cycle-5.rs @@ -1,9 +1,11 @@ // run-rustfix +#[allow(dead_code)] trait Baz {} impl Baz for () {} impl Baz for (T,) {} +#[allow(dead_code)] trait Fiz {} impl Fiz for bool {} diff --git a/tests/ui/associated-types/impl-wf-cycle-5.stderr b/tests/ui/associated-types/impl-wf-cycle-5.stderr index 284a50bb9a3be..61edf18b43d97 100644 --- a/tests/ui/associated-types/impl-wf-cycle-5.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-5.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` - --> $DIR/impl-wf-cycle-5.rs:20:1 + --> $DIR/impl-wf-cycle-5.rs:22:1 | LL | / impl Grault for (T,) LL | | @@ -12,7 +12,7 @@ LL | type A = (); | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` - --> $DIR/impl-wf-cycle-5.rs:20:9 + --> $DIR/impl-wf-cycle-5.rs:22:9 | LL | impl Grault for (T,) | ^^^^^^ ^^^^ diff --git a/tests/ui/associated-types/impl-wf-cycle-6.fixed b/tests/ui/associated-types/impl-wf-cycle-6.fixed index 73ed64f7ce381..5ddf1faefe088 100644 --- a/tests/ui/associated-types/impl-wf-cycle-6.fixed +++ b/tests/ui/associated-types/impl-wf-cycle-6.fixed @@ -1,9 +1,11 @@ // run-rustfix +#[allow(dead_code)] trait Baz {} impl Baz for () {} impl Baz for (T,) {} +#[allow(dead_code)] trait Fiz {} impl Fiz for bool {} diff --git a/tests/ui/associated-types/impl-wf-cycle-6.rs b/tests/ui/associated-types/impl-wf-cycle-6.rs index 20d635cac5d6f..28f6deb77ce1f 100644 --- a/tests/ui/associated-types/impl-wf-cycle-6.rs +++ b/tests/ui/associated-types/impl-wf-cycle-6.rs @@ -1,9 +1,11 @@ // run-rustfix +#[allow(dead_code)] trait Baz {} impl Baz for () {} impl Baz for (T,) {} +#[allow(dead_code)] trait Fiz {} impl Fiz for bool {} diff --git a/tests/ui/associated-types/impl-wf-cycle-6.stderr b/tests/ui/associated-types/impl-wf-cycle-6.stderr index c9b5d8060be68..1c7495033183f 100644 --- a/tests/ui/associated-types/impl-wf-cycle-6.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-6.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` - --> $DIR/impl-wf-cycle-6.rs:20:1 + --> $DIR/impl-wf-cycle-6.rs:22:1 | LL | / impl Grault for (T,) LL | | @@ -11,7 +11,7 @@ LL | type A = (); | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` - --> $DIR/impl-wf-cycle-6.rs:20:17 + --> $DIR/impl-wf-cycle-6.rs:22:17 | LL | impl Grault for (T,) | ^^^^^^ ^^^^ diff --git a/tests/ui/auto-traits/auto-trait-validation.fixed b/tests/ui/auto-traits/auto-trait-validation.fixed index da878ac6222bb..e37fed9faabae 100644 --- a/tests/ui/auto-traits/auto-trait-validation.fixed +++ b/tests/ui/auto-traits/auto-trait-validation.fixed @@ -1,4 +1,5 @@ #![feature(auto_traits)] +#![allow(dead_code)] // run-rustfix diff --git a/tests/ui/auto-traits/auto-trait-validation.rs b/tests/ui/auto-traits/auto-trait-validation.rs index d43055e270bd5..e209aa1322081 100644 --- a/tests/ui/auto-traits/auto-trait-validation.rs +++ b/tests/ui/auto-traits/auto-trait-validation.rs @@ -1,4 +1,5 @@ #![feature(auto_traits)] +#![allow(dead_code)] // run-rustfix diff --git a/tests/ui/auto-traits/auto-trait-validation.stderr b/tests/ui/auto-traits/auto-trait-validation.stderr index 89b63d23d4c8e..a6e5ac54869d2 100644 --- a/tests/ui/auto-traits/auto-trait-validation.stderr +++ b/tests/ui/auto-traits/auto-trait-validation.stderr @@ -1,5 +1,5 @@ error[E0567]: auto traits cannot have generic parameters - --> $DIR/auto-trait-validation.rs:5:19 + --> $DIR/auto-trait-validation.rs:6:19 | LL | auto trait Generic {} | -------^^^ help: remove the parameters @@ -7,7 +7,7 @@ LL | auto trait Generic {} | auto trait cannot have generic parameters error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/auto-trait-validation.rs:7:17 + --> $DIR/auto-trait-validation.rs:8:17 | LL | auto trait Bound : Copy {} | -----^^^^^^^ help: remove the super traits or lifetime bounds @@ -15,7 +15,7 @@ LL | auto trait Bound : Copy {} | auto traits cannot have super traits or lifetime bounds error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/auto-trait-validation.rs:9:25 + --> $DIR/auto-trait-validation.rs:10:25 | LL | auto trait LifetimeBound : 'static {} | -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds @@ -23,7 +23,7 @@ LL | auto trait LifetimeBound : 'static {} | auto traits cannot have super traits or lifetime bounds error[E0380]: auto traits cannot have associated items - --> $DIR/auto-trait-validation.rs:11:25 + --> $DIR/auto-trait-validation.rs:12:25 | LL | auto trait MyTrait { fn foo() {} } | ------- ---^^^----- diff --git a/tests/ui/auto-traits/auto-traits.rs b/tests/ui/auto-traits/auto-traits.rs index 6d8e1a52ec129..1e0fbcc1fdf63 100644 --- a/tests/ui/auto-traits/auto-traits.rs +++ b/tests/ui/auto-traits/auto-traits.rs @@ -19,8 +19,8 @@ fn take_auto_unsafe(_: T) {} fn main() { // Parse inside functions. - auto trait AutoInner {} - unsafe auto trait AutoUnsafeInner {} + auto trait AutoInner {} //~ WARN trait `AutoInner` is never used + unsafe auto trait AutoUnsafeInner {} //~ WARN trait `AutoUnsafeInner` is never used take_auto(0); take_auto(AutoBool(true)); diff --git a/tests/ui/auto-traits/auto-traits.stderr b/tests/ui/auto-traits/auto-traits.stderr new file mode 100644 index 0000000000000..34be8d3f67b8d --- /dev/null +++ b/tests/ui/auto-traits/auto-traits.stderr @@ -0,0 +1,16 @@ +warning: trait `AutoInner` is never used + --> $DIR/auto-traits.rs:22:16 + | +LL | auto trait AutoInner {} + | ^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: trait `AutoUnsafeInner` is never used + --> $DIR/auto-traits.rs:23:23 + | +LL | unsafe auto trait AutoUnsafeInner {} + | ^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs index 2edc52c6f55f0..7e8820cb2c65d 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs +++ b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_imports)] diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs b/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs index 8d24771578444..50914b1de53f2 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs +++ b/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Simple test case of implementing a trait with super-builtin-kinds. // pretty-expanded FIXME #23616 diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs b/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs index f999dfff786eb..0577acc572ad5 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs +++ b/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Tests correct implementation of traits with super-builtin-kinds // using a bounded type parameter. diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs index 249481467e646..be6a6bb8b1755 100644 --- a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs +++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs @@ -8,7 +8,7 @@ trait Foo { fn foo(&self, _: T) -> u32 { 42 } } -trait Bar { +trait Bar { //~ WARN trait `Bar` is never used fn bar(&self) { println!("Bar!"); } } diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr new file mode 100644 index 0000000000000..952687e98d0ef --- /dev/null +++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/cast-rfc0401-vtable-kinds.rs:11:7 + | +LL | trait Bar { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/cast/fat-ptr-cast-rpass.rs b/tests/ui/cast/fat-ptr-cast-rpass.rs index f5747eb8b9666..c79468cadddd9 100644 --- a/tests/ui/cast/fat-ptr-cast-rpass.rs +++ b/tests/ui/cast/fat-ptr-cast-rpass.rs @@ -3,7 +3,7 @@ #![feature(ptr_metadata)] trait Foo { - fn foo(&self) {} + fn foo(&self) {} //~ WARN method `foo` is never used } struct Bar; diff --git a/tests/ui/cast/fat-ptr-cast-rpass.stderr b/tests/ui/cast/fat-ptr-cast-rpass.stderr new file mode 100644 index 0000000000000..d01688e0cc3b0 --- /dev/null +++ b/tests/ui/cast/fat-ptr-cast-rpass.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/fat-ptr-cast-rpass.rs:6:8 + | +LL | trait Foo { + | --- method in this trait +LL | fn foo(&self) {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/coercion/issue-14589.rs b/tests/ui/coercion/issue-14589.rs index f92385f8d7275..6f95b30be06ae 100644 --- a/tests/ui/coercion/issue-14589.rs +++ b/tests/ui/coercion/issue-14589.rs @@ -19,6 +19,6 @@ impl Test { fn send(&self, _: T) {} } -trait Foo { fn dummy(&self) { }} +trait Foo { fn dummy(&self) { }} //~ WARN method `dummy` is never used struct Output(#[allow(dead_code)] isize); impl Foo for Output {} diff --git a/tests/ui/coercion/issue-14589.stderr b/tests/ui/coercion/issue-14589.stderr new file mode 100644 index 0000000000000..37b7fce7462b3 --- /dev/null +++ b/tests/ui/coercion/issue-14589.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-14589.rs:22:16 + | +LL | trait Foo { fn dummy(&self) { }} + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/coherence/coherence-multidispatch-tuple.rs b/tests/ui/coherence/coherence-multidispatch-tuple.rs index fa1d4bbb49665..b04b2a296b5b4 100644 --- a/tests/ui/coherence/coherence-multidispatch-tuple.rs +++ b/tests/ui/coherence/coherence-multidispatch-tuple.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_imports)] // pretty-expanded FIXME #23616 diff --git a/tests/ui/const-generics/associated-type-bound.rs b/tests/ui/const-generics/associated-type-bound.rs index 3044736b47e05..0a57352c10da1 100644 --- a/tests/ui/const-generics/associated-type-bound.rs +++ b/tests/ui/const-generics/associated-type-bound.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass trait Bar {} trait Foo { diff --git a/tests/ui/const-generics/condition-in-trait-const-arg.rs b/tests/ui/const-generics/condition-in-trait-const-arg.rs index 6f85237cf0aaf..74a663a53ec6b 100644 --- a/tests/ui/const-generics/condition-in-trait-const-arg.rs +++ b/tests/ui/const-generics/condition-in-trait-const-arg.rs @@ -1,5 +1,5 @@ // Checks that `impl Trait<{anon_const}> for Type` evaluates successfully. -// run-pass +// check-pass // revisions: full min #![cfg_attr(full, feature(generic_const_exprs))] diff --git a/tests/ui/const-generics/dyn-supertraits.rs b/tests/ui/const-generics/dyn-supertraits.rs index 3dee326a186e9..bb4924529824b 100644 --- a/tests/ui/const-generics/dyn-supertraits.rs +++ b/tests/ui/const-generics/dyn-supertraits.rs @@ -4,7 +4,7 @@ trait Foo { fn myfun(&self) -> usize; } trait Bar : Foo {} -trait Baz: Foo<3> {} +trait Baz: Foo<3> {} //~ WARN trait `Baz` is never used struct FooType; struct BarType; @@ -23,10 +23,10 @@ impl Foo<3> for BazType { impl Baz for BazType {} trait Foz {} -trait Boz: Foo<3> + Foz {} +trait Boz: Foo<3> + Foz {} //~ WARN trait `Boz` is never used trait Bok: Foo + Foz {} -struct FozType; +struct FozType; //~ WARN struct `FozType` is never constructed struct BozType; struct BokType; diff --git a/tests/ui/const-generics/dyn-supertraits.stderr b/tests/ui/const-generics/dyn-supertraits.stderr new file mode 100644 index 0000000000000..38b67ef4403a1 --- /dev/null +++ b/tests/ui/const-generics/dyn-supertraits.stderr @@ -0,0 +1,22 @@ +warning: trait `Baz` is never used + --> $DIR/dyn-supertraits.rs:7:7 + | +LL | trait Baz: Foo<3> {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: trait `Boz` is never used + --> $DIR/dyn-supertraits.rs:26:7 + | +LL | trait Boz: Foo<3> + Foz {} + | ^^^ + +warning: struct `FozType` is never constructed + --> $DIR/dyn-supertraits.rs:29:8 + | +LL | struct FozType; + | ^^^^^^^ + +warning: 3 warnings emitted + diff --git a/tests/ui/const-generics/issues/issue-69654-run-pass.rs b/tests/ui/const-generics/issues/issue-69654-run-pass.rs index 63d7fde78ac8a..21d6270b1fafa 100644 --- a/tests/ui/const-generics/issues/issue-69654-run-pass.rs +++ b/tests/ui/const-generics/issues/issue-69654-run-pass.rs @@ -1,5 +1,5 @@ // run-pass -trait Bar {} +trait Bar {} //~ WARN trait `Bar` is never used impl Bar for [u8; 7] {} struct Foo {} diff --git a/tests/ui/const-generics/issues/issue-69654-run-pass.stderr b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr new file mode 100644 index 0000000000000..7b3cd4f375fd0 --- /dev/null +++ b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/issue-69654-run-pass.rs:2:7 + | +LL | trait Bar {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/const-block-item.rs b/tests/ui/consts/const-block-item.rs index cf0d4441d4a9b..a04f4db263bb2 100644 --- a/tests/ui/consts/const-block-item.rs +++ b/tests/ui/consts/const-block-item.rs @@ -2,7 +2,7 @@ #![allow(unused_imports)] mod foo { - pub trait Value { + pub trait Value { //~ WARN trait `Value` is never used fn value(&self) -> usize; } } diff --git a/tests/ui/consts/const-block-item.stderr b/tests/ui/consts/const-block-item.stderr new file mode 100644 index 0000000000000..04658742b56ce --- /dev/null +++ b/tests/ui/consts/const-block-item.stderr @@ -0,0 +1,10 @@ +warning: trait `Value` is never used + --> $DIR/const-block-item.rs:5:15 + | +LL | pub trait Value { + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/underscore_const_names.rs b/tests/ui/consts/underscore_const_names.rs index d0e625bf1997a..e2ae5a9d53aac 100644 --- a/tests/ui/consts/underscore_const_names.rs +++ b/tests/ui/consts/underscore_const_names.rs @@ -2,12 +2,12 @@ #![deny(unused)] -trait Trt {} +pub trait Trt {} pub struct Str {} impl Trt for Str {} macro_rules! check_impl { - ($struct:ident,$trait:ident) => { + ($struct:ident, $trait:ident) => { const _ : () = { use std::marker::PhantomData; struct ImplementsTrait(PhantomData); diff --git a/tests/ui/default-method-parsing.rs b/tests/ui/default-method-parsing.rs index 9ffb8d94a59b3..5001d58f0a48e 100644 --- a/tests/ui/default-method-parsing.rs +++ b/tests/ui/default-method-parsing.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/delegation/target-expr-pass.rs b/tests/ui/delegation/target-expr-pass.rs index 56068dfce01d7..4ccb81c292aa5 100644 --- a/tests/ui/delegation/target-expr-pass.rs +++ b/tests/ui/delegation/target-expr-pass.rs @@ -14,14 +14,14 @@ reuse to_reuse::foo {{ x + self }} -trait Trait { +trait Trait { //~ WARN trait `Trait` is never used fn bar(&self, x: i32) -> i32 { x } } -struct F; +struct F; //~ WARN struct `F` is never constructed impl Trait for F {} -struct S(F); +struct S(F); //~ WARN struct `S` is never constructed impl Trait for S { reuse ::bar { #[allow(unused_imports)] diff --git a/tests/ui/delegation/target-expr-pass.stderr b/tests/ui/delegation/target-expr-pass.stderr index ea594f8a26a5b..dd1f3a14e0bd8 100644 --- a/tests/ui/delegation/target-expr-pass.stderr +++ b/tests/ui/delegation/target-expr-pass.stderr @@ -7,5 +7,25 @@ LL | #![feature(fn_delegation)] = note: see issue #118212 for more information = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +warning: trait `Trait` is never used + --> $DIR/target-expr-pass.rs:17:7 + | +LL | trait Trait { + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: struct `F` is never constructed + --> $DIR/target-expr-pass.rs:21:8 + | +LL | struct F; + | ^ + +warning: struct `S` is never constructed + --> $DIR/target-expr-pass.rs:24:8 + | +LL | struct S(F); + | ^ + +warning: 4 warnings emitted diff --git a/tests/ui/deriving/deriving-bounds.rs b/tests/ui/deriving/deriving-bounds.rs index f0b921d0e7c0e..f3e7cf99437d5 100644 --- a/tests/ui/deriving/deriving-bounds.rs +++ b/tests/ui/deriving/deriving-bounds.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #[derive(Copy, Clone)] struct Test; diff --git a/tests/ui/drop/drop-struct-as-object.rs b/tests/ui/drop/drop-struct-as-object.rs index 377027a4fc5f2..1aa6877704253 100644 --- a/tests/ui/drop/drop-struct-as-object.rs +++ b/tests/ui/drop/drop-struct-as-object.rs @@ -12,7 +12,7 @@ struct Cat { } trait Dummy { - fn get(&self) -> usize; + fn get(&self) -> usize; //~ WARN method `get` is never used } impl Dummy for Cat { diff --git a/tests/ui/drop/drop-struct-as-object.stderr b/tests/ui/drop/drop-struct-as-object.stderr new file mode 100644 index 0000000000000..10527c968ed70 --- /dev/null +++ b/tests/ui/drop/drop-struct-as-object.stderr @@ -0,0 +1,12 @@ +warning: method `get` is never used + --> $DIR/drop-struct-as-object.rs:15:8 + | +LL | trait Dummy { + | ----- method in this trait +LL | fn get(&self) -> usize; + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/dynamically-sized-types/dst-coercions.rs b/tests/ui/dynamically-sized-types/dst-coercions.rs index 66688e93fb80d..1efdf1de0e61c 100644 --- a/tests/ui/dynamically-sized-types/dst-coercions.rs +++ b/tests/ui/dynamically-sized-types/dst-coercions.rs @@ -5,7 +5,7 @@ // pretty-expanded FIXME #23616 struct S; -trait T { fn dummy(&self) { } } +trait T { fn dummy(&self) { } } //~ WARN method `dummy` is never used impl T for S {} pub fn main() { diff --git a/tests/ui/dynamically-sized-types/dst-coercions.stderr b/tests/ui/dynamically-sized-types/dst-coercions.stderr new file mode 100644 index 0000000000000..e4721ce50a045 --- /dev/null +++ b/tests/ui/dynamically-sized-types/dst-coercions.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/dst-coercions.rs:8:14 + | +LL | trait T { fn dummy(&self) { } } + | - ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/empty-type-parameter-list.rs b/tests/ui/empty-type-parameter-list.rs index e168cd03b2746..23d09fbf281d0 100644 --- a/tests/ui/empty-type-parameter-list.rs +++ b/tests/ui/empty-type-parameter-list.rs @@ -3,7 +3,7 @@ // no type parameters at all struct S<>; -trait T<> {} +trait T<> {} //~ WARN trait `T` is never used enum E<> { V } impl<> T<> for S<> {} impl T for E {} diff --git a/tests/ui/empty-type-parameter-list.stderr b/tests/ui/empty-type-parameter-list.stderr new file mode 100644 index 0000000000000..31a5015e99349 --- /dev/null +++ b/tests/ui/empty-type-parameter-list.stderr @@ -0,0 +1,10 @@ +warning: trait `T` is never used + --> $DIR/empty-type-parameter-list.rs:6:7 + | +LL | trait T<> {} + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed index bb093a4af4a3e..3c71587c8e399 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![allow(dropping_references)] struct Foo { diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs index 1a9f89c054f39..075d4cbe02b31 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![allow(dropping_references)] struct Foo { diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr index d2d69ce6daf72..13b6ee9987e88 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -1,5 +1,5 @@ error[E0040]: explicit use of destructor method - --> $DIR/explicit-call-to-supertrait-dtor.rs:22:14 + --> $DIR/explicit-call-to-supertrait-dtor.rs:23:14 | LL | self.drop(); | ^^^^ explicit destructor calls not allowed diff --git a/tests/ui/extern/no-mangle-associated-fn.rs b/tests/ui/extern/no-mangle-associated-fn.rs index ecd44abbf264c..56afd8b90926e 100644 --- a/tests/ui/extern/no-mangle-associated-fn.rs +++ b/tests/ui/extern/no-mangle-associated-fn.rs @@ -12,7 +12,7 @@ impl Foo { } } -trait Bar { +trait Bar { //~ WARN trait `Bar` is never used fn qux() -> u8; } diff --git a/tests/ui/extern/no-mangle-associated-fn.stderr b/tests/ui/extern/no-mangle-associated-fn.stderr new file mode 100644 index 0000000000000..772cbf6cf7dd7 --- /dev/null +++ b/tests/ui/extern/no-mangle-associated-fn.stderr @@ -0,0 +1,10 @@ +warning: trait `Bar` is never used + --> $DIR/no-mangle-associated-fn.rs:15:7 + | +LL | trait Bar { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/generic-associated-types/issue-88360.fixed b/tests/ui/generic-associated-types/issue-88360.fixed index 3dea8bf7ac81d..6fb1e2559c0ac 100644 --- a/tests/ui/generic-associated-types/issue-88360.fixed +++ b/tests/ui/generic-associated-types/issue-88360.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait GatTrait { type Gat<'a> where Self: 'a; diff --git a/tests/ui/generic-associated-types/issue-88360.rs b/tests/ui/generic-associated-types/issue-88360.rs index 4d4c7ea318078..c8f07955b6129 100644 --- a/tests/ui/generic-associated-types/issue-88360.rs +++ b/tests/ui/generic-associated-types/issue-88360.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait GatTrait { type Gat<'a> where Self: 'a; diff --git a/tests/ui/generic-associated-types/issue-88360.stderr b/tests/ui/generic-associated-types/issue-88360.stderr index 49d36acadd657..488e50d2843bf 100644 --- a/tests/ui/generic-associated-types/issue-88360.stderr +++ b/tests/ui/generic-associated-types/issue-88360.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-88360.rs:15:9 + --> $DIR/issue-88360.rs:16:9 | LL | trait SuperTrait | - found this type parameter diff --git a/tests/ui/generics/generic-no-mangle.fixed b/tests/ui/generics/generic-no-mangle.fixed index aa6d6310f5fe3..f51040358c0b3 100644 --- a/tests/ui/generics/generic-no-mangle.fixed +++ b/tests/ui/generics/generic-no-mangle.fixed @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![deny(no_mangle_generic_items)] diff --git a/tests/ui/generics/generic-no-mangle.rs b/tests/ui/generics/generic-no-mangle.rs index 8a59ca75aafd2..02015331c5712 100644 --- a/tests/ui/generics/generic-no-mangle.rs +++ b/tests/ui/generics/generic-no-mangle.rs @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![deny(no_mangle_generic_items)] #[no_mangle] diff --git a/tests/ui/impl-trait/example-st.rs b/tests/ui/impl-trait/example-st.rs index 4e1aa3a085921..1e6ebc52365dc 100644 --- a/tests/ui/impl-trait/example-st.rs +++ b/tests/ui/impl-trait/example-st.rs @@ -3,7 +3,7 @@ struct State; type Error = (); -trait Bind { +trait Bind { //~ WARN trait `Bind` is never used type Output; fn bind(self, f: F) -> Self::Output; } diff --git a/tests/ui/impl-trait/example-st.stderr b/tests/ui/impl-trait/example-st.stderr new file mode 100644 index 0000000000000..f722d7f658215 --- /dev/null +++ b/tests/ui/impl-trait/example-st.stderr @@ -0,0 +1,10 @@ +warning: trait `Bind` is never used + --> $DIR/example-st.rs:6:7 + | +LL | trait Bind { + | ^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed index 8dc8e045d4738..ecc8488a15299 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed @@ -1,6 +1,7 @@ // edition:2021 // run-rustfix +#![allow(dead_code)] trait Trait { #[allow(async_fn_in_trait)] async fn foo(); diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs index 30b04d87b9a3e..860fea07df964 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs @@ -1,6 +1,7 @@ // edition:2021 // run-rustfix +#![allow(dead_code)] trait Trait { #[allow(async_fn_in_trait)] async fn foo(); diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr index cf68ed87030a9..45fd79badb30f 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz` - --> $DIR/suggest-missing-item.rs:19:1 + --> $DIR/suggest-missing-item.rs:20:1 | LL | async fn foo(); | --------------- `foo` from trait diff --git a/tests/ui/impl-trait/type-alias-generic-param.rs b/tests/ui/impl-trait/type-alias-generic-param.rs index 1211625dac9cc..e4b2e4124202f 100644 --- a/tests/ui/impl-trait/type-alias-generic-param.rs +++ b/tests/ui/impl-trait/type-alias-generic-param.rs @@ -5,7 +5,7 @@ // run-pass #![feature(impl_trait_in_assoc_type)] -trait Meow { +trait Meow { //~ WARN trait `Meow` is never used type MeowType; fn meow(self) -> Self::MeowType; } diff --git a/tests/ui/impl-trait/type-alias-generic-param.stderr b/tests/ui/impl-trait/type-alias-generic-param.stderr new file mode 100644 index 0000000000000..e4115dc1319d1 --- /dev/null +++ b/tests/ui/impl-trait/type-alias-generic-param.stderr @@ -0,0 +1,10 @@ +warning: trait `Meow` is never used + --> $DIR/type-alias-generic-param.rs:8:7 + | +LL | trait Meow { + | ^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-14399.rs b/tests/ui/issues/issue-14399.rs index 7b32bf8e4cbb7..0c6c4d8dc6bd3 100644 --- a/tests/ui/issues/issue-14399.rs +++ b/tests/ui/issues/issue-14399.rs @@ -9,7 +9,7 @@ #[derive(Clone)] struct B1; -trait A { fn foo(&self) {} } +trait A { fn foo(&self) {} } //~ WARN method `foo` is never used impl A for B1 {} fn main() { diff --git a/tests/ui/issues/issue-14399.stderr b/tests/ui/issues/issue-14399.stderr new file mode 100644 index 0000000000000..d226ece6fb0b6 --- /dev/null +++ b/tests/ui/issues/issue-14399.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/issue-14399.rs:12:14 + | +LL | trait A { fn foo(&self) {} } + | - ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-15858.rs b/tests/ui/issues/issue-15858.rs index 77941c07671d6..e3e3c293d7a74 100644 --- a/tests/ui/issues/issue-15858.rs +++ b/tests/ui/issues/issue-15858.rs @@ -2,7 +2,7 @@ static mut DROP_RAN: bool = false; trait Bar { - fn do_something(&mut self); + fn do_something(&mut self); //~ WARN method `do_something` is never used } struct BarImpl; diff --git a/tests/ui/issues/issue-15858.stderr b/tests/ui/issues/issue-15858.stderr new file mode 100644 index 0000000000000..f36bcc21bd7fb --- /dev/null +++ b/tests/ui/issues/issue-15858.stderr @@ -0,0 +1,12 @@ +warning: method `do_something` is never used + --> $DIR/issue-15858.rs:5:8 + | +LL | trait Bar { + | --- method in this trait +LL | fn do_something(&mut self); + | ^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-17351.rs b/tests/ui/issues/issue-17351.rs index 62f6bcf15e3e7..12bb8a73b7bd4 100644 --- a/tests/ui/issues/issue-17351.rs +++ b/tests/ui/issues/issue-17351.rs @@ -1,7 +1,7 @@ // run-pass // pretty-expanded FIXME #23616 -trait Str { fn foo(&self) {} } +trait Str { fn foo(&self) {} } //~ WARN method `foo` is never used impl Str for str {} impl<'a, S: ?Sized> Str for &'a S where S: Str {} diff --git a/tests/ui/issues/issue-17351.stderr b/tests/ui/issues/issue-17351.stderr new file mode 100644 index 0000000000000..3242d578dabce --- /dev/null +++ b/tests/ui/issues/issue-17351.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/issue-17351.rs:4:16 + | +LL | trait Str { fn foo(&self) {} } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-18173.rs b/tests/ui/issues/issue-18173.rs index 11468040ee530..010efee9f8ab6 100644 --- a/tests/ui/issues/issue-18173.rs +++ b/tests/ui/issues/issue-18173.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass trait Foo { type T; } diff --git a/tests/ui/issues/issue-20055-box-trait.rs b/tests/ui/issues/issue-20055-box-trait.rs index 772cd9d7eda82..36f597450adb8 100644 --- a/tests/ui/issues/issue-20055-box-trait.rs +++ b/tests/ui/issues/issue-20055-box-trait.rs @@ -8,7 +8,7 @@ // statement surrounding the `match`. trait Boo { - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } impl Boo for [i8; 1] { } diff --git a/tests/ui/issues/issue-20055-box-trait.stderr b/tests/ui/issues/issue-20055-box-trait.stderr new file mode 100644 index 0000000000000..db9d359e2252c --- /dev/null +++ b/tests/ui/issues/issue-20055-box-trait.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-20055-box-trait.rs:11:8 + | +LL | trait Boo { + | --- method in this trait +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-21909.rs b/tests/ui/issues/issue-21909.rs index 7cb558d9a4fa6..6a6cdcfee159d 100644 --- a/tests/ui/issues/issue-21909.rs +++ b/tests/ui/issues/issue-21909.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait A { diff --git a/tests/ui/issues/issue-23485.rs b/tests/ui/issues/issue-23485.rs index 1dd3d9293bcc6..07ed0f1b00df8 100644 --- a/tests/ui/issues/issue-23485.rs +++ b/tests/ui/issues/issue-23485.rs @@ -17,7 +17,7 @@ trait Iterator { fn next(&mut self) -> Option; - fn clone_first(mut self) -> Option<::Target> where + fn clone_first(mut self) -> Option<::Target> where //~ WARN method `clone_first` is never used Self: Sized, Self::Item: Deref, ::Target: Clone, diff --git a/tests/ui/issues/issue-23485.stderr b/tests/ui/issues/issue-23485.stderr new file mode 100644 index 0000000000000..ed2d2400d0d93 --- /dev/null +++ b/tests/ui/issues/issue-23485.stderr @@ -0,0 +1,13 @@ +warning: method `clone_first` is never used + --> $DIR/issue-23485.rs:20:8 + | +LL | trait Iterator { + | -------- method in this trait +... +LL | fn clone_first(mut self) -> Option<::Target> where + | ^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-2989.rs b/tests/ui/issues/issue-2989.rs index c0b67374370e7..a95867514073c 100644 --- a/tests/ui/issues/issue-2989.rs +++ b/tests/ui/issues/issue-2989.rs @@ -1,8 +1,8 @@ // run-pass #![allow(non_camel_case_types)] -trait methods { - fn to_bytes(&self) -> Vec ; +trait methods { //~ WARN trait `methods` is never used + fn to_bytes(&self) -> Vec; } impl methods for () { diff --git a/tests/ui/issues/issue-2989.stderr b/tests/ui/issues/issue-2989.stderr new file mode 100644 index 0000000000000..57181607cecd3 --- /dev/null +++ b/tests/ui/issues/issue-2989.stderr @@ -0,0 +1,10 @@ +warning: trait `methods` is never used + --> $DIR/issue-2989.rs:4:7 + | +LL | trait methods { + | ^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-34074.rs b/tests/ui/issues/issue-34074.rs index 0600d3937c16e..ca7d7b49a042f 100644 --- a/tests/ui/issues/issue-34074.rs +++ b/tests/ui/issues/issue-34074.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Make sure several unnamed function parameters don't conflict with each other trait Tr { diff --git a/tests/ui/issues/issue-34503.rs b/tests/ui/issues/issue-34503.rs index 26e7358408f48..d2c95d990ecde 100644 --- a/tests/ui/issues/issue-34503.rs +++ b/tests/ui/issues/issue-34503.rs @@ -2,7 +2,7 @@ fn main() { struct X; trait Foo { - fn foo(&self) where (T, Option): Ord {} + fn foo(&self) where (T, Option): Ord {} //~ WARN methods `foo` and `bar` are never used fn bar(&self, x: &Option) -> bool where Option: Ord { *x < *x } } diff --git a/tests/ui/issues/issue-34503.stderr b/tests/ui/issues/issue-34503.stderr new file mode 100644 index 0000000000000..60d8d76a61965 --- /dev/null +++ b/tests/ui/issues/issue-34503.stderr @@ -0,0 +1,14 @@ +warning: methods `foo` and `bar` are never used + --> $DIR/issue-34503.rs:5:12 + | +LL | trait Foo { + | --- methods in this trait +LL | fn foo(&self) where (T, Option): Ord {} + | ^^^ +LL | fn bar(&self, x: &Option) -> bool + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-3563-3.rs b/tests/ui/issues/issue-3563-3.rs index bedfdab97d58b..6346b82167cb8 100644 --- a/tests/ui/issues/issue-3563-3.rs +++ b/tests/ui/issues/issue-3563-3.rs @@ -112,7 +112,7 @@ trait Canvas { // Unlike interfaces traits support default implementations. // Got an ICE as soon as I added this method. - fn add_points(&mut self, shapes: &[Point]) { + fn add_points(&mut self, shapes: &[Point]) { //~ WARN method `add_points` is never used for pt in shapes {self.add_point(*pt)}; } } diff --git a/tests/ui/issues/issue-3563-3.stderr b/tests/ui/issues/issue-3563-3.stderr new file mode 100644 index 0000000000000..bd65c1e3fd5b4 --- /dev/null +++ b/tests/ui/issues/issue-3563-3.stderr @@ -0,0 +1,13 @@ +warning: method `add_points` is never used + --> $DIR/issue-3563-3.rs:115:8 + | +LL | trait Canvas { + | ------ method in this trait +... +LL | fn add_points(&mut self, shapes: &[Point]) { + | ^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed index 2f8c925b85328..13c830cd0d4b1 100644 --- a/tests/ui/issues/issue-50571.fixed +++ b/tests/ui/issues/issue-50571.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn foo(_: [i32; 2]) {} //~^ ERROR: patterns aren't allowed in methods without bodies diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs index 56f422e7d5838..6fe13e3f707db 100644 --- a/tests/ui/issues/issue-50571.rs +++ b/tests/ui/issues/issue-50571.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn foo([a, b]: [i32; 2]) {} //~^ ERROR: patterns aren't allowed in methods without bodies diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr index fe47790f1ddfb..12256ded1c0a8 100644 --- a/tests/ui/issues/issue-50571.stderr +++ b/tests/ui/issues/issue-50571.stderr @@ -1,5 +1,5 @@ error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/issue-50571.rs:4:12 + --> $DIR/issue-50571.rs:5:12 | LL | fn foo([a, b]: [i32; 2]) {} | ^^^^^^ diff --git a/tests/ui/issues/issue-7575.rs b/tests/ui/issues/issue-7575.rs index ac69f2b1c80b6..0074f660c4ef0 100644 --- a/tests/ui/issues/issue-7575.rs +++ b/tests/ui/issues/issue-7575.rs @@ -1,6 +1,6 @@ // run-pass -trait Foo { +trait Foo { //~ WARN trait `Foo` is never used fn new() -> bool { false } fn dummy(&self) { } } diff --git a/tests/ui/issues/issue-7575.stderr b/tests/ui/issues/issue-7575.stderr new file mode 100644 index 0000000000000..2f987d19c80ce --- /dev/null +++ b/tests/ui/issues/issue-7575.stderr @@ -0,0 +1,10 @@ +warning: trait `Foo` is never used + --> $DIR/issue-7575.rs:3:7 + | +LL | trait Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-7911.rs b/tests/ui/issues/issue-7911.rs index d4db3b0776bca..114574b9009d8 100644 --- a/tests/ui/issues/issue-7911.rs +++ b/tests/ui/issues/issue-7911.rs @@ -4,7 +4,7 @@ #![allow(unused_variables)] // unused foobar_immut + foobar_mut trait FooBar { - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } struct Bar(#[allow(dead_code)] i32); struct Foo { bar: Bar } diff --git a/tests/ui/issues/issue-7911.stderr b/tests/ui/issues/issue-7911.stderr new file mode 100644 index 0000000000000..ead7ee191ac9b --- /dev/null +++ b/tests/ui/issues/issue-7911.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-7911.rs:7:8 + | +LL | trait FooBar { + | ------ method in this trait +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-8248.rs b/tests/ui/issues/issue-8248.rs index 31a305c31bee2..94b1a5203b47e 100644 --- a/tests/ui/issues/issue-8248.rs +++ b/tests/ui/issues/issue-8248.rs @@ -2,7 +2,7 @@ // pretty-expanded FIXME #23616 trait A { - fn dummy(&self) { } + fn dummy(&self) { } //~ WARN method `dummy` is never used } struct B; impl A for B {} diff --git a/tests/ui/issues/issue-8248.stderr b/tests/ui/issues/issue-8248.stderr new file mode 100644 index 0000000000000..a0098bcb771ae --- /dev/null +++ b/tests/ui/issues/issue-8248.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-8248.rs:5:8 + | +LL | trait A { + | - method in this trait +LL | fn dummy(&self) { } + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-9951.rs b/tests/ui/issues/issue-9951.rs index 2698a3b17c6c2..5db3f74efaa3e 100644 --- a/tests/ui/issues/issue-9951.rs +++ b/tests/ui/issues/issue-9951.rs @@ -4,7 +4,7 @@ #![allow(unused_variables)] trait Bar { - fn noop(&self); + fn noop(&self); //~ WARN method `noop` is never used } impl Bar for u8 { fn noop(&self) {} diff --git a/tests/ui/issues/issue-9951.stderr b/tests/ui/issues/issue-9951.stderr new file mode 100644 index 0000000000000..475f2817914d3 --- /dev/null +++ b/tests/ui/issues/issue-9951.stderr @@ -0,0 +1,12 @@ +warning: method `noop` is never used + --> $DIR/issue-9951.rs:7:6 + | +LL | trait Bar { + | --- method in this trait +LL | fn noop(&self); + | ^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lint/dead-code/associated-type.rs b/tests/ui/lint/dead-code/associated-type.rs index 1cf66e75a95a5..25106a66e7e36 100644 --- a/tests/ui/lint/dead-code/associated-type.rs +++ b/tests/ui/lint/dead-code/associated-type.rs @@ -15,5 +15,5 @@ impl Foo for Ex { } pub fn main() { - let _x = Ex; + let _x: &dyn Foo::Bar> = &Ex; } diff --git a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs index 942c551650032..2d6364aa0cde1 100644 --- a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs +++ b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs @@ -17,7 +17,7 @@ struct Bar { // Issue 119267: this should not ICE. #[derive(Debug)] -struct Foo(usize, #[allow(unused)] usize); //~ WARN field `0` is never read +struct Foo(usize, #[allow(unused)] usize); //~ WARN struct `Foo` is never constructed fn main() { Bar { diff --git a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr index 06f9b229c18c1..b992005318f2e 100644 --- a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr +++ b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr @@ -51,19 +51,13 @@ note: the lint level is defined here LL | #[forbid(dead_code)] | ^^^^^^^^^ -warning: field `0` is never read - --> $DIR/multiple-dead-codes-in-the-same-struct.rs:20:12 +warning: struct `Foo` is never constructed + --> $DIR/multiple-dead-codes-in-the-same-struct.rs:20:8 | LL | struct Foo(usize, #[allow(unused)] usize); - | --- ^^^^^ - | | - | field in this struct + | ^^^ | = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis -help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field - | -LL | struct Foo((), #[allow(unused)] usize); - | ~~ error: aborting due to 2 previous errors; 2 warnings emitted diff --git a/tests/ui/lint/issue-20343.rs b/tests/ui/lint/issue-20343.rs index 000b6398442a3..f0f4eccc676a1 100644 --- a/tests/ui/lint/issue-20343.rs +++ b/tests/ui/lint/issue-20343.rs @@ -22,6 +22,8 @@ impl B { // test for unused code in generics fn baz>() {} + + fn foz>(a: A) { a.dummy(D); } } pub fn main() { @@ -29,4 +31,5 @@ pub fn main() { B::foo(b); B::bar(); B::baz::<()>(); + B::foz::<()>(()); } diff --git a/tests/ui/macros/issue-22463.rs b/tests/ui/macros/issue-22463.rs index fdf5a2fca7255..8f7b27cb9a056 100644 --- a/tests/ui/macros/issue-22463.rs +++ b/tests/ui/macros/issue-22463.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass macro_rules! items { () => { type A = (); diff --git a/tests/ui/methods/method-lookup-order.rs b/tests/ui/methods/method-lookup-order.rs index 986fe103cdc79..5a46cf35dec0e 100644 --- a/tests/ui/methods/method-lookup-order.rs +++ b/tests/ui/methods/method-lookup-order.rs @@ -1,6 +1,7 @@ // ignore-tidy-linelength // run-pass +#![allow(dead_code)] // There are five cfg's below. I explored the set of all non-empty combinations // of the below five cfg's, which is 2^5 - 1 = 31 combinations. diff --git a/tests/ui/methods/method-recursive-blanket-impl.rs b/tests/ui/methods/method-recursive-blanket-impl.rs index a2db75b4e85d8..e7e83cbec7756 100644 --- a/tests/ui/methods/method-recursive-blanket-impl.rs +++ b/tests/ui/methods/method-recursive-blanket-impl.rs @@ -11,7 +11,7 @@ use std::marker::Sized; // Note: this must be generic for the problem to show up -trait Foo { +trait Foo { //~ WARN trait `Foo` is never used fn foo(&self, a: A); } diff --git a/tests/ui/methods/method-recursive-blanket-impl.stderr b/tests/ui/methods/method-recursive-blanket-impl.stderr new file mode 100644 index 0000000000000..9797a8f6c8308 --- /dev/null +++ b/tests/ui/methods/method-recursive-blanket-impl.stderr @@ -0,0 +1,10 @@ +warning: trait `Foo` is never used + --> $DIR/method-recursive-blanket-impl.rs:14:7 + | +LL | trait Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/methods/method-two-trait-defer-resolution-2.rs b/tests/ui/methods/method-two-trait-defer-resolution-2.rs index fc5766da9714b..d6076126732bc 100644 --- a/tests/ui/methods/method-two-trait-defer-resolution-2.rs +++ b/tests/ui/methods/method-two-trait-defer-resolution-2.rs @@ -14,7 +14,7 @@ trait Foo { fn foo(&self) -> isize; } -trait MyCopy { fn foo(&self) { } } +trait MyCopy { fn foo(&self) { } } //~ WARN method `foo` is never used impl MyCopy for i32 { } impl Foo for Vec { diff --git a/tests/ui/methods/method-two-trait-defer-resolution-2.stderr b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr new file mode 100644 index 0000000000000..4501ea5d24334 --- /dev/null +++ b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/method-two-trait-defer-resolution-2.rs:17:19 + | +LL | trait MyCopy { fn foo(&self) { } } + | ------ ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs index d820d2ad08ae8..2fd6c3bfab868 100644 --- a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs +++ b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 -trait A { +trait A { //~ WARN trait `A` is never used fn foo(self); } diff --git a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr new file mode 100644 index 0000000000000..0a60c6242bb2d --- /dev/null +++ b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr @@ -0,0 +1,10 @@ +warning: trait `A` is never used + --> $DIR/method-two-traits-distinguished-via-where-clause.rs:7:7 + | +LL | trait A { + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/mir/mir_raw_fat_ptr.rs b/tests/ui/mir/mir_raw_fat_ptr.rs index 8e5a2043dc696..e141aa03aa985 100644 --- a/tests/ui/mir/mir_raw_fat_ptr.rs +++ b/tests/ui/mir/mir_raw_fat_ptr.rs @@ -98,7 +98,7 @@ fn assert_inorder(a: &[T], } } -trait Foo { fn foo(&self) -> usize; } +trait Foo { fn foo(&self) -> usize; } //~ WARN method `foo` is never used impl Foo for T { fn foo(&self) -> usize { mem::size_of::() diff --git a/tests/ui/mir/mir_raw_fat_ptr.stderr b/tests/ui/mir/mir_raw_fat_ptr.stderr new file mode 100644 index 0000000000000..a9e9dd66ebdfa --- /dev/null +++ b/tests/ui/mir/mir_raw_fat_ptr.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/mir_raw_fat_ptr.rs:101:16 + | +LL | trait Foo { fn foo(&self) -> usize; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/moves/issue-22536-copy-mustnt-zero.rs b/tests/ui/moves/issue-22536-copy-mustnt-zero.rs index 017f36484c1cf..b3fc1a56f882f 100644 --- a/tests/ui/moves/issue-22536-copy-mustnt-zero.rs +++ b/tests/ui/moves/issue-22536-copy-mustnt-zero.rs @@ -5,7 +5,7 @@ trait Resources { type Buffer: Copy; - fn foo(&self) {} + fn foo(&self) {} //~ WARN method `foo` is never used } struct BufferHandle { diff --git a/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr new file mode 100644 index 0000000000000..b1fcdfa44c33d --- /dev/null +++ b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr @@ -0,0 +1,13 @@ +warning: method `foo` is never used + --> $DIR/issue-22536-copy-mustnt-zero.rs:8:8 + | +LL | trait Resources { + | --------- method in this trait +LL | type Buffer: Copy; +LL | fn foo(&self) {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed index 45c7e07a26471..52046a8ab693d 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait TraitWithAType { type Item: ?Sized; } diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs index c3e958f498390..96620c0abda34 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait TraitWithAType { type Item; } diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr index cd2aa9fdbe3e4..9bb770ce43199 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr @@ -1,12 +1,12 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time - --> $DIR/assoc_type_bounds_implicit_sized.rs:8:17 + --> $DIR/assoc_type_bounds_implicit_sized.rs:9:17 | LL | type Item = dyn Trait; | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` note: required by a bound in `TraitWithAType::Item` - --> $DIR/assoc_type_bounds_implicit_sized.rs:3:5 + --> $DIR/assoc_type_bounds_implicit_sized.rs:4:5 | LL | type Item; | ^^^^^^^^^^ required by this bound in `TraitWithAType::Item` diff --git a/tests/ui/overloaded/issue-14958.rs b/tests/ui/overloaded/issue-14958.rs index a12564ca9c0ee..80abf5e4e7689 100644 --- a/tests/ui/overloaded/issue-14958.rs +++ b/tests/ui/overloaded/issue-14958.rs @@ -3,7 +3,7 @@ #![feature(fn_traits, unboxed_closures)] -trait Foo { fn dummy(&self) { }} +trait Foo { fn dummy(&self) { }} //~ WARN method `dummy` is never used struct Bar; diff --git a/tests/ui/overloaded/issue-14958.stderr b/tests/ui/overloaded/issue-14958.stderr new file mode 100644 index 0000000000000..cc97730239c30 --- /dev/null +++ b/tests/ui/overloaded/issue-14958.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/issue-14958.rs:6:16 + | +LL | trait Foo { fn dummy(&self) { }} + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/overloaded/overloaded-index-in-field.rs b/tests/ui/overloaded/overloaded-index-in-field.rs index 8a1fa7deb9996..0dc45ea8ca2b8 100644 --- a/tests/ui/overloaded/overloaded-index-in-field.rs +++ b/tests/ui/overloaded/overloaded-index-in-field.rs @@ -27,7 +27,7 @@ impl Index for Foo { trait Int { fn get(self) -> isize; - fn get_from_ref(&self) -> isize; + fn get_from_ref(&self) -> isize; //~ WARN methods `get_from_ref` and `inc` are never used fn inc(&mut self); } diff --git a/tests/ui/overloaded/overloaded-index-in-field.stderr b/tests/ui/overloaded/overloaded-index-in-field.stderr new file mode 100644 index 0000000000000..10c0a3faeb59a --- /dev/null +++ b/tests/ui/overloaded/overloaded-index-in-field.stderr @@ -0,0 +1,15 @@ +warning: methods `get_from_ref` and `inc` are never used + --> $DIR/overloaded-index-in-field.rs:30:8 + | +LL | trait Int { + | --- methods in this trait +LL | fn get(self) -> isize; +LL | fn get_from_ref(&self) -> isize; + | ^^^^^^^^^^^^ +LL | fn inc(&mut self); + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/parser/parse-assoc-type-lt.rs b/tests/ui/parser/parse-assoc-type-lt.rs index d3fe6079a5d2a..913fcd920bdb6 100644 --- a/tests/ui/parser/parse-assoc-type-lt.rs +++ b/tests/ui/parser/parse-assoc-type-lt.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/parser/suggest-assoc-const.fixed b/tests/ui/parser/suggest-assoc-const.fixed index 259f37b23a584..4229135ebb23b 100644 --- a/tests/ui/parser/suggest-assoc-const.fixed +++ b/tests/ui/parser/suggest-assoc-const.fixed @@ -1,5 +1,6 @@ // Issue: 101797, Suggest associated const for incorrect use of let in traits // run-rustfix +#![allow(dead_code)] trait Trait { const _X: i32; //~^ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-assoc-const.rs b/tests/ui/parser/suggest-assoc-const.rs index c7be712ec076e..0cf695bd40aff 100644 --- a/tests/ui/parser/suggest-assoc-const.rs +++ b/tests/ui/parser/suggest-assoc-const.rs @@ -1,5 +1,6 @@ // Issue: 101797, Suggest associated const for incorrect use of let in traits // run-rustfix +#![allow(dead_code)] trait Trait { let _X: i32; //~^ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-assoc-const.stderr b/tests/ui/parser/suggest-assoc-const.stderr index 7ba1dbdff7e59..6e29fad98d466 100644 --- a/tests/ui/parser/suggest-assoc-const.stderr +++ b/tests/ui/parser/suggest-assoc-const.stderr @@ -1,5 +1,5 @@ error: non-item in item list - --> $DIR/suggest-assoc-const.rs:4:5 + --> $DIR/suggest-assoc-const.rs:5:5 | LL | let _X: i32; | ^^^ help: consider using `const` instead of `let` for associated const: `const` diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed index 63704735490fa..81ee6cdf0a722 100644 --- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed +++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn bar() {} //~ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs index 4650b05e20ce8..c8f525fc4f0ad 100644 --- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs +++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait Foo { fn bar() {}; //~ ERROR non-item in item list diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr index c716d5908ea11..396c76ac85f2f 100644 --- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr +++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr @@ -1,5 +1,5 @@ error: non-item in item list - --> $DIR/suggest-removing-semicolon-after-impl-trait-items.rs:4:16 + --> $DIR/suggest-removing-semicolon-after-impl-trait-items.rs:5:16 | LL | trait Foo { | - item list starts here diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs index c26e457f9e452..8a0f51d0b84b9 100644 --- a/tests/ui/pattern/issue-22546.rs +++ b/tests/ui/pattern/issue-22546.rs @@ -15,7 +15,7 @@ impl Foo { } } -trait Tr { +trait Tr { //~ WARN trait `Tr` is never used type U; } diff --git a/tests/ui/pattern/issue-22546.stderr b/tests/ui/pattern/issue-22546.stderr new file mode 100644 index 0000000000000..e067a95e4226c --- /dev/null +++ b/tests/ui/pattern/issue-22546.stderr @@ -0,0 +1,10 @@ +warning: trait `Tr` is never used + --> $DIR/issue-22546.rs:18:7 + | +LL | trait Tr { + | ^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed index 79b6a6516ab26..6de7b865a9914 100644 --- a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] pub mod a { pub use self::b::Trait; diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.rs b/tests/ui/privacy/sealed-traits/re-exported-trait.rs index 5f96dfdcbd6c4..bf07d666dff89 100644 --- a/tests/ui/privacy/sealed-traits/re-exported-trait.rs +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] pub mod a { pub use self::b::Trait; diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr index 9f2291e6825a6..6e2f36e3f381d 100644 --- a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr @@ -1,11 +1,11 @@ error[E0603]: module `b` is private - --> $DIR/re-exported-trait.rs:11:9 + --> $DIR/re-exported-trait.rs:12:9 | LL | impl a::b::Trait for S {} | ^ private module | note: the module `b` is defined here - --> $DIR/re-exported-trait.rs:5:5 + --> $DIR/re-exported-trait.rs:6:5 | LL | mod b { | ^^^^^ diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed index ae5f9f86726f3..a61c868ed0a1a 100644 --- a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed +++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed @@ -1,6 +1,7 @@ // run-rustfix #[derive(Debug)] //~ ERROR `derive` attribute cannot be used at crate level +#[allow(dead_code)] struct Test {} fn main() {} diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs index 639c64f8827c5..403f4470de77b 100644 --- a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs +++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs @@ -1,6 +1,7 @@ // run-rustfix #![derive(Debug)] //~ ERROR `derive` attribute cannot be used at crate level +#[allow(dead_code)] struct Test {} fn main() {} diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr index f62cdd14b873f..09908160542d4 100644 --- a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr +++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr @@ -3,6 +3,7 @@ error: `derive` attribute cannot be used at crate level | LL | #![derive(Debug)] | ^^^^^^^^^^^^^^^^^ +LL | #[allow(dead_code)] LL | struct Test {} | ---- the inner attribute doesn't annotate this struct | diff --git a/tests/ui/regions/regions-no-variance-from-fn-generics.rs b/tests/ui/regions/regions-no-variance-from-fn-generics.rs index 76706a8278197..a455d4efd71b5 100644 --- a/tests/ui/regions/regions-no-variance-from-fn-generics.rs +++ b/tests/ui/regions/regions-no-variance-from-fn-generics.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_variables)] // Issue #12856: a lifetime formal binding introduced by a generic fn // should not upset the variance inference for actual occurrences of diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed index e730f94660bbd..a7ab88fe99357 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![deny(unused_qualifications)] #![feature(unsized_fn_params)] diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs index 641c892e3de9a..05936b191ffea 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(dead_code)] #![deny(unused_qualifications)] #![feature(unsized_fn_params)] diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr index d9c7fd21871ba..bcda721071235 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr @@ -1,11 +1,11 @@ error: unnecessary qualification - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:12:6 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:13:6 | LL | impl ops::Index for A { | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:3:9 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:4:9 | LL | #![deny(unused_qualifications)] | ^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL + impl Index for A { | error: unnecessary qualification - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:28:6 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:29:6 | LL | impl inner::Trait for () {} | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr new file mode 100644 index 0000000000000..4a219ff8b5562 --- /dev/null +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr @@ -0,0 +1,15 @@ +warning: methods `good_virt` and `good_indirect` are never used + --> $DIR/manual-self-impl-for-unsafe-obj.rs:22:8 + | +LL | trait Good { + | ---- methods in this trait +LL | fn good_virt(&self) -> char { + | ^^^^^^^^^ +... +LL | fn good_indirect(&self) -> char { + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr new file mode 100644 index 0000000000000..4a219ff8b5562 --- /dev/null +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr @@ -0,0 +1,15 @@ +warning: methods `good_virt` and `good_indirect` are never used + --> $DIR/manual-self-impl-for-unsafe-obj.rs:22:8 + | +LL | trait Good { + | ---- methods in this trait +LL | fn good_virt(&self) -> char { + | ^^^^^^^^^ +... +LL | fn good_indirect(&self) -> char { + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs index c7665affb992b..c8eee9835fed3 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs @@ -19,7 +19,7 @@ trait Bad { } trait Good { - fn good_virt(&self) -> char { + fn good_virt(&self) -> char { //~ WARN methods `good_virt` and `good_indirect` are never used panic!() } fn good_indirect(&self) -> char { diff --git a/tests/ui/rust-2018/issue-51008-1.rs b/tests/ui/rust-2018/issue-51008-1.rs index da7b8ef65c566..67dfbf6460133 100644 --- a/tests/ui/rust-2018/issue-51008-1.rs +++ b/tests/ui/rust-2018/issue-51008-1.rs @@ -2,7 +2,7 @@ // being incorrectly considered part of the "elided lifetimes" from // the impl. // -// run-pass +// check-pass trait A { diff --git a/tests/ui/rust-2018/issue-51008.rs b/tests/ui/rust-2018/issue-51008.rs index 56517b9adee65..f9e4bc14ec82c 100644 --- a/tests/ui/rust-2018/issue-51008.rs +++ b/tests/ui/rust-2018/issue-51008.rs @@ -2,7 +2,7 @@ // being incorrectly considered part of the "elided lifetimes" from // the impl. // -// run-pass +// check-pass trait A { diff --git a/tests/ui/sized/coinductive-2.rs b/tests/ui/sized/coinductive-2.rs index 212274d2e4b6c..43a5a28f710a7 100644 --- a/tests/ui/sized/coinductive-2.rs +++ b/tests/ui/sized/coinductive-2.rs @@ -11,7 +11,7 @@ impl CollectionFactory for Vec<()> { type Collection = Vec; } -trait Collection: Sized { +trait Collection: Sized { //~ WARN trait `Collection` is never used fn push(&mut self, v: T); } diff --git a/tests/ui/sized/coinductive-2.stderr b/tests/ui/sized/coinductive-2.stderr new file mode 100644 index 0000000000000..1390b1f8d7bf1 --- /dev/null +++ b/tests/ui/sized/coinductive-2.stderr @@ -0,0 +1,10 @@ +warning: trait `Collection` is never used + --> $DIR/coinductive-2.rs:14:7 + | +LL | trait Collection: Sized { + | ^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/specialization/assoc-ty-graph-cycle.rs b/tests/ui/specialization/assoc-ty-graph-cycle.rs index fc39b553a61ac..bec8cc187b4ab 100644 --- a/tests/ui/specialization/assoc-ty-graph-cycle.rs +++ b/tests/ui/specialization/assoc-ty-graph-cycle.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Make sure we don't crash with a cycle error during coherence. diff --git a/tests/ui/specialization/defaultimpl/out-of-order.rs b/tests/ui/specialization/defaultimpl/out-of-order.rs index 13258ac8c9fe6..94b3905178fa8 100644 --- a/tests/ui/specialization/defaultimpl/out-of-order.rs +++ b/tests/ui/specialization/defaultimpl/out-of-order.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that you can list the more specific impl before the more general one. diff --git a/tests/ui/specialization/defaultimpl/overlap-projection.rs b/tests/ui/specialization/defaultimpl/overlap-projection.rs index 0add4d5516c7b..46f54c466a831 100644 --- a/tests/ui/specialization/defaultimpl/overlap-projection.rs +++ b/tests/ui/specialization/defaultimpl/overlap-projection.rs @@ -1,4 +1,4 @@ -// run-pass +// 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 diff --git a/tests/ui/specialization/specialization-out-of-order.rs b/tests/ui/specialization/specialization-out-of-order.rs index cb7563e2760c2..66e6c3c9eab31 100644 --- a/tests/ui/specialization/specialization-out-of-order.rs +++ b/tests/ui/specialization/specialization-out-of-order.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Test that you can list the more specific impl before the more general one. diff --git a/tests/ui/specialization/specialization-overlap-projection.rs b/tests/ui/specialization/specialization-overlap-projection.rs index b07efb2a5c1cd..cd21eab24c0b7 100644 --- a/tests/ui/specialization/specialization-overlap-projection.rs +++ b/tests/ui/specialization/specialization-overlap-projection.rs @@ -1,4 +1,4 @@ -// run-pass +// 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 diff --git a/tests/ui/specialization/specialization-supertraits.rs b/tests/ui/specialization/specialization-supertraits.rs index fb85d8019218a..d0c9dbb1d4014 100644 --- a/tests/ui/specialization/specialization-supertraits.rs +++ b/tests/ui/specialization/specialization-supertraits.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(specialization)] //~ WARN the feature `specialization` is incomplete diff --git a/tests/ui/statics/static-impl.rs b/tests/ui/statics/static-impl.rs index e7bdb38ee62c9..9e2db7e0caf50 100644 --- a/tests/ui/statics/static-impl.rs +++ b/tests/ui/statics/static-impl.rs @@ -35,7 +35,7 @@ impl uint_utils for usize { trait vec_utils { fn length_(&self, ) -> usize; - fn iter_(&self, f: F) where F: FnMut(&T); + fn iter_(&self, f: F) where F: FnMut(&T); //~ WARN method `iter_` is never used fn map_(&self, f: F) -> Vec where F: FnMut(&T) -> U; } diff --git a/tests/ui/statics/static-impl.stderr b/tests/ui/statics/static-impl.stderr new file mode 100644 index 0000000000000..83c3ffbefe1f2 --- /dev/null +++ b/tests/ui/statics/static-impl.stderr @@ -0,0 +1,13 @@ +warning: method `iter_` is never used + --> $DIR/static-impl.rs:38:8 + | +LL | trait vec_utils { + | --------- method in this trait +LL | fn length_(&self, ) -> usize; +LL | fn iter_(&self, f: F) where F: FnMut(&T); + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs b/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs index 0f535523dcc06..4a8289cb24284 100644 --- a/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs +++ b/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs @@ -32,7 +32,7 @@ fn assert_inorder(a: &[T]) { } } -trait Foo { fn foo(&self) -> usize; } +trait Foo { fn foo(&self) -> usize; } //~ WARN method `foo` is never used impl Foo for T { fn foo(&self) -> usize { mem::size_of::() diff --git a/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr new file mode 100644 index 0000000000000..670fa5bb9224b --- /dev/null +++ b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/raw-fat-ptr.rs:35:16 + | +LL | trait Foo { fn foo(&self) -> usize; } + | --- ^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.rs b/tests/ui/structs-enums/enum-null-pointer-opt.rs index 356f8a6dd36f6..21564eeec29e3 100644 --- a/tests/ui/structs-enums/enum-null-pointer-opt.rs +++ b/tests/ui/structs-enums/enum-null-pointer-opt.rs @@ -7,7 +7,7 @@ use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; -trait Trait { fn dummy(&self) { } } +trait Trait { fn dummy(&self) { } } //~ WARN method `dummy` is never used trait Mirror { type Image; } impl Mirror for T { type Image = T; } struct ParamTypeStruct(#[allow(dead_code)] T); diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.stderr b/tests/ui/structs-enums/enum-null-pointer-opt.stderr new file mode 100644 index 0000000000000..64e93ffaffd60 --- /dev/null +++ b/tests/ui/structs-enums/enum-null-pointer-opt.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/enum-null-pointer-opt.rs:10:18 + | +LL | trait Trait { fn dummy(&self) { } } + | ----- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/suggestions/bound-suggestions.fixed b/tests/ui/suggestions/bound-suggestions.fixed index 17a019c69849f..ef61fb9ad325f 100644 --- a/tests/ui/suggestions/bound-suggestions.fixed +++ b/tests/ui/suggestions/bound-suggestions.fixed @@ -40,26 +40,31 @@ fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Sized { //~^ ERROR doesn't implement } +#[allow(dead_code)] trait Foo: Sized { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bar: std::fmt::Display + Sized { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Baz: Sized where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Qux: Sized where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bat: std::fmt::Display + Sized { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time diff --git a/tests/ui/suggestions/bound-suggestions.rs b/tests/ui/suggestions/bound-suggestions.rs index 86f708d42f5e7..6d17fae6a088e 100644 --- a/tests/ui/suggestions/bound-suggestions.rs +++ b/tests/ui/suggestions/bound-suggestions.rs @@ -40,26 +40,31 @@ fn test_many_bounds_where(x: X) where X: Sized, X: Sized { //~^ ERROR doesn't implement } +#[allow(dead_code)] trait Foo { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bar: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Baz where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Qux where Self: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time } +#[allow(dead_code)] trait Bat: std::fmt::Display { const SIZE: usize = core::mem::size_of::(); //~^ ERROR the size for values of type `Self` cannot be known at compilation time diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr index 7e58ccd461d19..4965e7439f849 100644 --- a/tests/ui/suggestions/bound-suggestions.stderr +++ b/tests/ui/suggestions/bound-suggestions.stderr @@ -71,7 +71,7 @@ LL | fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Siz | +++++++++++++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:44:46 + --> $DIR/bound-suggestions.rs:45:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time @@ -84,7 +84,7 @@ LL | trait Foo: Sized { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:49:46 + --> $DIR/bound-suggestions.rs:51:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time @@ -97,7 +97,7 @@ LL | trait Bar: std::fmt::Display + Sized { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:54:46 + --> $DIR/bound-suggestions.rs:57:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time @@ -110,7 +110,7 @@ LL | trait Baz: Sized where Self: std::fmt::Display { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:59:46 + --> $DIR/bound-suggestions.rs:63:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time @@ -123,7 +123,7 @@ LL | trait Qux: Sized where Self: std::fmt::Display { | +++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/bound-suggestions.rs:64:46 + --> $DIR/bound-suggestions.rs:69:46 | LL | const SIZE: usize = core::mem::size_of::(); | ^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/suggestions/constrain-trait.fixed b/tests/ui/suggestions/constrain-trait.fixed index f292f27f0f342..f7360efe4c527 100644 --- a/tests/ui/suggestions/constrain-trait.fixed +++ b/tests/ui/suggestions/constrain-trait.fixed @@ -1,5 +1,6 @@ // run-rustfix // check-only +#![allow(dead_code)] #[derive(Debug)] struct Demo { diff --git a/tests/ui/suggestions/constrain-trait.rs b/tests/ui/suggestions/constrain-trait.rs index 99ccf7a7f3bdf..799100669b654 100644 --- a/tests/ui/suggestions/constrain-trait.rs +++ b/tests/ui/suggestions/constrain-trait.rs @@ -1,5 +1,6 @@ // run-rustfix // check-only +#![allow(dead_code)] #[derive(Debug)] struct Demo { diff --git a/tests/ui/suggestions/constrain-trait.stderr b/tests/ui/suggestions/constrain-trait.stderr index a26f86917bc1f..b28972ecde041 100644 --- a/tests/ui/suggestions/constrain-trait.stderr +++ b/tests/ui/suggestions/constrain-trait.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `get_a` found for reference `&Self` in the current scope - --> $DIR/constrain-trait.rs:15:31 + --> $DIR/constrain-trait.rs:16:31 | LL | println!("{:?}", self.get_a()); | ^^^^^ method not found in `&Self` @@ -11,7 +11,7 @@ LL | trait UseString: std::fmt::Debug + GetString { | +++++++++++ error[E0599]: no method named `get_a` found for reference `&Self` in the current scope - --> $DIR/constrain-trait.rs:21:31 + --> $DIR/constrain-trait.rs:22:31 | LL | println!("{:?}", self.get_a()); | ^^^^^ method not found in `&Self` diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed index 3257ea04c6900..d4a8381fcb146 100644 --- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed +++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed @@ -1,6 +1,7 @@ // Make sure we suggest the bound `T: 'a` in the correct scope: // trait, impl or associated fn. // run-rustfix +#![allow(dead_code)] struct Inv<'a>(#[allow(dead_code)] Option<*mut &'a u8>); diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs index fcc13aad9965e..dc43e2df6ddb0 100644 --- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs +++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs @@ -1,6 +1,7 @@ // Make sure we suggest the bound `T: 'a` in the correct scope: // trait, impl or associated fn. // run-rustfix +#![allow(dead_code)] struct Inv<'a>(#[allow(dead_code)] Option<*mut &'a u8>); diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr index d3ca2cc116228..91054472c04d4 100644 --- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr +++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr @@ -1,5 +1,5 @@ error[E0309]: the parameter type `Self` may not live long enough - --> $DIR/type-param-bound-scope.rs:11:9 + --> $DIR/type-param-bound-scope.rs:12:9 | LL | trait Trait1<'a>: Sized { | -- the parameter type `Self` must be valid for the lifetime `'a` as defined here... @@ -13,7 +13,7 @@ LL | trait Trait1<'a>: Sized where Self: 'a { | ++++++++++++++ error[E0309]: the parameter type `Self` may not live long enough - --> $DIR/type-param-bound-scope.rs:18:9 + --> $DIR/type-param-bound-scope.rs:19:9 | LL | fn foo<'a>(self, lt: Inv<'a>) { | -- the parameter type `Self` must be valid for the lifetime `'a` as defined here... @@ -26,7 +26,7 @@ LL | fn foo<'a>(self, lt: Inv<'a>) where Self: 'a { | ++++++++++++++ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/type-param-bound-scope.rs:25:9 + --> $DIR/type-param-bound-scope.rs:26:9 | LL | fn foo<'a>(arg: T, lt: Inv<'a>) { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... @@ -39,7 +39,7 @@ LL | fn foo<'a>(arg: T, lt: Inv<'a>) where T: 'a { | +++++++++++ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/type-param-bound-scope.rs:32:9 + --> $DIR/type-param-bound-scope.rs:33:9 | LL | trait Trait4<'a> { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... @@ -53,7 +53,7 @@ LL | fn foo(arg: T, lt: Inv<'a>) { | ++++ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/type-param-bound-scope.rs:42:9 + --> $DIR/type-param-bound-scope.rs:43:9 | LL | impl<'a, T> Trait5<'a> for T { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed index f32c61a99bb8c..90bc10d34c611 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs index d7725f4a3743d..34673852a9b53 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr index 6dc512223d1b0..23a75154f2008 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/missing-bound-in-manual-copy-impl-2.rs:16:18 + --> $DIR/missing-bound-in-manual-copy-impl-2.rs:17:18 | LL | struct Wrapper(T); | - this field does not implement `Copy` @@ -8,7 +8,7 @@ LL | impl Copy for Wrapper> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the `Copy` impl for `OnlyCopyIfDisplay` requires that `S: std::fmt::Display` - --> $DIR/missing-bound-in-manual-copy-impl-2.rs:4:19 + --> $DIR/missing-bound-in-manual-copy-impl-2.rs:5:19 | LL | struct Wrapper(T); | ^ diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed index 1139b315313fc..ff84e42c9470b 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs index 19549248efc23..35d0a9dda7914 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] #[derive(Clone)] struct Wrapper(T); diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr index fd38d4c64b44c..c9f277fb3501a 100644 --- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr +++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/missing-bound-in-manual-copy-impl.rs:6:18 + --> $DIR/missing-bound-in-manual-copy-impl.rs:7:18 | LL | struct Wrapper(T); | - this field does not implement `Copy` diff --git a/tests/ui/suggestions/missing-trait-item.fixed b/tests/ui/suggestions/missing-trait-item.fixed index a1cf359ec9124..ded4ec1976067 100644 --- a/tests/ui/suggestions/missing-trait-item.fixed +++ b/tests/ui/suggestions/missing-trait-item.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait T { unsafe fn foo(a: &usize, b: &usize) -> usize; diff --git a/tests/ui/suggestions/missing-trait-item.rs b/tests/ui/suggestions/missing-trait-item.rs index b4fca25ba2f11..de8974037ac99 100644 --- a/tests/ui/suggestions/missing-trait-item.rs +++ b/tests/ui/suggestions/missing-trait-item.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait T { unsafe fn foo(a: &usize, b: &usize) -> usize; diff --git a/tests/ui/suggestions/missing-trait-item.stderr b/tests/ui/suggestions/missing-trait-item.stderr index 4a9d7b472c93a..298d0d16438be 100644 --- a/tests/ui/suggestions/missing-trait-item.stderr +++ b/tests/ui/suggestions/missing-trait-item.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `foo`, `bar` - --> $DIR/missing-trait-item.rs:10:5 + --> $DIR/missing-trait-item.rs:11:5 | LL | unsafe fn foo(a: &usize, b: &usize) -> usize; | --------------------------------------------- `foo` from trait @@ -10,7 +10,7 @@ LL | impl T for () {} | ^^^^^^^^^^^^^ missing `foo`, `bar` in implementation error[E0046]: not all trait items implemented, missing: `foo`, `bar` - --> $DIR/missing-trait-item.rs:12:5 + --> $DIR/missing-trait-item.rs:13:5 | LL | unsafe fn foo(a: &usize, b: &usize) -> usize; | --------------------------------------------- `foo` from trait diff --git a/tests/ui/threads-sendsync/sync-send-atomics.rs b/tests/ui/threads-sendsync/sync-send-atomics.rs index 0466f4f0e9ddc..6b260311a50a7 100644 --- a/tests/ui/threads-sendsync/sync-send-atomics.rs +++ b/tests/ui/threads-sendsync/sync-send-atomics.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 diff --git a/tests/ui/traits/alias/bounds.rs b/tests/ui/traits/alias/bounds.rs index b97eb38c5af8d..7b1920bc8f27c 100644 --- a/tests/ui/traits/alias/bounds.rs +++ b/tests/ui/traits/alias/bounds.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; -trait Empty {} +trait Empty {} //~ WARN trait `Empty` is never used trait EmptyAlias = Empty; trait CloneDefault = Clone + Default; trait SendSyncAlias = Send + Sync; diff --git a/tests/ui/traits/alias/bounds.stderr b/tests/ui/traits/alias/bounds.stderr new file mode 100644 index 0000000000000..7fb8e918da36d --- /dev/null +++ b/tests/ui/traits/alias/bounds.stderr @@ -0,0 +1,10 @@ +warning: trait `Empty` is never used + --> $DIR/bounds.rs:7:7 + | +LL | trait Empty {} + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/alias/syntax.rs b/tests/ui/traits/alias/syntax.rs index 17557a51aa723..50c77d33c6bce 100644 --- a/tests/ui/traits/alias/syntax.rs +++ b/tests/ui/traits/alias/syntax.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(trait_alias)] diff --git a/tests/ui/traits/bound/impl-comparison-duplicates.rs b/tests/ui/traits/bound/impl-comparison-duplicates.rs index de6c2afa2bbe1..a59662c2797ff 100644 --- a/tests/ui/traits/bound/impl-comparison-duplicates.rs +++ b/tests/ui/traits/bound/impl-comparison-duplicates.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Tests that type parameter bounds on an implementation need not match the // trait exactly, as long as the implementation doesn't demand *more* bounds // than the trait. diff --git a/tests/ui/traits/bound/recursion.rs b/tests/ui/traits/bound/recursion.rs index 0023ff654e84c..767040dff3f73 100644 --- a/tests/ui/traits/bound/recursion.rs +++ b/tests/ui/traits/bound/recursion.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait I { fn i(&self) -> Self; } diff --git a/tests/ui/traits/composition-trivial.rs b/tests/ui/traits/composition-trivial.rs index 90e5dcd68e8c4..41e6a55607449 100644 --- a/tests/ui/traits/composition-trivial.rs +++ b/tests/ui/traits/composition-trivial.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Foo { diff --git a/tests/ui/traits/cycle-generic-bound.rs b/tests/ui/traits/cycle-generic-bound.rs index 9241f3789d72a..77685c26da242 100644 --- a/tests/ui/traits/cycle-generic-bound.rs +++ b/tests/ui/traits/cycle-generic-bound.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Regression test for #15477. This test just needs to compile. // pretty-expanded FIXME #23616 diff --git a/tests/ui/traits/default-method/bound-subst4.rs b/tests/ui/traits/default-method/bound-subst4.rs index ef13306458255..6bc4cf0ef805c 100644 --- a/tests/ui/traits/default-method/bound-subst4.rs +++ b/tests/ui/traits/default-method/bound-subst4.rs @@ -4,7 +4,7 @@ trait A { fn g(&self, x: usize) -> usize { x } - fn h(&self, x: T) { } + fn h(&self, x: T) { } //~ WARN method `h` is never used } impl A for isize { } diff --git a/tests/ui/traits/default-method/bound-subst4.stderr b/tests/ui/traits/default-method/bound-subst4.stderr new file mode 100644 index 0000000000000..548c46f123322 --- /dev/null +++ b/tests/ui/traits/default-method/bound-subst4.stderr @@ -0,0 +1,13 @@ +warning: method `h` is never used + --> $DIR/bound-subst4.rs:7:8 + | +LL | trait A { + | - method in this trait +LL | fn g(&self, x: usize) -> usize { x } +LL | fn h(&self, x: T) { } + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/default-method/mut.rs b/tests/ui/traits/default-method/mut.rs index 5f8e983b09cfb..3294b96561fd1 100644 --- a/tests/ui/traits/default-method/mut.rs +++ b/tests/ui/traits/default-method/mut.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(unused_assignments)] // pretty-expanded FIXME #23616 diff --git a/tests/ui/traits/impl-inherent-prefer-over-trait.rs b/tests/ui/traits/impl-inherent-prefer-over-trait.rs index 82760788897a5..f03e730d091eb 100644 --- a/tests/ui/traits/impl-inherent-prefer-over-trait.rs +++ b/tests/ui/traits/impl-inherent-prefer-over-trait.rs @@ -3,7 +3,7 @@ struct Foo; trait Trait { - fn bar(&self); + fn bar(&self); //~ WARN method `bar` is never used } // Inherent impls should be preferred over trait ones. diff --git a/tests/ui/traits/impl-inherent-prefer-over-trait.stderr b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr new file mode 100644 index 0000000000000..f0bb21402d873 --- /dev/null +++ b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr @@ -0,0 +1,12 @@ +warning: method `bar` is never used + --> $DIR/impl-inherent-prefer-over-trait.rs:6:8 + | +LL | trait Trait { + | ----- method in this trait +LL | fn bar(&self); + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/impl-object-overlap-issue-23853.rs b/tests/ui/traits/impl-object-overlap-issue-23853.rs index e490967b69047..c0d3af11443d4 100644 --- a/tests/ui/traits/impl-object-overlap-issue-23853.rs +++ b/tests/ui/traits/impl-object-overlap-issue-23853.rs @@ -5,7 +5,7 @@ // including `Bar`, but the object type `Bar` also implicitly supplies // this context. -trait Foo { fn dummy(&self) { } } +trait Foo { fn dummy(&self) { } } //~ WARN method `dummy` is never used trait Bar: Foo { } diff --git a/tests/ui/traits/impl-object-overlap-issue-23853.stderr b/tests/ui/traits/impl-object-overlap-issue-23853.stderr new file mode 100644 index 0000000000000..9fa7a36816e4d --- /dev/null +++ b/tests/ui/traits/impl-object-overlap-issue-23853.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/impl-object-overlap-issue-23853.rs:8:16 + | +LL | trait Foo { fn dummy(&self) { } } + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/impl.rs b/tests/ui/traits/impl.rs index f512d91ebeb4a..7bec1b6c9ff4f 100644 --- a/tests/ui/traits/impl.rs +++ b/tests/ui/traits/impl.rs @@ -9,7 +9,7 @@ use traitimpl::Bar; static mut COUNT: usize = 1; trait T { - fn t(&self) {} + fn t(&self) {} //~ WARN method `t` is never used } impl<'a> dyn T+'a { diff --git a/tests/ui/traits/impl.stderr b/tests/ui/traits/impl.stderr new file mode 100644 index 0000000000000..98b6fb03d836f --- /dev/null +++ b/tests/ui/traits/impl.stderr @@ -0,0 +1,12 @@ +warning: method `t` is never used + --> $DIR/impl.rs:12:8 + | +LL | trait T { + | - method in this trait +LL | fn t(&self) {} + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/issue-38033.rs b/tests/ui/traits/issue-38033.rs index 16b867ec88f17..4d76df1e8d5bc 100644 --- a/tests/ui/traits/issue-38033.rs +++ b/tests/ui/traits/issue-38033.rs @@ -19,7 +19,7 @@ trait IntoFuture { type Item; type Error; - fn into_future(self) -> Self::Future; + fn into_future(self) -> Self::Future; //~ WARN method `into_future` is never used } impl IntoFuture for F { diff --git a/tests/ui/traits/issue-38033.stderr b/tests/ui/traits/issue-38033.stderr new file mode 100644 index 0000000000000..05385e8cf4d9d --- /dev/null +++ b/tests/ui/traits/issue-38033.stderr @@ -0,0 +1,13 @@ +warning: method `into_future` is never used + --> $DIR/issue-38033.rs:22:8 + | +LL | trait IntoFuture { + | ---------- method in this trait +... +LL | fn into_future(self) -> Self::Future; + | ^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/issue-56488.rs b/tests/ui/traits/issue-56488.rs index e2f3996927b7f..8b68f314c04dd 100644 --- a/tests/ui/traits/issue-56488.rs +++ b/tests/ui/traits/issue-56488.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(trait_alias)] diff --git a/tests/ui/traits/issue-59029-2.rs b/tests/ui/traits/issue-59029-2.rs index 2bdb128d8c4c8..fca9f1f13c9de 100644 --- a/tests/ui/traits/issue-59029-2.rs +++ b/tests/ui/traits/issue-59029-2.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(trait_alias)] trait Svc { type Res; } diff --git a/tests/ui/traits/issue-6128.rs b/tests/ui/traits/issue-6128.rs index 07d92f8f8a016..f5fa0de809a19 100644 --- a/tests/ui/traits/issue-6128.rs +++ b/tests/ui/traits/issue-6128.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; trait Graph { - fn f(&self, _: Edge); + fn f(&self, _: Edge); //~ WARN methods `f` and `g` are never used fn g(&self, _: Node); } diff --git a/tests/ui/traits/issue-6128.stderr b/tests/ui/traits/issue-6128.stderr new file mode 100644 index 0000000000000..c9518ea41ea70 --- /dev/null +++ b/tests/ui/traits/issue-6128.stderr @@ -0,0 +1,14 @@ +warning: methods `f` and `g` are never used + --> $DIR/issue-6128.rs:6:8 + | +LL | trait Graph { + | ----- methods in this trait +LL | fn f(&self, _: Edge); + | ^ +LL | fn g(&self, _: Node); + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs b/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs index f845e198aa574..e9ae8ab012a09 100644 --- a/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs +++ b/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs @@ -6,7 +6,7 @@ use std::cell::RefCell; -trait Foo { +trait Foo { //~ WARN trait `Foo` is never used fn foo(&self) {} } diff --git a/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr new file mode 100644 index 0000000000000..25313a477f7af --- /dev/null +++ b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr @@ -0,0 +1,10 @@ +warning: trait `Foo` is never used + --> $DIR/multidispatch-conditional-impl-not-considered.rs:9:7 + | +LL | trait Foo { + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/multidispatch-infer-convert-target.rs b/tests/ui/traits/multidispatch-infer-convert-target.rs index 626e1ae71bc2f..a3653dea2cbdf 100644 --- a/tests/ui/traits/multidispatch-infer-convert-target.rs +++ b/tests/ui/traits/multidispatch-infer-convert-target.rs @@ -5,7 +5,7 @@ use std::mem; trait Convert { - fn convert(&self) -> Target; + fn convert(&self) -> Target; //~ WARN method `convert` is never used } impl Convert for i16 { diff --git a/tests/ui/traits/multidispatch-infer-convert-target.stderr b/tests/ui/traits/multidispatch-infer-convert-target.stderr new file mode 100644 index 0000000000000..c8c1b64271950 --- /dev/null +++ b/tests/ui/traits/multidispatch-infer-convert-target.stderr @@ -0,0 +1,12 @@ +warning: method `convert` is never used + --> $DIR/multidispatch-infer-convert-target.rs:8:8 + | +LL | trait Convert { + | ------- method in this trait +LL | fn convert(&self) -> Target; + | ^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/negative-impls/negative-specializes-negative.rs b/tests/ui/traits/negative-impls/negative-specializes-negative.rs index 35297ab124ed0..01829e4130115 100644 --- a/tests/ui/traits/negative-impls/negative-specializes-negative.rs +++ b/tests/ui/traits/negative-impls/negative-specializes-negative.rs @@ -3,7 +3,7 @@ // Test a negative impl that "specializes" another negative impl. // -// run-pass +// check-pass trait MyTrait {} diff --git a/tests/ui/traits/trait-upcasting/lifetime.rs b/tests/ui/traits/trait-upcasting/lifetime.rs index 9825158c2dd38..6486ec3891c68 100644 --- a/tests/ui/traits/trait-upcasting/lifetime.rs +++ b/tests/ui/traits/trait-upcasting/lifetime.rs @@ -7,7 +7,7 @@ trait Foo: PartialEq + std::fmt::Debug + Send + Sync { 10 } - fn z(&self) -> i32 { + fn z(&self) -> i32 { //~ WARN methods `z` and `y` are never used 11 } @@ -21,7 +21,7 @@ trait Bar: Foo { 20 } - fn w(&self) -> i32 { + fn w(&self) -> i32 { //~ WARN method `w` is never used 21 } } diff --git a/tests/ui/traits/trait-upcasting/lifetime.stderr b/tests/ui/traits/trait-upcasting/lifetime.stderr new file mode 100644 index 0000000000000..ca8f9cf63f3e7 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/lifetime.stderr @@ -0,0 +1,25 @@ +warning: methods `z` and `y` are never used + --> $DIR/lifetime.rs:10:8 + | +LL | trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + | --- methods in this trait +... +LL | fn z(&self) -> i32 { + | ^ +... +LL | fn y(&self) -> i32 { + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: method `w` is never used + --> $DIR/lifetime.rs:24:8 + | +LL | trait Bar: Foo { + | --- method in this trait +... +LL | fn w(&self) -> i32 { + | ^ + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.rs b/tests/ui/traits/trait-upcasting/replace-vptr.rs index 9ccfc9306ac0c..5ef65786bb705 100644 --- a/tests/ui/traits/trait-upcasting/replace-vptr.rs +++ b/tests/ui/traits/trait-upcasting/replace-vptr.rs @@ -3,7 +3,7 @@ #![feature(trait_upcasting)] trait A { - fn foo_a(&self); + fn foo_a(&self); //~ WARN method `foo_a` is never used } trait B { @@ -11,7 +11,7 @@ trait B { } trait C: A + B { - fn foo_c(&self); + fn foo_c(&self); //~ WARN method `foo_c` is never used } struct S(i32); diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.stderr b/tests/ui/traits/trait-upcasting/replace-vptr.stderr new file mode 100644 index 0000000000000..823094761b385 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/replace-vptr.stderr @@ -0,0 +1,20 @@ +warning: method `foo_a` is never used + --> $DIR/replace-vptr.rs:6:8 + | +LL | trait A { + | - method in this trait +LL | fn foo_a(&self); + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: method `foo_c` is never used + --> $DIR/replace-vptr.rs:14:8 + | +LL | trait C: A + B { + | - method in this trait +LL | fn foo_c(&self); + | ^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/use-before-def.rs b/tests/ui/traits/use-before-def.rs index 1ee2b941909f4..e52dc53fbab79 100644 --- a/tests/ui/traits/use-before-def.rs +++ b/tests/ui/traits/use-before-def.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![allow(non_camel_case_types)] // Issue #1761 diff --git a/tests/ui/traits/wf-object/reverse-order.rs b/tests/ui/traits/wf-object/reverse-order.rs index 74b2ef48533d2..e90c8763d651f 100644 --- a/tests/ui/traits/wf-object/reverse-order.rs +++ b/tests/ui/traits/wf-object/reverse-order.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // Ensure that `dyn $($AutoTrait)+ ObjSafe` is well-formed. diff --git a/tests/ui/trivial_casts-rpass.rs b/tests/ui/trivial_casts-rpass.rs index 8e49468bf0c45..4653a8df802da 100644 --- a/tests/ui/trivial_casts-rpass.rs +++ b/tests/ui/trivial_casts-rpass.rs @@ -4,7 +4,7 @@ #![allow(trivial_casts, trivial_numeric_casts)] trait Foo { - fn foo(&self) {} + fn foo(&self) {} //~ WARN method `foo` is never used } pub struct Bar; diff --git a/tests/ui/trivial_casts-rpass.stderr b/tests/ui/trivial_casts-rpass.stderr new file mode 100644 index 0000000000000..74698b61ab4a4 --- /dev/null +++ b/tests/ui/trivial_casts-rpass.stderr @@ -0,0 +1,12 @@ +warning: method `foo` is never used + --> $DIR/trivial_casts-rpass.rs:7:8 + | +LL | trait Foo { + | --- method in this trait +LL | fn foo(&self) {} + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/type-alias-impl-trait/issue-58887.rs b/tests/ui/type-alias-impl-trait/issue-58887.rs index 9675867656a96..68d85ed6b0f9b 100644 --- a/tests/ui/type-alias-impl-trait/issue-58887.rs +++ b/tests/ui/type-alias-impl-trait/issue-58887.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass #![feature(impl_trait_in_assoc_type)] diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed index 5be6ff8e7e14e..700e4f2542384 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs index d7072aa118161..66ba9b24dac2f 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr index 54e62f34fbaa3..f012120e550d7 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-inherent-impl-ampersand-rust2015.rs:13:17 + --> $DIR/where-clause-inherent-impl-ampersand-rust2015.rs:14:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed index 0f1be586589e2..56682db3b0b43 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed @@ -1,5 +1,6 @@ // edition:2018 // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs index 59f7e472e2d34..5302b2f1576b6 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs @@ -1,5 +1,6 @@ // edition:2018 // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr index 36f3e9ef14527..7d675dd41e904 100644 --- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr +++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-inherent-impl-ampersand-rust2018.rs:14:17 + --> $DIR/where-clause-inherent-impl-ampersand-rust2018.rs:15:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed index 55c7470960eb2..f3adc7e7fad32 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs index 42a35b0216119..1e084e9ad41bb 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(dead_code)] trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr index 92b7a9c2af893..8aa0e52c688db 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-trait-impl-region-2015.rs:10:17 + --> $DIR/where-clause-trait-impl-region-2015.rs:11:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed index 09b96fe5ea42a..dd8074abed728 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed @@ -1,6 +1,8 @@ // run-rustfix // edition:2018 +#![allow(dead_code)] + trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs index 445f38cbee187..4fc9c71b17943 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs @@ -1,6 +1,8 @@ // run-rustfix // edition:2018 +#![allow(dead_code)] + trait WithType {} trait WithRegion<'a> { } diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr index 63d8b99ed18fb..22940d0b0b18d 100644 --- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr +++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr @@ -1,5 +1,5 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/where-clause-trait-impl-region-2018.rs:11:17 + --> $DIR/where-clause-trait-impl-region-2018.rs:13:17 | LL | T: WithType<&u32> | ^ explicit lifetime name needed here diff --git a/tests/ui/where-clauses/issue-50825-1.rs b/tests/ui/where-clauses/issue-50825-1.rs index ee4316029a829..2ee34ad714ede 100644 --- a/tests/ui/where-clauses/issue-50825-1.rs +++ b/tests/ui/where-clauses/issue-50825-1.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // regression test for issue #50825 // Make sure that the `impl` bound (): X is preferred over // the (): X bound in the where clause. diff --git a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs index ea60fa708764f..65fd2f3096c93 100644 --- a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs +++ b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // pretty-expanded FIXME #23616 trait Bound { diff --git a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs index 6fc570b9b5b9b..a7ce0590fcd46 100644 --- a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs +++ b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs @@ -3,7 +3,7 @@ // pretty-expanded FIXME #23616 -trait TheTrait { fn dummy(&self) { } } +trait TheTrait { fn dummy(&self) { } } //~ WARN method `dummy` is never used impl TheTrait for &'static isize { } diff --git a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr new file mode 100644 index 0000000000000..a9fe11ea6b316 --- /dev/null +++ b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/where-clause-early-bound-lifetimes.rs:6:21 + | +LL | trait TheTrait { fn dummy(&self) { } } + | -------- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs b/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs index daa3c8dd8e367..8f9c6fbff3d8f 100644 --- a/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs +++ b/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs @@ -2,7 +2,7 @@ #![allow(unused_variables)] // pretty-expanded FIXME #23616 -trait Foo { fn dummy(&self, arg: T) { } } +trait Foo { fn dummy(&self, arg: T) { } } //~ WARN method `dummy` is never used trait Bar { fn method(&self) where A: Foo; diff --git a/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr new file mode 100644 index 0000000000000..0d09cb9de3f6b --- /dev/null +++ b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr @@ -0,0 +1,12 @@ +warning: method `dummy` is never used + --> $DIR/where-clause-method-substituion-rpass.rs:5:19 + | +LL | trait Foo { fn dummy(&self, arg: T) { } } + | --- ^^^^^ + | | + | method in this trait + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed index 2f47c0d91fa96..4e1aa59aac0f0 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed @@ -1,6 +1,8 @@ // check-pass // run-rustfix +#![allow(dead_code)] + trait Trait { // Fine. type Assoc where u32: Copy; diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs index b20aa9398b58f..05b2f8c82a456 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs @@ -1,6 +1,8 @@ // check-pass // run-rustfix +#![allow(dead_code)] + trait Trait { // Fine. type Assoc where u32: Copy; diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr index b4de051845fa6..6ff9d2dd73b5b 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr @@ -1,5 +1,5 @@ warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:13:16 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:15:16 | LL | type Assoc where u32: Copy = (); | ^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:16:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:18:17 | LL | type Assoc2 where u32: Copy = () where i32: Copy; | ^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL + type Assoc2 = () where i32: Copy, u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:24:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:26:17 | LL | type Assoc2 where u32: Copy, i32: Copy = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed index d171eba50b788..940e2cc8e9750 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed @@ -1,6 +1,7 @@ // check-pass // run-rustfix +#![allow(dead_code)] #![feature(associated_type_defaults)] trait Trait { diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs index 59afee65794c4..7001a9245a5f3 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs @@ -1,6 +1,7 @@ // check-pass // run-rustfix +#![allow(dead_code)] #![feature(associated_type_defaults)] trait Trait { diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr index a81cb8c8cd62e..9e9967ef7391a 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr @@ -1,5 +1,5 @@ warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-trait.rs:8:16 + --> $DIR/where-clause-placement-assoc-type-in-trait.rs:9:16 | LL | type Assoc where u32: Copy = (); | ^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-trait.rs:11:17 + --> $DIR/where-clause-placement-assoc-type-in-trait.rs:12:17 | LL | type Assoc2 where u32: Copy = () where i32: Copy; | ^^^^^^^^^^^^^^^ From 4451bf4d678c67755c153995d638559a76469af2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 7 Jan 2024 17:53:20 -0500 Subject: [PATCH 084/101] Use a better set of targets for blessing mir-opt tests --- src/bootstrap/src/core/build_steps/compile.rs | 32 ++- src/bootstrap/src/core/build_steps/test.rs | 119 +++----- src/bootstrap/src/core/builder.rs | 256 ++++++++++-------- src/tools/compiletest/src/runtest.rs | 2 + .../inline/cycle.g.Inline.panic-abort.diff | 21 +- .../inline/cycle.g.Inline.panic-unwind.diff | 29 +- tests/mir-opt/inline/cycle.rs | 4 +- ...cycle_generic.main.Inline.panic-abort.diff | 6 +- ...ycle_generic.main.Inline.panic-unwind.diff | 6 +- .../issue_99325.main.built.after.32bit.mir | 4 +- .../issue_99325.main.built.after.64bit.mir | 4 +- 11 files changed, 220 insertions(+), 263 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index ddbe18ab8388d..3c0d074807d39 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -97,6 +97,20 @@ impl Std { is_for_mir_opt_tests: false, } } + + fn copy_extra_objects( + &self, + builder: &Builder<'_>, + compiler: &Compiler, + target: TargetSelection, + ) -> Vec<(PathBuf, DependencyType)> { + let mut deps = Vec::new(); + if !self.is_for_mir_opt_tests { + deps.extend(copy_third_party_objects(builder, &compiler, target)); + deps.extend(copy_self_contained_objects(builder, &compiler, target)); + } + deps + } } impl Step for Std { @@ -159,8 +173,7 @@ impl Step for Std { { builder.info("WARNING: Using a potentially old libstd. This may not behave well."); - copy_third_party_objects(builder, &compiler, target); - copy_self_contained_objects(builder, &compiler, target); + self.copy_extra_objects(builder, &compiler, target); builder.ensure(StdLink::from_std(self, compiler)); return; @@ -193,15 +206,13 @@ impl Step for Std { // Even if we're not building std this stage, the new sysroot must // still contain the third party objects needed by various targets. - copy_third_party_objects(builder, &compiler, target); - copy_self_contained_objects(builder, &compiler, target); + self.copy_extra_objects(builder, &compiler, target); builder.ensure(StdLink::from_std(self, compiler_to_use)); return; } - target_deps.extend(copy_third_party_objects(builder, &compiler, target)); - target_deps.extend(copy_self_contained_objects(builder, &compiler, target)); + target_deps.extend(self.copy_extra_objects(builder, &compiler, target)); // The LLD wrappers and `rust-lld` are self-contained linking components that can be // necessary to link the stdlib on some targets. We'll also need to copy these binaries to @@ -222,9 +233,12 @@ impl Step for Std { } } + // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build + // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the + // fact that this is a check build integrates nicely with run_cargo. let mut cargo = if self.is_for_mir_opt_tests { - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustc"); - cargo.arg("-p").arg("std").arg("--crate-type=lib"); + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "check"); + cargo.rustflag("-Zalways-encode-mir"); std_cargo(builder, target, compiler.stage, &mut cargo); cargo } else { @@ -257,7 +271,7 @@ impl Step for Std { vec![], &libstd_stamp(builder, compiler, target), target_deps, - false, + self.is_for_mir_opt_tests, // is_check false, ); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 04728e2e00dcc..e1a1c416ae993 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -25,7 +25,6 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; use crate::core::config::flags::Subcommand; use crate::core::config::TargetSelection; -use crate::utils; use crate::utils::cache::{Interned, INTERNER}; use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ @@ -38,23 +37,6 @@ use crate::{envify, CLang, DocTests, GitRepo, Mode}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; -// mir-opt tests have different variants depending on whether a target is 32bit or 64bit, and -// blessing them requires blessing with each target. To aid developers, when blessing the mir-opt -// test suite the corresponding target of the opposite pointer size is also blessed. -// -// This array serves as the known mappings between 32bit and 64bit targets. If you're developing on -// a target where a target with the opposite pointer size exists, feel free to add it here. -const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[ - // (32bit, 64bit) - ("i686-unknown-linux-gnu", "x86_64-unknown-linux-gnu"), - ("i686-unknown-linux-musl", "x86_64-unknown-linux-musl"), - ("i686-pc-windows-msvc", "x86_64-pc-windows-msvc"), - ("i686-pc-windows-gnu", "x86_64-pc-windows-gnu"), - // ARM Macs don't have a corresponding 32-bit target that they can (easily) - // build for, so there is no entry for "aarch64-apple-darwin" here. - // Likewise, i686 for macOS is no longer possible to build. -]; - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct CrateBootstrap { path: Interned, @@ -1487,46 +1469,19 @@ impl Step for MirOpt { }) }; - // We use custom logic to bless the mir-opt suite: mir-opt tests have multiple variants - // (32bit vs 64bit, and panic=abort vs panic=unwind), and all of them needs to be blessed. - // When blessing, we try best-effort to also bless the other variants, to aid developers. if builder.config.cmd.bless() { - let targets = MIR_OPT_BLESS_TARGET_MAPPING - .iter() - .filter(|(target_32bit, target_64bit)| { - *target_32bit == &*self.target.triple || *target_64bit == &*self.target.triple - }) - .next() - .map(|(target_32bit, target_64bit)| { - let target_32bit = TargetSelection::from_user(target_32bit); - let target_64bit = TargetSelection::from_user(target_64bit); - - // Running compiletest requires a C compiler to be available, but it might not - // have been detected by bootstrap if the target we're testing wasn't in the - // --target flags. - if !builder.cc.borrow().contains_key(&target_32bit) { - utils::cc_detect::find_target(builder, target_32bit); - } - if !builder.cc.borrow().contains_key(&target_64bit) { - utils::cc_detect::find_target(builder, target_64bit); - } - - vec![target_32bit, target_64bit] - }) - .unwrap_or_else(|| { - eprintln!( - "\ -Note that not all variants of mir-opt tests are going to be blessed, as no mapping between -a 32bit and a 64bit target was found for {target}. -You can add that mapping by changing MIR_OPT_BLESS_TARGET_MAPPING in src/bootstrap/test.rs", - target = self.target, - ); - vec![self.target] - }); - - for target in targets { - run(target); + crate::utils::cc_detect::find_target(builder, self.compiler.host); + // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort, + // but while we're at it we might as well flex our cross-compilation support. This + // selection covers all our tier 1 operating systems and architectures using only tier + // 1 targets. + + for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] { + run(TargetSelection::from_user(target)); + } + for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] { + let target = TargetSelection::from_user(target); let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget { compiler: self.compiler, base: target, @@ -1616,27 +1571,27 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target }); } - if suite == "mir-opt" { - builder.ensure(compile::Std::new_for_mir_opt_tests(compiler, target)); - } else { - builder.ensure(compile::Std::new(compiler, target)); - } + // Also provide `rust_test_helpers` for the host. + builder.ensure(TestHelpers { target: compiler.host }); // ensure that `libproc_macro` is available on the host. builder.ensure(compile::Std::new(compiler, compiler.host)); - // Also provide `rust_test_helpers` for the host. - builder.ensure(TestHelpers { target: compiler.host }); - // As well as the target, except for plain wasm32, which can't build it if suite != "mir-opt" && !target.contains("wasm") && !target.contains("emscripten") { builder.ensure(TestHelpers { target }); } - builder.ensure(RemoteCopyLibs { compiler, target }); - let mut cmd = builder.tool_cmd(Tool::Compiletest); + if suite == "mir-opt" { + builder.ensure(compile::Std::new_for_mir_opt_tests(compiler, target)); + } else { + builder.ensure(compile::Std::new(compiler, target)); + } + + builder.ensure(RemoteCopyLibs { compiler, target }); + // compiletest currently has... a lot of arguments, so let's just pass all // of them! @@ -1745,11 +1700,13 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests)); flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string())); - if let Some(linker) = builder.linker(target) { - cmd.arg("--target-linker").arg(linker); - } - if let Some(linker) = builder.linker(compiler.host) { - cmd.arg("--host-linker").arg(linker); + if suite != "mir-opt" { + if let Some(linker) = builder.linker(target) { + cmd.arg("--target-linker").arg(linker); + } + if let Some(linker) = builder.linker(compiler.host) { + cmd.arg("--host-linker").arg(linker); + } } let mut hostflags = flags.clone(); @@ -1936,15 +1893,17 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient)); } - // Running a C compiler on MSVC requires a few env vars to be set, to be - // sure to set them here. - // - // Note that if we encounter `PATH` we make sure to append to our own `PATH` - // rather than stomp over it. - if !builder.config.dry_run() && target.is_msvc() { - for &(ref k, ref v) in builder.cc.borrow()[&target].env() { - if k != "PATH" { - cmd.env(k, v); + if suite != "mir-opt" { + // Running a C compiler on MSVC requires a few env vars to be set, to be + // sure to set them here. + // + // Note that if we encounter `PATH` we make sure to append to our own `PATH` + // rather than stomp over it. + if !builder.config.dry_run() && target.is_msvc() { + for &(ref k, ref v) in builder.cc.borrow()[&target].env() { + if k != "PATH" { + cmd.env(k, v); + } } } } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index dac8393de6b4c..4bb8ed2fa67fb 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1646,76 +1646,12 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_WRAPPER_REAL", existing_wrapper); } - // Dealing with rpath here is a little special, so let's go into some - // detail. First off, `-rpath` is a linker option on Unix platforms - // which adds to the runtime dynamic loader path when looking for - // dynamic libraries. We use this by default on Unix platforms to ensure - // that our nightlies behave the same on Windows, that is they work out - // of the box. This can be disabled by setting `rpath = false` in `[rust]` - // table of `config.toml` - // - // Ok, so the astute might be wondering "why isn't `-C rpath` used - // here?" and that is indeed a good question to ask. This codegen - // option is the compiler's current interface to generating an rpath. - // Unfortunately it doesn't quite suffice for us. The flag currently - // takes no value as an argument, so the compiler calculates what it - // should pass to the linker as `-rpath`. This unfortunately is based on - // the **compile time** directory structure which when building with - // Cargo will be very different than the runtime directory structure. - // - // All that's a really long winded way of saying that if we use - // `-Crpath` then the executables generated have the wrong rpath of - // something like `$ORIGIN/deps` when in fact the way we distribute - // rustc requires the rpath to be `$ORIGIN/../lib`. - // - // So, all in all, to set up the correct rpath we pass the linker - // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it - // fun to pass a flag to a tool to pass a flag to pass a flag to a tool - // to change a flag in a binary? - if self.config.rpath_enabled(target) && helpers::use_host_linker(target) { - let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap(); - let rpath = if target.contains("apple") { - // Note that we need to take one extra step on macOS to also pass - // `-Wl,-instal_name,@rpath/...` to get things to work right. To - // do that we pass a weird flag to the compiler to get it to do - // so. Note that this is definitely a hack, and we should likely - // flesh out rpath support more fully in the future. - rustflags.arg("-Zosx-rpath-install-name"); - Some(format!("-Wl,-rpath,@loader_path/../{libdir}")) - } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") { - rustflags.arg("-Clink-args=-Wl,-z,origin"); - Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}")) - } else { - None - }; - if let Some(rpath) = rpath { - rustflags.arg(&format!("-Clink-args={rpath}")); - } - } - cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string()); if let Some(stack_protector) = &self.config.rust_stack_protector { rustflags.arg(&format!("-Zstack-protector={stack_protector}")); } - for arg in linker_args(self, compiler.host, LldThreads::Yes) { - hostflags.arg(&arg); - } - - if let Some(target_linker) = self.linker(target) { - let target = crate::envify(&target.triple); - cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker); - } - // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not - // `linker_args` here. - for flag in linker_flags(self, target, LldThreads::Yes) { - rustflags.arg(&flag); - } - for arg in linker_args(self, target, LldThreads::Yes) { - rustdocflags.arg(&arg); - } - if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc { cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)); } @@ -1731,10 +1667,6 @@ impl<'a> Builder<'a> { if let Some(opt_level) = &self.config.rust_optimize.get_opt_level() { cargo.env(profile_var("OPT_LEVEL"), opt_level); } - if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz") - { - rustflags.arg("-Clink-arg=-gz"); - } cargo.env( profile_var("DEBUG_ASSERTIONS"), if mode == Mode::Std { @@ -1940,55 +1872,15 @@ impl<'a> Builder<'a> { rustflags.arg("-Wrustc::internal"); } - // Throughout the build Cargo can execute a number of build scripts - // compiling C/C++ code and we need to pass compilers, archivers, flags, etc - // obtained previously to those build scripts. - // Build scripts use either the `cc` crate or `configure/make` so we pass - // the options through environment variables that are fetched and understood by both. - // - // FIXME: the guard against msvc shouldn't need to be here - if target.is_msvc() { - if let Some(ref cl) = self.config.llvm_clang_cl { - cargo.env("CC", cl).env("CXX", cl); - } - } else { - let ccache = self.config.ccache.as_ref(); - let ccacheify = |s: &Path| { - let ccache = match ccache { - Some(ref s) => s, - None => return s.display().to_string(), - }; - // FIXME: the cc-rs crate only recognizes the literal strings - // `ccache` and `sccache` when doing caching compilations, so we - // mirror that here. It should probably be fixed upstream to - // accept a new env var or otherwise work with custom ccache - // vars. - match &ccache[..] { - "ccache" | "sccache" => format!("{} {}", ccache, s.display()), - _ => s.display().to_string(), - } - }; - let triple_underscored = target.triple.replace("-", "_"); - let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{triple_underscored}"), &cc); - - let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" "); - cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags); - - if let Some(ar) = self.ar(target) { - let ranlib = format!("{} s", ar.display()); - cargo - .env(format!("AR_{triple_underscored}"), ar) - .env(format!("RANLIB_{triple_underscored}"), ranlib); - } - - if let Ok(cxx) = self.cxx(target) { - let cxx = ccacheify(&cxx); - let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" "); - cargo - .env(format!("CXX_{triple_underscored}"), &cxx) - .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags); - } + if cmd != "check" { + self.configure_linker( + compiler, + target, + &mut cargo, + &mut rustflags, + &mut rustdocflags, + &mut hostflags, + ); } // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc @@ -2142,6 +2034,136 @@ impl<'a> Builder<'a> { Cargo { command: cargo, rustflags, rustdocflags, hostflags, allow_features } } + fn configure_linker( + &self, + compiler: Compiler, + target: TargetSelection, + cargo: &mut Command, + rustflags: &mut Rustflags, + rustdocflags: &mut Rustflags, + hostflags: &mut HostFlags, + ) { + // Dealing with rpath here is a little special, so let's go into some + // detail. First off, `-rpath` is a linker option on Unix platforms + // which adds to the runtime dynamic loader path when looking for + // dynamic libraries. We use this by default on Unix platforms to ensure + // that our nightlies behave the same on Windows, that is they work out + // of the box. This can be disabled by setting `rpath = false` in `[rust]` + // table of `config.toml` + // + // Ok, so the astute might be wondering "why isn't `-C rpath` used + // here?" and that is indeed a good question to ask. This codegen + // option is the compiler's current interface to generating an rpath. + // Unfortunately it doesn't quite suffice for us. The flag currently + // takes no value as an argument, so the compiler calculates what it + // should pass to the linker as `-rpath`. This unfortunately is based on + // the **compile time** directory structure which when building with + // Cargo will be very different than the runtime directory structure. + // + // All that's a really long winded way of saying that if we use + // `-Crpath` then the executables generated have the wrong rpath of + // something like `$ORIGIN/deps` when in fact the way we distribute + // rustc requires the rpath to be `$ORIGIN/../lib`. + // + // So, all in all, to set up the correct rpath we pass the linker + // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it + // fun to pass a flag to a tool to pass a flag to pass a flag to a tool + // to change a flag in a binary? + if self.config.rpath_enabled(target) && helpers::use_host_linker(target) { + let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap(); + let rpath = if target.contains("apple") { + // Note that we need to take one extra step on macOS to also pass + // `-Wl,-instal_name,@rpath/...` to get things to work right. To + // do that we pass a weird flag to the compiler to get it to do + // so. Note that this is definitely a hack, and we should likely + // flesh out rpath support more fully in the future. + rustflags.arg("-Zosx-rpath-install-name"); + Some(format!("-Wl,-rpath,@loader_path/../{libdir}")) + } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") { + rustflags.arg("-Clink-args=-Wl,-z,origin"); + Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}")) + } else { + None + }; + if let Some(rpath) = rpath { + rustflags.arg(&format!("-Clink-args={rpath}")); + } + } + + for arg in linker_args(self, compiler.host, LldThreads::Yes) { + hostflags.arg(&arg); + } + + if let Some(target_linker) = self.linker(target) { + let target = crate::envify(&target.triple); + cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker); + } + // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not + // `linker_args` here. + for flag in linker_flags(self, target, LldThreads::Yes) { + rustflags.arg(&flag); + } + for arg in linker_args(self, target, LldThreads::Yes) { + rustdocflags.arg(&arg); + } + + if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz") + { + rustflags.arg("-Clink-arg=-gz"); + } + + // Throughout the build Cargo can execute a number of build scripts + // compiling C/C++ code and we need to pass compilers, archivers, flags, etc + // obtained previously to those build scripts. + // Build scripts use either the `cc` crate or `configure/make` so we pass + // the options through environment variables that are fetched and understood by both. + // + // FIXME: the guard against msvc shouldn't need to be here + if target.is_msvc() { + if let Some(ref cl) = self.config.llvm_clang_cl { + cargo.env("CC", cl).env("CXX", cl); + } + } else { + let ccache = self.config.ccache.as_ref(); + let ccacheify = |s: &Path| { + let ccache = match ccache { + Some(ref s) => s, + None => return s.display().to_string(), + }; + // FIXME: the cc-rs crate only recognizes the literal strings + // `ccache` and `sccache` when doing caching compilations, so we + // mirror that here. It should probably be fixed upstream to + // accept a new env var or otherwise work with custom ccache + // vars. + match &ccache[..] { + "ccache" | "sccache" => format!("{} {}", ccache, s.display()), + _ => s.display().to_string(), + } + }; + let triple_underscored = target.triple.replace("-", "_"); + let cc = ccacheify(&self.cc(target)); + cargo.env(format!("CC_{triple_underscored}"), &cc); + + let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" "); + cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags); + + if let Some(ar) = self.ar(target) { + let ranlib = format!("{} s", ar.display()); + cargo + .env(format!("AR_{triple_underscored}"), ar) + .env(format!("RANLIB_{triple_underscored}"), ranlib); + } + + if let Ok(cxx) = self.cxx(target) { + let cxx = ccacheify(&cxx); + let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" "); + cargo + .env(format!("CXX_{triple_underscored}"), &cxx) + .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags); + } + } + } + /// Ensure that a given step is built, returning its output. This will /// cache the step, so it is safe (and good!) to call this as often as /// needed to ensure that all dependencies are built. diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8be4def15dedc..00ebd91f3871f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2467,6 +2467,8 @@ impl<'test> TestCx<'test> { "-Zvalidate-mir", "-Zlint-mir", "-Zdump-mir-exclude-pass-number", + "--crate-type=rlib", + "-Clink-dead-code", ]); if let Some(pass) = &self.props.mir_unit_test { rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]); diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff index 8f2baf4a3b61c..1be0a4f2d2976 100644 --- a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff @@ -4,35 +4,16 @@ fn g() -> () { let mut _0: (); let _1: (); -+ let mut _2: fn() {main}; -+ scope 1 (inlined f::) { -+ debug g => _2; -+ let mut _3: &fn() {main}; -+ let _4: (); -+ } bb0: { StorageLive(_1); -- _1 = f::(main) -> [return: bb1, unwind unreachable]; -+ StorageLive(_2); -+ _2 = main; -+ StorageLive(_4); -+ StorageLive(_3); -+ _3 = &_2; -+ _4 = >::call(move _3, const ()) -> [return: bb2, unwind unreachable]; + _1 = f::(main) -> [return: bb1, unwind unreachable]; } bb1: { -+ StorageDead(_4); -+ StorageDead(_2); StorageDead(_1); _0 = const (); return; -+ } -+ -+ bb2: { -+ StorageDead(_3); -+ drop(_2) -> [return: bb1, unwind unreachable]; } } diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff index 1fd1014ba1d53..da516220d5048 100644 --- a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff @@ -4,43 +4,16 @@ fn g() -> () { let mut _0: (); let _1: (); -+ let mut _2: fn() {main}; -+ scope 1 (inlined f::) { -+ debug g => _2; -+ let mut _3: &fn() {main}; -+ let _4: (); -+ } bb0: { StorageLive(_1); -- _1 = f::(main) -> [return: bb1, unwind continue]; -+ StorageLive(_2); -+ _2 = main; -+ StorageLive(_4); -+ StorageLive(_3); -+ _3 = &_2; -+ _4 = >::call(move _3, const ()) -> [return: bb2, unwind: bb3]; + _1 = f::(main) -> [return: bb1, unwind continue]; } bb1: { -+ StorageDead(_4); -+ StorageDead(_2); StorageDead(_1); _0 = const (); return; -+ } -+ -+ bb2: { -+ StorageDead(_3); -+ drop(_2) -> [return: bb1, unwind continue]; -+ } -+ -+ bb3 (cleanup): { -+ drop(_2) -> [return: bb4, unwind terminate(cleanup)]; -+ } -+ -+ bb4 (cleanup): { -+ resume; } } diff --git a/tests/mir-opt/inline/cycle.rs b/tests/mir-opt/inline/cycle.rs index 350724235ba04..c251226673d5f 100644 --- a/tests/mir-opt/inline/cycle.rs +++ b/tests/mir-opt/inline/cycle.rs @@ -13,9 +13,7 @@ fn f(g: impl Fn()) { #[inline(always)] fn g() { // CHECK-LABEL: fn g( - // CHECK-NOT: inlined - // CHECK: (inlined f::) - // CHECK-NOT: inlined + // CHECK-NOT: (inlined f::) f(main); } diff --git a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff index d437dbf5763a2..142b9c5659889 100644 --- a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff @@ -7,6 +7,10 @@ + scope 1 (inlined ::call) { + scope 2 (inlined as Call>::call) { + scope 3 (inlined ::call) { ++ scope 4 (inlined as Call>::call) { ++ scope 5 (inlined ::call) { ++ } ++ } + } + } + } @@ -14,7 +18,7 @@ bb0: { StorageLive(_1); - _1 = ::call() -> [return: bb1, unwind unreachable]; -+ _1 = as Call>::call() -> [return: bb1, unwind unreachable]; ++ _1 = as Call>::call() -> [return: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff index 8314526ee0431..193ada05f0234 100644 --- a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff @@ -7,6 +7,10 @@ + scope 1 (inlined ::call) { + scope 2 (inlined as Call>::call) { + scope 3 (inlined ::call) { ++ scope 4 (inlined as Call>::call) { ++ scope 5 (inlined ::call) { ++ } ++ } + } + } + } @@ -14,7 +18,7 @@ bb0: { StorageLive(_1); - _1 = ::call() -> [return: bb1, unwind continue]; -+ _1 = as Call>::call() -> [return: bb1, unwind continue]; ++ _1 = as Call>::call() -> [return: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index ffb1aedd2ea90..a10061ed9412c 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index ffb1aedd2ea90..a10061ed9412c 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); From 2116ed723d178313cac1ff829d5a7417bba1cd3b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 30 Jan 2024 22:28:28 -0500 Subject: [PATCH 085/101] Tweak a few mir-opt tests instead of using -Clink-dead-code --- src/bootstrap/src/core/build_steps/test.rs | 1 - src/tools/compiletest/src/runtest.rs | 1 - tests/mir-opt/fn_ptr_shim.rs | 2 +- tests/mir-opt/retag.rs | 2 +- tests/mir-opt/slice_drop_shim.rs | 6 ++++-- tests/mir-opt/unusual_item_types.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index e1a1c416ae993..baf1b5a4a1afd 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1470,7 +1470,6 @@ impl Step for MirOpt { }; if builder.config.cmd.bless() { - crate::utils::cc_detect::find_target(builder, self.compiler.host); // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort, // but while we're at it we might as well flex our cross-compilation support. This // selection covers all our tier 1 operating systems and architectures using only tier diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 00ebd91f3871f..ed1c559e1f692 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2468,7 +2468,6 @@ impl<'test> TestCx<'test> { "-Zlint-mir", "-Zdump-mir-exclude-pass-number", "--crate-type=rlib", - "-Clink-dead-code", ]); if let Some(pass) = &self.props.mir_unit_test { rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]); diff --git a/tests/mir-opt/fn_ptr_shim.rs b/tests/mir-opt/fn_ptr_shim.rs index c82260baefee3..2650cbf9704f3 100644 --- a/tests/mir-opt/fn_ptr_shim.rs +++ b/tests/mir-opt/fn_ptr_shim.rs @@ -5,7 +5,7 @@ // (as only `FnDef` and `FnPtr` callees are allowed in MIR). // EMIT_MIR core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir -fn main() { +pub fn main() { call(noop as fn()); } diff --git a/tests/mir-opt/retag.rs b/tests/mir-opt/retag.rs index 1e4b017dad5fa..554b8ece90f28 100644 --- a/tests/mir-opt/retag.rs +++ b/tests/mir-opt/retag.rs @@ -28,7 +28,7 @@ impl Drop for Test { // EMIT_MIR retag.main.SimplifyCfg-elaborate-drops.after.mir // EMIT_MIR retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir -fn main() { +pub fn main() { let mut x = 0; { let v = Test(0).foo(&mut x); // just making sure we do not panic when there is a tuple struct ctor diff --git a/tests/mir-opt/slice_drop_shim.rs b/tests/mir-opt/slice_drop_shim.rs index cac0a349128c3..037e048b3b797 100644 --- a/tests/mir-opt/slice_drop_shim.rs +++ b/tests/mir-opt/slice_drop_shim.rs @@ -1,6 +1,8 @@ // skip-filecheck -// compile-flags: -Zmir-opt-level=0 - +// compile-flags: -Zmir-opt-level=0 -Clink-dead-code +// mir-opt tests are always built as rlibs so that they seamlessly cross-compile, +// so this test only produces MIR for the drop_in_place we're looking for +// if we use -Clink-dead-code. // EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir fn main() { diff --git a/tests/mir-opt/unusual_item_types.rs b/tests/mir-opt/unusual_item_types.rs index 49b663b4f8298..fa6ba515473ba 100644 --- a/tests/mir-opt/unusual_item_types.rs +++ b/tests/mir-opt/unusual_item_types.rs @@ -23,7 +23,7 @@ enum E { V = 5, } -fn main() { +pub fn main() { let f = Test::X as fn(usize) -> Test; // EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir let v = Vec::::new(); From 476f91cbf7fd4080fea7ede8c145c83f0b589ff9 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 5 Feb 2024 19:52:02 -0500 Subject: [PATCH 086/101] Don't call std_cargo to build mir-only sysroots --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3c0d074807d39..73f29d6bb6f45 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -239,7 +239,7 @@ impl Step for Std { let mut cargo = if self.is_for_mir_opt_tests { let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "check"); cargo.rustflag("-Zalways-encode-mir"); - std_cargo(builder, target, compiler.stage, &mut cargo); + cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml")); cargo } else { let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build"); From 3c7a8b9d7168b0e59f4264a987ffea54b54f0223 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 6 Feb 2024 23:40:58 -0500 Subject: [PATCH 087/101] Fixup async_closure_shims mir-opt test --- tests/mir-opt/async_closure_shims.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs index ef3bdaaa145a3..2c99a2dad37a7 100644 --- a/tests/mir-opt/async_closure_shims.rs +++ b/tests/mir-opt/async_closure_shims.rs @@ -33,7 +33,7 @@ async fn call_once(f: impl AsyncFnOnce(i32)) { // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir -fn main() { +pub fn main() { block_on(async { let b = 2i32; let mut async_closure = async move |a: i32| { From a59d00674a6b04ba1eaa5e0c3cf00ddb0346296b Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Wed, 7 Feb 2024 15:26:57 +0800 Subject: [PATCH 088/101] Add parallel rustc ui tests --- src/tools/tidy/src/ui_tests.rs | 2 +- .../cache-after-waiting-issue-111528.rs | 16 ++++++++++++++ .../cache-after-waiting-issue-111528.stderr | 8 +++++++ .../export-symbols-deadlock-issue-118205-2.rs | 7 ++++++ .../export-symbols-deadlock-issue-118205.rs | 22 +++++++++++++++++++ tests/ui/parallel-rustc/hello_world.rs | 6 +++++ .../read-stolen-value-issue-111520.rs | 18 +++++++++++++++ 7 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs create mode 100644 tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr create mode 100644 tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs create mode 100644 tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs create mode 100644 tests/ui/parallel-rustc/hello_world.rs create mode 100644 tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index e7b1ccf6a0299..4a44c40debd22 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -15,7 +15,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1819; -const ROOT_ENTRY_LIMIT: usize = 870; +const ROOT_ENTRY_LIMIT: usize = 871; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs new file mode 100644 index 0000000000000..148a59240f99a --- /dev/null +++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs @@ -0,0 +1,16 @@ +// compile-flags: -Z threads=16 +// build-fail + +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +pub fn a() { +} + +#[export_name="fail"] +pub fn b() { +//~^ Error symbol `fail` is already defined +} + +fn main() {} diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr new file mode 100644 index 0000000000000..7963165e31b0a --- /dev/null +++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr @@ -0,0 +1,8 @@ +error: symbol `fail` is already defined + --> $DIR/cache-after-waiting-issue-111528.rs:12:1 + | +LL | pub fn b() { + | ^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs new file mode 100644 index 0000000000000..8240b249018e2 --- /dev/null +++ b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs @@ -0,0 +1,7 @@ +// compile-flags:-C extra-filename=-1 -Z threads=16 +// no-prefer-dynamic +// build-pass +#![crate_name = "crateresolve1"] +#![crate_type = "lib"] + +pub fn f() -> isize { 10 } diff --git a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs new file mode 100644 index 0000000000000..691c36cfc9ec4 --- /dev/null +++ b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs @@ -0,0 +1,22 @@ +// compile-flags: -Z threads=16 +// build-pass + +pub static GLOBAL: isize = 3; + +static GLOBAL0: isize = 4; + +pub static GLOBAL2: &'static isize = &GLOBAL0; + +pub fn verify_same(a: &'static isize) { + let a = a as *const isize as usize; + let b = &GLOBAL as *const isize as usize; + assert_eq!(a, b); +} + +pub fn verify_same2(a: &'static isize) { + let a = a as *const isize as usize; + let b = GLOBAL2 as *const isize as usize; + assert_eq!(a, b); +} + +fn main() {} diff --git a/tests/ui/parallel-rustc/hello_world.rs b/tests/ui/parallel-rustc/hello_world.rs new file mode 100644 index 0000000000000..53e95c890ef52 --- /dev/null +++ b/tests/ui/parallel-rustc/hello_world.rs @@ -0,0 +1,6 @@ +// compile-flags: -Z threads=8 +// run-pass + +fn main() { + println!("Hello world!"); +} diff --git a/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs b/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs new file mode 100644 index 0000000000000..1907348cf09dc --- /dev/null +++ b/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs @@ -0,0 +1,18 @@ +// compile-flags: -Z threads=16 +// run-pass + +#[repr(transparent)] +struct Sched { + i: i32, +} +impl Sched { + extern "C" fn get(self) -> i32 { self.i } +} + +fn main() { + let s = Sched { i: 4 }; + let f = || -> i32 { + s.get() + }; + println!("f: {}", f()); +} From e55df623ead33023fe6c4488064e5d5e4e141b9e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 6 Feb 2024 17:40:11 +1100 Subject: [PATCH 089/101] Remove an `unchecked_claim_error_was_emitted` call. When `catch_fatal_errors` catches a `FatalErrorMarker`, it returns an `ErrorGuaranteed` that is conjured out of thin air with `unchecked_claim_error_was_emitted`. But that `ErrorGuaranteed` is never used. This commit changes it to instead conjure a `FatalError` out of thin air. (A non-deprecated action!) This makes more sense because `FatalError` and `FatalErrorMarker` are a natural pairing -- a `FatalErrorMarker` is created by calling `FatalError::raise`, so this is effectively getting back the original `FatalError`. This requires a tiny change in `catch_with_exit_code`. The old result of the `catch_fatal_errors` call there was `Result, ErrorGuaranteed>` which could be `flatten`ed into `Result<(), ErrorGuaranteed>`. The new result of the `catch_fatal_errors` calls is `Result, FatalError>`, which can't be `flatten`ed but is still easily matched for the success case. --- compiler/rustc_driver_impl/src/lib.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 5903c43ae98af..519bde988200e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -24,7 +24,9 @@ use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; use rustc_errors::registry::Registry; -use rustc_errors::{markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, PResult}; +use rustc_errors::{ + markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, +}; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; @@ -1231,11 +1233,10 @@ fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { /// The compiler currently unwinds with a special sentinel value to abort /// compilation on fatal errors. This function catches that sentinel and turns /// the panic into a `Result` instead. -pub fn catch_fatal_errors R, R>(f: F) -> Result { +pub fn catch_fatal_errors R, R>(f: F) -> Result { catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { if value.is::() { - #[allow(deprecated)] - ErrorGuaranteed::unchecked_claim_error_was_emitted() + FatalError } else { panic::resume_unwind(value); } @@ -1245,9 +1246,9 @@ pub fn catch_fatal_errors R, R>(f: F) -> Result interface::Result<()>) -> i32 { - match catch_fatal_errors(f).flatten() { - Ok(()) => EXIT_SUCCESS, - Err(_) => EXIT_FAILURE, + match catch_fatal_errors(f) { + Ok(Ok(())) => EXIT_SUCCESS, + _ => EXIT_FAILURE, } } From e6794ddfb00e14b29b3befc5bc054a15094321b7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 6 Feb 2024 20:47:47 +1100 Subject: [PATCH 090/101] rustdoc: make `main` more like rustc's. By making non-unicode arguments a fatal error instead of a warning, we don't need to handle what comes after, which avoids the need for an `unchecked_claim_error_was_emitted` call. --- src/librustdoc/lib.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 8c10f14116a0c..0fe3adadba347 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -177,13 +177,16 @@ pub fn main() { init_logging(&early_dcx); rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")); - let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&early_dcx) { - Some(args) => main_args(&mut early_dcx, &args, using_internal_features), - _ => - { - #[allow(deprecated)] - Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) - } + let exit_code = rustc_driver::catch_with_exit_code(|| { + let args = env::args_os() + .enumerate() + .map(|(i, arg)| { + arg.into_string().unwrap_or_else(|arg| { + early_dcx.early_fatal(format!("argument {i} is not valid Unicode: {arg:?}")) + }) + }) + .collect::>(); + main_args(&mut early_dcx, &args, using_internal_features) }); process::exit(exit_code); } @@ -219,19 +222,6 @@ fn init_logging(early_dcx: &EarlyDiagCtxt) { tracing::subscriber::set_global_default(subscriber).unwrap(); } -fn get_args(early_dcx: &EarlyDiagCtxt) -> Option> { - env::args_os() - .enumerate() - .map(|(i, arg)| { - arg.into_string() - .map_err(|arg| { - early_dcx.early_warn(format!("Argument {i} is not valid Unicode: {arg:?}")); - }) - .ok() - }) - .collect() -} - fn opts() -> Vec { let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable; let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable; From 83adf883a20fc7531e886996ce07b8555c943fba Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Feb 2024 09:01:49 +1100 Subject: [PATCH 091/101] rustdoc: remove `unchecked_claim_error_was_emitted` call in `main_args`. `main_args` calls `from_matches`, which does lots of initialization. If anything goes wrong, `from_matches` emits an error message and returns `Err(1)` (or `Err(3)`). `main_args` then turns the `Err(1)` into `Err(ErrorGuaranteed)`, because that's what `catch_with_exit_code` requires on error. But `catch_with_exit_code` doesn't do anything with the `ErrorGuaranteed`, it just exits with `EXIT_FAILURE`. We can avoid the creation of the `ErrorGuaranteed` (which requires an undesirable `unchecked_claim_error_was_emitted` call), by changing `from_matches` to instead eagerly abort if anything goes wrong. The behaviour from the user's point of view is the same: an early abort with an `EXIT_FAILURE` exit code. And we can also simplify `from_matches` to return an `Option` instead of a `Result`: - Old `Err(0)` case --> `None` - Old `Err(_)` case --> fatal error. This requires similar changes to `ScrapeExamplesOptions::new` and `load_call_locations`. --- src/librustdoc/config.rs | 96 +++++++++++-------------------- src/librustdoc/lib.rs | 11 +--- src/librustdoc/scrape_examples.rs | 49 +++++++--------- 3 files changed, 54 insertions(+), 102 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 3f7f9270b2da0..c46047aa0dbad 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -323,20 +323,20 @@ impl Options { early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches, args: Vec, - ) -> Result<(Options, RenderOptions), i32> { + ) -> Option<(Options, RenderOptions)> { // Check for unstable options. nightly_options::check_nightly_options(early_dcx, matches, &opts()); if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") { crate::usage("rustdoc"); - return Err(0); + return None; } else if matches.opt_present("version") { rustc_driver::version!(&early_dcx, "rustdoc", matches); - return Err(0); + return None; } if rustc_driver::describe_flag_categories(early_dcx, &matches) { - return Err(0); + return None; } let color = config::parse_color(early_dcx, matches); @@ -382,7 +382,7 @@ impl Options { } } - return Err(0); + return None; } let mut emit = Vec::new(); @@ -390,10 +390,7 @@ impl Options { for kind in list.split(',') { match kind.parse() { Ok(kind) => emit.push(kind), - Err(()) => { - dcx.err(format!("unrecognized emission type: {kind}")); - return Err(1); - } + Err(()) => dcx.fatal(format!("unrecognized emission type: {kind}")), } } } @@ -403,7 +400,7 @@ impl Options { && !matches.opt_present("show-coverage") && !nightly_options::is_unstable_enabled(matches) { - early_dcx.early_fatal( + dcx.fatal( "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)", ); } @@ -420,10 +417,7 @@ impl Options { } let paths = match theme::load_css_paths(content) { Ok(p) => p, - Err(e) => { - dcx.err(e); - return Err(1); - } + Err(e) => dcx.fatal(e), }; let mut errors = 0; @@ -442,9 +436,9 @@ impl Options { } } if errors != 0 { - return Err(1); + dcx.fatal("[check-theme] one or more tests failed"); } - return Err(0); + return None; } let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); @@ -452,11 +446,9 @@ impl Options { let input = PathBuf::from(if describe_lints { "" // dummy, this won't be used } else if matches.free.is_empty() { - dcx.err("missing file operand"); - return Err(1); + dcx.fatal("missing file operand"); } else if matches.free.len() > 1 { - dcx.err("too many file operands"); - return Err(1); + dcx.fatal("too many file operands"); } else { &matches.free[0] }); @@ -466,10 +458,7 @@ impl Options { let externs = parse_externs(early_dcx, matches, &unstable_opts); let extern_html_root_urls = match parse_extern_html_roots(matches) { Ok(ex) => ex, - Err(err) => { - dcx.err(err); - return Err(1); - } + Err(err) => dcx.fatal(err), }; let default_settings: Vec> = vec![ @@ -526,16 +515,14 @@ impl Options { let no_run = matches.opt_present("no-run"); if !should_test && no_run { - dcx.err("the `--test` flag must be passed to enable `--no-run`"); - return Err(1); + dcx.fatal("the `--test` flag must be passed to enable `--no-run`"); } let out_dir = matches.opt_str("out-dir").map(|s| PathBuf::from(&s)); let output = matches.opt_str("output").map(|s| PathBuf::from(&s)); let output = match (out_dir, output) { (Some(_), Some(_)) => { - dcx.err("cannot use both 'out-dir' and 'output' at once"); - return Err(1); + dcx.fatal("cannot use both 'out-dir' and 'output' at once"); } (Some(out_dir), None) => out_dir, (None, Some(output)) => output, @@ -549,8 +536,7 @@ impl Options { if let Some(ref p) = extension_css { if !p.is_file() { - dcx.err("option --extend-css argument must be a file"); - return Err(1); + dcx.fatal("option --extend-css argument must be a file"); } } @@ -566,31 +552,25 @@ impl Options { } let paths = match theme::load_css_paths(content) { Ok(p) => p, - Err(e) => { - dcx.err(e); - return Err(1); - } + Err(e) => dcx.fatal(e), }; for (theme_file, theme_s) in matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned())) { if !theme_file.is_file() { - dcx.struct_err(format!("invalid argument: \"{theme_s}\"")) + dcx.struct_fatal(format!("invalid argument: \"{theme_s}\"")) .with_help("arguments to --theme must be files") .emit(); - return Err(1); } if theme_file.extension() != Some(OsStr::new("css")) { - dcx.struct_err(format!("invalid argument: \"{theme_s}\"")) + dcx.struct_fatal(format!("invalid argument: \"{theme_s}\"")) .with_help("arguments to --theme must have a .css extension") .emit(); - return Err(1); } let (success, ret) = theme::test_theme_against(&theme_file, &paths, &dcx); if !success { - dcx.err(format!("error loading theme file: \"{theme_s}\"")); - return Err(1); + dcx.fatal(format!("error loading theme file: \"{theme_s}\"")); } else if !ret.is_empty() { dcx.struct_warn(format!( "theme file \"{theme_s}\" is missing CSS rules from the default theme", @@ -620,22 +600,18 @@ impl Options { edition, &None, ) else { - return Err(3); + dcx.fatal("`ExternalHtml::load` failed"); }; match matches.opt_str("r").as_deref() { Some("rust") | None => {} - Some(s) => { - dcx.err(format!("unknown input format: {s}")); - return Err(1); - } + Some(s) => dcx.fatal(format!("unknown input format: {s}")), } let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s)); if let Some(ref index_page) = index_page { if !index_page.is_file() { - dcx.err("option `--index-page` argument must be a file"); - return Err(1); + dcx.fatal("option `--index-page` argument must be a file"); } } @@ -646,8 +622,7 @@ impl Options { let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { Ok(types) => types, Err(e) => { - dcx.err(format!("unknown crate type: {e}")); - return Err(1); + dcx.fatal(format!("unknown crate type: {e}")); } }; @@ -655,18 +630,13 @@ impl Options { Some(s) => match OutputFormat::try_from(s.as_str()) { Ok(out_fmt) => { if !out_fmt.is_json() && show_coverage { - dcx.struct_err( + dcx.fatal( "html output format isn't supported for the --show-coverage option", - ) - .emit(); - return Err(1); + ); } out_fmt } - Err(e) => { - dcx.err(e); - return Err(1); - } + Err(e) => dcx.fatal(e), }, None => OutputFormat::default(), }; @@ -709,16 +679,14 @@ impl Options { let html_no_source = matches.opt_present("html-no-source"); if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) { - dcx.struct_err( + dcx.fatal( "--generate-link-to-definition option can only be used with HTML output format", - ) - .emit(); - return Err(1); + ); } - let scrape_examples_options = ScrapeExamplesOptions::new(matches, &dcx)?; + let scrape_examples_options = ScrapeExamplesOptions::new(matches, &dcx); let with_examples = matches.opt_strs("with-examples"); - let call_locations = crate::scrape_examples::load_call_locations(with_examples, &dcx)?; + let call_locations = crate::scrape_examples::load_call_locations(with_examples, &dcx); let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); @@ -793,7 +761,7 @@ impl Options { no_emit_shared: false, html_no_source, }; - Ok((options, render_options)) + Some((options, render_options)) } /// Returns `true` if the file given as `self.input` is a Markdown file. diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0fe3adadba347..097bbeb6d2857 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -720,15 +720,8 @@ fn main_args( // Note that we discard any distinction between different non-zero exit // codes from `from_matches` here. let (options, render_options) = match config::Options::from_matches(early_dcx, &matches, args) { - Ok(opts) => opts, - Err(code) => { - return if code == 0 { - Ok(()) - } else { - #[allow(deprecated)] - Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) - }; - } + Some(opts) => opts, + None => return Ok(()), }; let diag = diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index b7d9c16f34837..9c9b386edda7c 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -38,28 +38,23 @@ pub(crate) struct ScrapeExamplesOptions { } impl ScrapeExamplesOptions { - pub(crate) fn new( - matches: &getopts::Matches, - dcx: &rustc_errors::DiagCtxt, - ) -> Result, i32> { + pub(crate) fn new(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) -> Option { let output_path = matches.opt_str("scrape-examples-output-path"); let target_crates = matches.opt_strs("scrape-examples-target-crate"); let scrape_tests = matches.opt_present("scrape-tests"); match (output_path, !target_crates.is_empty(), scrape_tests) { - (Some(output_path), true, _) => Ok(Some(ScrapeExamplesOptions { + (Some(output_path), true, _) => Some(ScrapeExamplesOptions { output_path: PathBuf::from(output_path), target_crates, scrape_tests, - })), + }), (Some(_), false, _) | (None, true, _) => { - dcx.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together"); - Err(1) + dcx.fatal("must use --scrape-examples-output-path and --scrape-examples-target-crate together"); } (None, false, true) => { - dcx.err("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests"); - Err(1) + dcx.fatal("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests"); } - (None, false, false) => Ok(None), + (None, false, false) => None, } } } @@ -342,24 +337,20 @@ pub(crate) fn run( pub(crate) fn load_call_locations( with_examples: Vec, dcx: &rustc_errors::DiagCtxt, -) -> Result { - let inner = || { - let mut all_calls: AllCallLocations = FxHashMap::default(); - for path in with_examples { - let bytes = fs::read(&path).map_err(|e| format!("{e} (for path {path})"))?; - let mut decoder = MemDecoder::new(&bytes, 0); - let calls = AllCallLocations::decode(&mut decoder); - - for (function, fn_calls) in calls.into_iter() { - all_calls.entry(function).or_default().extend(fn_calls.into_iter()); - } - } +) -> AllCallLocations { + let mut all_calls: AllCallLocations = FxHashMap::default(); + for path in with_examples { + let bytes = match fs::read(&path) { + Ok(bytes) => bytes, + Err(e) => dcx.fatal(format!("failed to load examples: {e}")), + }; + let mut decoder = MemDecoder::new(&bytes, 0); + let calls = AllCallLocations::decode(&mut decoder); - Ok(all_calls) - }; + for (function, fn_calls) in calls.into_iter() { + all_calls.entry(function).or_default().extend(fn_calls.into_iter()); + } + } - inner().map_err(|e: String| { - dcx.err(format!("failed to load examples: {e}")); - 1 - }) + all_calls } From 97c157fe1e52eeabe14a64865b4731794a23393a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Feb 2024 10:26:50 +1100 Subject: [PATCH 092/101] Tighten up `ErrorGuaranteed` handling. - In `emit_producing_error_guaranteed`, only allow `Level::Error`. - In `emit_diagnostic`, only produce `ErrorGuaranteed` for `Level` and `DelayedBug`. (Not `Bug` or `Fatal`. They don't need it, because the relevant `emit` methods abort.) - Add/update various comments. --- compiler/rustc_errors/src/diagnostic_builder.rs | 16 ++++++++++------ compiler/rustc_errors/src/lib.rs | 14 ++++++++++---- compiler/rustc_span/src/lib.rs | 5 ++--- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index faff7f0b52673..e484bef0e0bc9 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -99,16 +99,20 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { } /// `ErrorGuaranteed::emit_producing_guarantee` uses this. - // FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`. fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { let diag = self.take_diag(); - // Only allow a guarantee if the `level` wasn't switched to a - // non-error. The field isn't `pub`, but the whole `Diagnostic` can be - // overwritten with a new one, thanks to `DerefMut`. + // The only error levels that produce `ErrorGuaranteed` are + // `Error` and `DelayedBug`. But `DelayedBug` should never occur here + // because delayed bugs have their level changed to `Bug` when they are + // actually printed, so they produce an ICE. + // + // (Also, even though `level` isn't `pub`, the whole `Diagnostic` could + // be overwritten with a new one thanks to `DerefMut`. So this assert + // protects against that, too.) assert!( - diag.is_error(), - "emitted non-error ({:?}) diagnostic from `DiagnosticBuilder`", + matches!(diag.level, Level::Error | Level::DelayedBug), + "invalid diagnostic level ({:?})", diag.level, ); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 7c62e3aa42281..74cccda6cbff6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -931,6 +931,7 @@ impl DiagCtxt { /// This excludes lint errors and delayed bugs. pub fn has_errors(&self) -> Option { self.inner.borrow().has_errors().then(|| { + // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) @@ -942,6 +943,7 @@ impl DiagCtxt { let inner = self.inner.borrow(); let result = inner.has_errors() || inner.lint_err_count > 0; result.then(|| { + // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) @@ -954,6 +956,7 @@ impl DiagCtxt { let result = inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty(); result.then(|| { + // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) @@ -1238,6 +1241,7 @@ impl DiagCtxtInner { } } + // Return value is only `Some` if the level is `Error` or `DelayedBug`. fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option { assert!(diagnostic.level.can_be_top_or_sub().0); @@ -1316,6 +1320,7 @@ impl DiagCtxtInner { !self.emitted_diagnostics.insert(diagnostic_hash) }; + let level = diagnostic.level; let is_error = diagnostic.is_error(); let is_lint = diagnostic.is_lint.is_some(); @@ -1352,6 +1357,7 @@ impl DiagCtxtInner { self.emitter.emit_diagnostic(diagnostic); } + if is_error { if is_lint { self.lint_err_count += 1; @@ -1359,11 +1365,11 @@ impl DiagCtxtInner { self.err_count += 1; } self.panic_if_treat_err_as_bug(); + } - #[allow(deprecated)] - { - guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); - } + #[allow(deprecated)] + if level == Level::Error { + guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); } }); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ea6766ea583be..1a1e1de6734ac 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2477,9 +2477,8 @@ where pub struct ErrorGuaranteed(()); impl ErrorGuaranteed { - /// To be used only if you really know what you are doing... ideally, we would find a way to - /// eliminate all calls to this method. - #[deprecated = "`Session::span_delayed_bug` should be preferred over this function"] + /// Don't use this outside of `DiagCtxtInner::emit_diagnostic`! + #[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"] pub fn unchecked_claim_error_was_emitted() -> Self { ErrorGuaranteed(()) } From 6889fe3806fa44addca89193e5c45ced8c7f532d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Feb 2024 19:30:59 +1100 Subject: [PATCH 093/101] Rename `unchecked_claim_error_was_emitted` as `unchecked_error_guaranteed`. It's more to-the-point. --- compiler/rustc_errors/src/lib.rs | 10 +++++----- compiler/rustc_span/src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 74cccda6cbff6..ec5029e505f96 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -933,7 +933,7 @@ impl DiagCtxt { self.inner.borrow().has_errors().then(|| { // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. #[allow(deprecated)] - ErrorGuaranteed::unchecked_claim_error_was_emitted() + ErrorGuaranteed::unchecked_error_guaranteed() }) } @@ -945,7 +945,7 @@ impl DiagCtxt { result.then(|| { // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. #[allow(deprecated)] - ErrorGuaranteed::unchecked_claim_error_was_emitted() + ErrorGuaranteed::unchecked_error_guaranteed() }) } @@ -958,7 +958,7 @@ impl DiagCtxt { result.then(|| { // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. #[allow(deprecated)] - ErrorGuaranteed::unchecked_claim_error_was_emitted() + ErrorGuaranteed::unchecked_error_guaranteed() }) } @@ -1286,7 +1286,7 @@ impl DiagCtxtInner { let backtrace = std::backtrace::Backtrace::capture(); self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); #[allow(deprecated)] - return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + return Some(ErrorGuaranteed::unchecked_error_guaranteed()); } GoodPathDelayedBug => { let backtrace = std::backtrace::Backtrace::capture(); @@ -1369,7 +1369,7 @@ impl DiagCtxtInner { #[allow(deprecated)] if level == Level::Error { - guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + guaranteed = Some(ErrorGuaranteed::unchecked_error_guaranteed()); } }); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 1a1e1de6734ac..bcf04a71ae223 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2479,7 +2479,7 @@ pub struct ErrorGuaranteed(()); impl ErrorGuaranteed { /// Don't use this outside of `DiagCtxtInner::emit_diagnostic`! #[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"] - pub fn unchecked_claim_error_was_emitted() -> Self { + pub fn unchecked_error_guaranteed() -> Self { ErrorGuaranteed(()) } } From c5e6df0c78afb787ae5b121ee8394baa21bca555 Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 7 Feb 2024 10:47:52 +0300 Subject: [PATCH 094/101] MirPass: make name more const --- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/mir/mod.rs | 8 ++++++-- compiler/rustc_middle/src/util/common.rs | 16 ++++++++++++++++ compiler/rustc_mir_transform/src/pass_manager.rs | 12 ++---------- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index ddfb2ece39f10..9f1609a559568 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,6 +30,7 @@ #![feature(assert_matches)] #![feature(box_patterns)] #![feature(core_intrinsics)] +#![feature(const_type_name)] #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(coroutines)] diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c9e69253701c5..4ba96464c0e2f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -140,8 +140,12 @@ fn to_profiler_name(type_name: &'static str) -> &'static str { /// loop that goes over each available MIR and applies `run_pass`. pub trait MirPass<'tcx> { fn name(&self) -> &'static str { - let name = std::any::type_name::(); - if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } + // FIXME Simplify the implementation once more `str` methods get const-stable. + // See copypaste in `MirLint` + const { + let name = std::any::type_name::(); + crate::util::common::c_name(name) + } } fn profiler_name(&self) -> &'static str { diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs index df101a2f6e4c6..dd3a36c7bf853 100644 --- a/compiler/rustc_middle/src/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -65,3 +65,19 @@ pub fn indenter() -> Indenter { debug!(">>"); Indenter { _cannot_construct_outside_of_this_module: () } } + +// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }` +pub const fn c_name(name: &'static str) -> &'static str { + // FIXME Simplify the implementation once more `str` methods get const-stable. + // and inline into call site + let bytes = name.as_bytes(); + let mut i = bytes.len(); + while i > 0 && bytes[i - 1] != b':' { + i = i - 1; + } + let (_, bytes) = bytes.split_at(i); + match std::str::from_utf8(bytes) { + Ok(name) => name, + Err(_) => name, + } +} diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index c1ef2b9f887fb..211a4057ff000 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -8,18 +8,10 @@ use crate::{lint::lint_body, validate, MirPass}; pub trait MirLint<'tcx> { fn name(&self) -> &'static str { // FIXME Simplify the implementation once more `str` methods get const-stable. + // See copypaste in `MirPass` const { let name = std::any::type_name::(); - let bytes = name.as_bytes(); - let mut i = bytes.len(); - while i > 0 && bytes[i - 1] != b':' { - i = i - 1; - } - let (_, bytes) = bytes.split_at(i); - match std::str::from_utf8(bytes) { - Ok(name) => name, - Err(_) => name, - } + rustc_middle::util::common::c_name(name) } } From dcca9a12cdda3be34ed74beca05d72c77d797e7f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 7 Feb 2024 16:06:52 +0000 Subject: [PATCH 095/101] Record coroutine kind in generics --- .../src/collect/generics_of.rs | 13 ++++++++++--- compiler/rustc_middle/src/ty/instance.rs | 9 ++++++++- tests/ui/coroutine/polymorphize-args.rs | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 tests/ui/coroutine/polymorphize-args.rs diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 1dabb6feb5e1b..4860555de2056 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -344,11 +344,18 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind: hir::ExprKind::Closure(hir::Closure { kind, .. }), .. }) = node { + // See `ClosureArgsParts`, `CoroutineArgsParts`, and `CoroutineClosureArgsParts` + // for info on the usage of each of these fields. let dummy_args = match kind { ClosureKind::Closure => &["", "", ""][..], - ClosureKind::Coroutine(_) => { - &["", "", "", "", ""][..] - } + ClosureKind::Coroutine(_) => &[ + "", + "", + "", + "", + "", + "", + ][..], ClosureKind::CoroutineClosure(_) => &[ "", "", diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 9c1f4b20d2c83..8848d216f5b49 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -765,7 +765,14 @@ fn polymorphize<'tcx>( let def_id = instance.def_id(); let upvars_ty = match tcx.type_of(def_id).skip_binder().kind() { ty::Closure(..) => Some(args.as_closure().tupled_upvars_ty()), - ty::Coroutine(..) => Some(args.as_coroutine().tupled_upvars_ty()), + ty::Coroutine(..) => { + assert_eq!( + args.as_coroutine().kind_ty(), + tcx.types.unit, + "polymorphization does not support coroutines from async closures" + ); + Some(args.as_coroutine().tupled_upvars_ty()) + } _ => None, }; let has_upvars = upvars_ty.is_some_and(|ty| !ty.tuple_fields().is_empty()); diff --git a/tests/ui/coroutine/polymorphize-args.rs b/tests/ui/coroutine/polymorphize-args.rs new file mode 100644 index 0000000000000..de44d667656c4 --- /dev/null +++ b/tests/ui/coroutine/polymorphize-args.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zpolymorphize=on +// build-pass + +#![feature(coroutines, coroutine_trait)] + +use std::ops::Coroutine; +use std::pin::Pin; +use std::thread; + +fn main() { + let mut foo = || yield; + thread::spawn(move || match Pin::new(&mut foo).resume(()) { + s => panic!("bad state: {:?}", s), + }) + .join() + .unwrap(); +} From a41ceff982aa81fbb0e17ae3f923e48fad4b6be0 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 7 Feb 2024 12:03:12 -0500 Subject: [PATCH 096/101] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index cdf84b69d0416..ccc84ccec4b73 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit cdf84b69d0416c57ac9dc3459af80dfb4883d27a +Subproject commit ccc84ccec4b7340eb916aefda1cb3e2fe17d8e7b From f0c6f5a7feb0a2d14a68133c050ec5d56902f961 Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Wed, 7 Feb 2024 23:29:22 -0500 Subject: [PATCH 097/101] Add documentation on `str::starts_with` Add documentation about a current footgun of `str::starts_with` --- library/core/src/str/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index ecc0613d7b9e5..b90f34360f6c4 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1160,6 +1160,12 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// Note that there is a footgun to this method when using a slice of [`char`]s. + /// Some users may expect that a slice of chars will behave similarly to a `&str` with this method. + /// That is not currently the case. When you pass a slice of [`char`]s to this method, it will return true + /// if any of the [`char`]s in the slice is the first [`char`] of this string slice. It does not work for + /// sequentially comparing a slice of [`char`]s to a string slice. See the second example below. + /// /// [`char`]: prim@char /// [pattern]: self::pattern /// @@ -1171,6 +1177,14 @@ impl str { /// assert!(bananas.starts_with("bana")); /// assert!(!bananas.starts_with("nana")); /// ``` + /// + /// ``` + /// let bananas = "bananas"; + /// + /// // Note that both of these assert successfully. + /// assert!(bananas.starts_with(&['b', 'a', 'n', 'a'])); + /// assert!(bananas.starts_with(&['a', 'b', 'c', 'd'])); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { pat.is_prefix_of(self) From 8ff1994ec06a0bc4d8f80ecbefe981013b902a9b Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Wed, 7 Feb 2024 23:37:34 -0500 Subject: [PATCH 098/101] Fix whitespace issues that tidy caught --- library/core/src/str/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index b90f34360f6c4..597d924469cfa 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1161,7 +1161,7 @@ impl str { /// function or closure that determines if a character matches. /// /// Note that there is a footgun to this method when using a slice of [`char`]s. - /// Some users may expect that a slice of chars will behave similarly to a `&str` with this method. + /// Some users may expect that a slice of chars will behave similarly to a `&str` with this method. /// That is not currently the case. When you pass a slice of [`char`]s to this method, it will return true /// if any of the [`char`]s in the slice is the first [`char`] of this string slice. It does not work for /// sequentially comparing a slice of [`char`]s to a string slice. See the second example below. @@ -1177,11 +1177,11 @@ impl str { /// assert!(bananas.starts_with("bana")); /// assert!(!bananas.starts_with("nana")); /// ``` - /// + /// /// ``` /// let bananas = "bananas"; - /// - /// // Note that both of these assert successfully. + /// + /// // Note that both of these assert successfully. /// assert!(bananas.starts_with(&['b', 'a', 'n', 'a'])); /// assert!(bananas.starts_with(&['a', 'b', 'c', 'd'])); /// ``` From cab1cc48ec25f1b2531a271abd2a6c04087dcc61 Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Thu, 8 Feb 2024 05:06:15 +0000 Subject: [PATCH 099/101] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f3e10689ff1d4..17e50400cec10 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f3b9d47a46c6d237665801155aa3e26c5f49958b +384b02c0825cefa59f2e8a99a33d9a5344959079 From d7263d7aada418eb22d0560388379a2e3658e211 Mon Sep 17 00:00:00 2001 From: Venus Xeon-Blonde Date: Fri, 9 Feb 2024 22:24:57 -0500 Subject: [PATCH 100/101] Change wording --- library/core/src/str/mod.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 597d924469cfa..e11d13f8bed16 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1157,14 +1157,13 @@ impl str { /// /// Returns `false` if it does not. /// - /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a - /// function or closure that determines if a character matches. + /// The [pattern] can be a `&str`, in which case this function will return true if + /// the `&str` is a prefix of this string slice. /// - /// Note that there is a footgun to this method when using a slice of [`char`]s. - /// Some users may expect that a slice of chars will behave similarly to a `&str` with this method. - /// That is not currently the case. When you pass a slice of [`char`]s to this method, it will return true - /// if any of the [`char`]s in the slice is the first [`char`] of this string slice. It does not work for - /// sequentially comparing a slice of [`char`]s to a string slice. See the second example below. + /// The [pattern] can also be a [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// These will only be checked against the first character of this string slice. + /// Look at the second example below regarding behavior for slices of [`char`]s. /// /// [`char`]: prim@char /// [pattern]: self::pattern From 964a576dc026f4805df652776abf8a22664815be Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Thu, 8 Feb 2024 05:14:42 +0000 Subject: [PATCH 101/101] fmt --- .../issue-miri-3288-ice-symbolic-alignment-extern-static.rs | 3 +-- src/tools/miri/tests/pass/align_offset_symbolic.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs index 446040749822e..fef5a6cddb91d 100644 --- a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs @@ -4,8 +4,7 @@ extern "C" { static _dispatch_queue_attr_concurrent: [u8; 0]; } -static DISPATCH_QUEUE_CONCURRENT: &'static [u8; 0] = - unsafe { &_dispatch_queue_attr_concurrent }; +static DISPATCH_QUEUE_CONCURRENT: &'static [u8; 0] = unsafe { &_dispatch_queue_attr_concurrent }; fn main() { let _val = *DISPATCH_QUEUE_CONCURRENT; //~ERROR: is not supported diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs index e96f11b1efa72..ac28c63e08110 100644 --- a/src/tools/miri/tests/pass/align_offset_symbolic.rs +++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs @@ -113,7 +113,7 @@ fn vtable() { let ptr: &dyn Send = &0; let parts: (*const (), *const u8) = unsafe { mem::transmute(ptr) }; - let vtable = parts.1 ; + let vtable = parts.1; let offset = vtable.align_offset(mem::align_of::()); let _vtable_aligned = vtable.wrapping_add(offset) as *const [TWOPTR; 0]; // FIXME: we can't actually do the access since vtable pointers act like zero-sized allocations.