From 75af3c58f9df479894465e81d374e047082e8789 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 15 Feb 2024 13:58:21 +1100 Subject: [PATCH 01/15] coverage: Regression test for a span extraction inconsistency --- tests/coverage/closure_unit_return.cov-map | 34 +++++++++++++++++++++ tests/coverage/closure_unit_return.coverage | 30 ++++++++++++++++++ tests/coverage/closure_unit_return.rs | 29 ++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 tests/coverage/closure_unit_return.cov-map create mode 100644 tests/coverage/closure_unit_return.coverage create mode 100644 tests/coverage/closure_unit_return.rs diff --git a/tests/coverage/closure_unit_return.cov-map b/tests/coverage/closure_unit_return.cov-map new file mode 100644 index 0000000000000..330a6b420b0e2 --- /dev/null +++ b/tests/coverage/closure_unit_return.cov-map @@ -0,0 +1,34 @@ +Function name: closure_unit_return::explicit_unit +Raw bytes (14): 0x[01, 01, 00, 02, 01, 07, 01, 01, 10, 01, 05, 05, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) + +Function name: closure_unit_return::explicit_unit::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 08, 16, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 8, 22) to (start + 2, 6) + +Function name: closure_unit_return::implicit_unit +Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 01, 13, 01, 03, 06, 04, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 19) +- Code(Counter(0)) at (prev + 3, 6) to (start + 4, 2) + +Function name: closure_unit_return::implicit_unit::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 16, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 17, 22) to (start + 2, 6) + diff --git a/tests/coverage/closure_unit_return.coverage b/tests/coverage/closure_unit_return.coverage new file mode 100644 index 0000000000000..1a706b3a18d66 --- /dev/null +++ b/tests/coverage/closure_unit_return.coverage @@ -0,0 +1,30 @@ + LL| |#![feature(coverage_attribute)] + LL| |// edition: 2021 + LL| | + LL| |// Regression test for an inconsistency between functions that return the value + LL| |// of their trailing expression, and functions that implicitly return `()`. + LL| | + LL| 1|fn explicit_unit() { + LL| 1| let closure = || { + LL| 0| (); + LL| 0| }; + LL| | + LL| 1| drop(closure); + LL| 1| () // explicit return of trailing value + LL| 1|} + LL| | + LL| 1|fn implicit_unit() { + LL| 1| let closure = || { + LL| 0| (); + LL| 1| }; + LL| 1| + LL| 1| drop(closure); + LL| 1| // implicit return of `()` + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | explicit_unit(); + LL| | implicit_unit(); + LL| |} + diff --git a/tests/coverage/closure_unit_return.rs b/tests/coverage/closure_unit_return.rs new file mode 100644 index 0000000000000..d2b4ab8bd9ff9 --- /dev/null +++ b/tests/coverage/closure_unit_return.rs @@ -0,0 +1,29 @@ +#![feature(coverage_attribute)] +// edition: 2021 + +// Regression test for an inconsistency between functions that return the value +// of their trailing expression, and functions that implicitly return `()`. + +fn explicit_unit() { + let closure = || { + (); + }; + + drop(closure); + () // explicit return of trailing value +} + +fn implicit_unit() { + let closure = || { + (); + }; + + drop(closure); + // implicit return of `()` +} + +#[coverage(off)] +fn main() { + explicit_unit(); + implicit_unit(); +} From cd9021e8cb1ab6cf5bdf341d7e0538703d86fc5b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 15 Feb 2024 18:12:27 +1100 Subject: [PATCH 02/15] coverage: Discard spans that fill the entire function body When we try to extract coverage-relevant spans from MIR, sometimes we see MIR statements/terminators whose spans cover the entire function body. Those spans tend to be unhelpful for coverage purposes, because they often represent compiler-inserted code, e.g. the implicit return value of `()`. --- .../src/coverage/spans/from_mir.rs | 13 +++++++++---- tests/coverage/closure_unit_return.cov-map | 6 +++--- tests/coverage/closure_unit_return.coverage | 4 ++-- tests/coverage/coverage_attr_closure.cov-map | 8 ++++---- tests/coverage/coverage_attr_closure.coverage | 8 ++++---- tests/coverage/inline-dead.cov-map | 6 +++--- tests/coverage/macro_name_span.cov-map | 4 ++-- tests/coverage/macro_name_span.coverage | 2 +- tests/coverage/unicode.cov-map | 8 -------- tests/coverage/unicode.coverage | 3 +-- 10 files changed, 29 insertions(+), 33 deletions(-) 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 9517ede288f5d..2db358379fe51 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -132,18 +132,23 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( bcb_data.basic_blocks.iter().flat_map(move |&bb| { let data = &mir_body[bb]; + let unexpand = move |expn_span| { + unexpand_into_body_span_with_visible_macro(expn_span, body_span) + // Discard any spans that fill the entire body, because they tend + // to represent compiler-inserted code, e.g. implicitly returning `()`. + .filter(|(span, _)| !span.source_equal(body_span)) + }; + let statement_spans = data.statements.iter().filter_map(move |statement| { let expn_span = filtered_statement_span(statement)?; - let (span, visible_macro) = - unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; + let (span, visible_macro) = unexpand(expn_span)?; Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement))) }); let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { let expn_span = filtered_terminator_span(terminator)?; - let (span, visible_macro) = - unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; + let (span, visible_macro) = unexpand(expn_span)?; Some(SpanFromMir::new(span, visible_macro, bcb, false)) }); diff --git a/tests/coverage/closure_unit_return.cov-map b/tests/coverage/closure_unit_return.cov-map index 330a6b420b0e2..c97b4a44dd6b2 100644 --- a/tests/coverage/closure_unit_return.cov-map +++ b/tests/coverage/closure_unit_return.cov-map @@ -16,13 +16,13 @@ Number of file 0 mappings: 1 - Code(Zero) at (prev + 8, 22) to (start + 2, 6) Function name: closure_unit_return::implicit_unit -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 01, 13, 01, 03, 06, 04, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 01, 10, 01, 05, 05, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 19) -- Code(Counter(0)) at (prev + 3, 6) to (start + 4, 2) +- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 16) +- Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) Function name: closure_unit_return::implicit_unit::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 16, 02, 06] diff --git a/tests/coverage/closure_unit_return.coverage b/tests/coverage/closure_unit_return.coverage index 1a706b3a18d66..1056baa385cb4 100644 --- a/tests/coverage/closure_unit_return.coverage +++ b/tests/coverage/closure_unit_return.coverage @@ -16,8 +16,8 @@ LL| 1|fn implicit_unit() { LL| 1| let closure = || { LL| 0| (); - LL| 1| }; - LL| 1| + LL| 0| }; + LL| | LL| 1| drop(closure); LL| 1| // implicit return of `()` LL| 1|} diff --git a/tests/coverage/coverage_attr_closure.cov-map b/tests/coverage/coverage_attr_closure.cov-map index 2208b28fd4149..5d2c6b00b40f8 100644 --- a/tests/coverage/coverage_attr_closure.cov-map +++ b/tests/coverage/coverage_attr_closure.cov-map @@ -15,14 +15,14 @@ Number of file 0 mappings: 1 - Code(Zero) at (prev + 29, 19) to (start + 2, 6) Function name: coverage_attr_closure::contains_closures_on -Raw bytes (19): 0x[01, 01, 00, 03, 01, 0f, 01, 02, 05, 01, 04, 06, 02, 05, 01, 04, 06, 01, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0f, 01, 01, 1a, 01, 05, 09, 00, 1b, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 5) -- Code(Counter(0)) at (prev + 4, 6) to (start + 2, 5) -- Code(Counter(0)) at (prev + 4, 6) to (start + 1, 2) +- Code(Counter(0)) at (prev + 15, 1) to (start + 1, 26) +- Code(Counter(0)) at (prev + 5, 9) to (start + 0, 27) +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 2) Function name: coverage_attr_closure::contains_closures_on::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 13, 02, 06] diff --git a/tests/coverage/coverage_attr_closure.coverage b/tests/coverage/coverage_attr_closure.coverage index 32c75b40d83c0..3474ad65063ec 100644 --- a/tests/coverage/coverage_attr_closure.coverage +++ b/tests/coverage/coverage_attr_closure.coverage @@ -14,13 +14,13 @@ LL| |#[coverage(on)] LL| 1|fn contains_closures_on() { LL| 1| let _local_closure_on = #[coverage(on)] - LL| 1| |input: &str| { + LL| 0| |input: &str| { LL| 0| println!("{input}"); - LL| 1| }; + LL| 0| }; LL| 1| let _local_closure_off = #[coverage(off)] - LL| 1| |input: &str| { + LL| | |input: &str| { LL| | println!("{input}"); - LL| 1| }; + LL| | }; LL| 1|} LL| | LL| |#[coverage(off)] diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index c669b7245ead8..f77781ca02839 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -22,13 +22,13 @@ Number of file 0 mappings: 4 = (Zero + (c0 - Zero)) Function name: inline_dead::main -Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0d, 01, 05, 06, 02, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0a, 01, 06, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 13) -- Code(Counter(0)) at (prev + 5, 6) to (start + 2, 2) +- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 10) +- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 2) Function name: inline_dead::main::{closure#0} Raw bytes (23): 0x[01, 01, 02, 00, 06, 01, 00, 03, 01, 07, 17, 01, 16, 00, 01, 17, 00, 18, 03, 01, 05, 00, 06] diff --git a/tests/coverage/macro_name_span.cov-map b/tests/coverage/macro_name_span.cov-map index a18e5f1486147..f3ee44d2a5abc 100644 --- a/tests/coverage/macro_name_span.cov-map +++ b/tests/coverage/macro_name_span.cov-map @@ -1,10 +1,10 @@ Function name: macro_name_span::affected_function -Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 1c, 02, 06] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 1c, 01, 40] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 22, 28) to (start + 2, 6) +- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 64) Function name: macro_name_span::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] diff --git a/tests/coverage/macro_name_span.coverage b/tests/coverage/macro_name_span.coverage index 28c88b1defa83..0e12ce4a27cad 100644 --- a/tests/coverage/macro_name_span.coverage +++ b/tests/coverage/macro_name_span.coverage @@ -21,6 +21,6 @@ LL| |macro_name_span_helper::macro_that_defines_a_function! { LL| 1| fn affected_function() { LL| 1| macro_with_an_unreasonably_and_egregiously_long_name!(); - LL| 1| } + LL| | } LL| |} diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index cd40194a0831b..aedfb2071c144 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -27,14 +27,6 @@ Number of file 0 mappings: 9 - Code(Expression(5, Add)) at (prev + 2, 5) to (start + 1, 2) = (c4 + ((((c0 + c1) - c1) - c2) + c3)) -Function name: unicode::サビ -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 14, 00, 18] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 30, 20) to (start + 0, 24) - Function name: unicode::他 (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25] Number of files: 1 diff --git a/tests/coverage/unicode.coverage b/tests/coverage/unicode.coverage index b284a557d5754..af586111ba348 100644 --- a/tests/coverage/unicode.coverage +++ b/tests/coverage/unicode.coverage @@ -29,8 +29,7 @@ LL| | LL| |macro_rules! macro_that_defines_a_function { LL| | (fn $名:ident () $体:tt) => { - LL| 1| fn $名 () $体 fn 他 () {} - ^0 + LL| 0| fn $名 () $体 fn 他 () {} LL| | } LL| |} LL| | From b49bd0bba00e5622917db09cb70f42e47d322df8 Mon Sep 17 00:00:00 2001 From: Takashiidobe Date: Fri, 16 Feb 2024 09:20:51 -0500 Subject: [PATCH 03/15] Add examples to document the return type of `select_nth_unstable`, `select_nth_unstable_by`, and `select_nth_unstable_by_key`. --- library/core/src/slice/mod.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1d8ac6aa04394..c948337ba6c2d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3016,8 +3016,13 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the median - /// v.select_nth_unstable(2); + /// // Find the items less than or equal to the median, the median, and greater than or equal to + /// // the median. + /// let (lesser, median, greater) = v.select_nth_unstable(2); + /// + /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); + /// assert_eq!(median, &mut 1); + /// assert!(greater == [4, 2] || greater == [2, 4]); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -3067,8 +3072,13 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the median as if the slice were sorted in descending order. - /// v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// // Find the items less than or equal to the median, the median, and greater than or equal to + /// // the median as if the slice were sorted in descending order. + /// let (lesser, median, greater) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// + /// assert!(lesser == [4, 2] || lesser == [2, 4]); + /// assert_eq!(median, &mut 1); + /// assert!(greater == [-3, -5] || greater == [-5, -3]); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -3122,8 +3132,13 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 1, -3, 2]; /// - /// // Return the median as if the array were sorted according to absolute value. - /// v.select_nth_unstable_by_key(2, |a| a.abs()); + /// // Find the items less than or equal to the median, the median, and greater than or equal to + /// // the median as if the slice were sorted according to absolute value. + /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); + /// + /// assert!(lesser == [1, 2] || lesser == [2, 1]); + /// assert_eq!(median, &mut -3); + /// assert!(greater == [4, -5] || greater == [-5, 4]); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. From 3250e953050be1a6867aac3745742f86ab406361 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 13 Feb 2024 23:49:28 +0000 Subject: [PATCH 04/15] Add a simple extension trait derive --- compiler/rustc_macros/src/extension.rs | 136 +++++++++++++++++++++++++ compiler/rustc_macros/src/lib.rs | 6 ++ 2 files changed, 142 insertions(+) create mode 100644 compiler/rustc_macros/src/extension.rs diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs new file mode 100644 index 0000000000000..7bb07285ae205 --- /dev/null +++ b/compiler/rustc_macros/src/extension.rs @@ -0,0 +1,136 @@ +use proc_macro2::Ident; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::{ + braced, parse_macro_input, Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, + Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, +}; + +pub(crate) fn extension(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + // Parse the input tokens into a syntax tree + let Extension { attrs, generics, vis, trait_, self_ty, items } = + parse_macro_input!(input as Extension); + let headers: Vec<_> = items + .iter() + .map(|item| match item { + ImplItem::Fn(f) => TraitItem::Fn(TraitItemFn { + attrs: scrub_attrs(&f.attrs), + sig: scrub_header(f.sig.clone()), + default: None, + semi_token: Some(Token![;](f.block.span())), + }), + ImplItem::Const(ct) => TraitItem::Const(TraitItemConst { + attrs: scrub_attrs(&ct.attrs), + const_token: ct.const_token, + ident: ct.ident.clone(), + generics: ct.generics.clone(), + colon_token: ct.colon_token, + ty: ct.ty.clone(), + default: None, + semi_token: ct.semi_token, + }), + ImplItem::Type(ty) => TraitItem::Type(TraitItemType { + attrs: scrub_attrs(&ty.attrs), + type_token: ty.type_token, + ident: ty.ident.clone(), + generics: ty.generics.clone(), + colon_token: None, + bounds: Punctuated::new(), + default: None, + semi_token: ty.semi_token, + }), + ImplItem::Macro(mac) => TraitItem::Macro(TraitItemMacro { + attrs: scrub_attrs(&mac.attrs), + mac: mac.mac.clone(), + semi_token: mac.semi_token, + }), + ImplItem::Verbatim(stream) => TraitItem::Verbatim(stream.clone()), + _ => unimplemented!(), + }) + .collect(); + + quote! { + #(#attrs)* + #vis trait #trait_ { + #(#headers)* + } + + impl #generics #trait_ for #self_ty { + #(#items)* + } + } + .into() +} + +/// Only keep `#[doc]` attrs. +fn scrub_attrs(attrs: &[Attribute]) -> Vec { + attrs.into_iter().cloned().filter(|attr| attr.path().segments[0].ident == "doc").collect() +} + +/// Scrub arguments so that they're valid for trait signatures. +fn scrub_header(mut sig: Signature) -> Signature { + for (idx, input) in sig.inputs.iter_mut().enumerate() { + match input { + syn::FnArg::Receiver(rcvr) => { + // `mut self` -> `self` + if rcvr.reference.is_none() { + rcvr.mutability.take(); + } + } + syn::FnArg::Typed(arg) => match &mut *arg.pat { + Pat::Ident(arg) => { + // `ref mut ident @ pat` -> `ident` + arg.by_ref.take(); + arg.mutability.take(); + arg.subpat.take(); + } + _ => { + // `pat` -> `__arg0` + arg.pat = Box::new( + PatIdent { + attrs: vec![], + by_ref: None, + mutability: None, + ident: Ident::new(&format!("__arg{idx}"), arg.pat.span()), + subpat: None, + } + .into(), + ) + } + }, + } + } + sig +} + +struct Extension { + attrs: Vec, + vis: Visibility, + generics: Generics, + trait_: Path, + self_ty: Type, + items: Vec, +} + +impl Parse for Extension { + fn parse(input: ParseStream<'_>) -> syn::Result { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse()?; + let _: Token![impl] = input.parse()?; + let generics = input.parse()?; + let trait_ = input.parse()?; + let _: Token![for] = input.parse()?; + let self_ty = input.parse()?; + + let content; + let _brace_token = braced!(content in input); + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(Extension { attrs, generics, vis, trait_, self_ty, items }) + } +} diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index af65c908ee66b..841f5c06126c2 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -14,6 +14,7 @@ use proc_macro::TokenStream; mod current_version; mod diagnostics; +mod extension; mod hash_stable; mod lift; mod query; @@ -40,6 +41,11 @@ pub fn symbols(input: TokenStream) -> TokenStream { symbols::symbols(input.into()).into() } +#[proc_macro_attribute] +pub fn extension(_attr: TokenStream, input: TokenStream) -> TokenStream { + extension::extension(input) +} + decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); decl_derive!( [HashStable_Generic, attributes(stable_hasher)] => From 9c25823bb4bba6416ca4b15cd956ae92716f82eb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 13 Feb 2024 23:49:39 +0000 Subject: [PATCH 05/15] Use extension trait derive --- compiler/rustc_ast_lowering/src/lib.rs | 11 +- compiler/rustc_borrowck/src/facts.rs | 15 +- compiler/rustc_borrowck/src/place_ext.rs | 14 +- .../src/region_infer/opaque_types.rs | 12 +- .../rustc_borrowck/src/universal_regions.rs | 22 +- .../src/collect/resolve_bound_vars.rs | 12 +- .../src/infer/canonical/instantiate.rs | 26 +- .../src/infer/error_reporting/mod.rs | 15 +- compiler/rustc_infer/src/infer/mod.rs | 7 +- compiler/rustc_infer/src/traits/engine.rs | 14 +- compiler/rustc_middle/src/ty/layout.rs | 24 +- compiler/rustc_middle/src/ty/util.rs | 9 +- compiler/rustc_trait_selection/src/infer.rs | 82 ++--- compiler/rustc_trait_selection/src/regions.rs | 10 +- .../src/solve/eval_ctxt/mod.rs | 14 +- .../src/solve/eval_ctxt/select.rs | 10 +- .../src/solve/inspect/analyse.rs | 11 +- .../rustc_trait_selection/src/solve/mod.rs | 5 +- .../src/traits/engine.rs | 7 +- .../traits/error_reporting/infer_ctxt_ext.rs | 37 +-- .../error_reporting/on_unimplemented.rs | 21 +- .../src/traits/error_reporting/suggestions.rs | 276 +---------------- .../error_reporting/type_err_ctxt_ext.rs | 286 +----------------- .../src/traits/outlives_bounds.rs | 25 +- .../src/traits/project.rs | 33 +- .../src/traits/query/evaluate_obligation.rs | 34 +-- .../src/traits/query/normalize.rs | 16 +- .../traits/specialize/specialization_graph.rs | 32 +- .../src/traits/structural_normalize.rs | 11 +- 29 files changed, 119 insertions(+), 972 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e9e1095a4ae5e..e6a7c08429bd4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -57,6 +57,7 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate}; use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; @@ -190,15 +191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } -trait ResolverAstLoweringExt { - fn legacy_const_generic_args(&self, expr: &Expr) -> Option>; - fn get_partial_res(&self, id: NodeId) -> Option; - fn get_import_res(&self, id: NodeId) -> PerNS>>; - fn get_label_res(&self, id: NodeId) -> Option; - fn get_lifetime_res(&self, id: NodeId) -> Option; - fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>; -} - +#[extension] impl ResolverAstLoweringExt for ResolverAstLowering { fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { if let ExprKind::Path(None, path) = &expr.kind { diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 68dc9a6764bfc..da14408fb6961 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -2,6 +2,7 @@ use crate::location::{LocationIndex, LocationTable}; use crate::BorrowIndex; use polonius_engine::AllFacts as PoloniusFacts; use polonius_engine::Atom; +use rustc_macros::extension; use rustc_middle::mir::Local; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::move_paths::MovePathIndex; @@ -24,20 +25,10 @@ impl polonius_engine::FactTypes for RustcFacts { pub type AllFacts = PoloniusFacts; -pub(crate) trait AllFactsExt { +#[extension] +pub(crate) impl AllFactsExt for AllFacts { /// Returns `true` if there is a need to gather `AllFacts` given the /// current `-Z` flags. - fn enabled(tcx: TyCtxt<'_>) -> bool; - - fn write_to_dir( - &self, - dir: impl AsRef, - location_table: &LocationTable, - ) -> Result<(), Box>; -} - -impl AllFactsExt for AllFacts { - /// Return fn enabled(tcx: TyCtxt<'_>) -> bool { tcx.sess.opts.unstable_opts.nll_facts || tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index b59ab7fafa576..ac8991ccf00bd 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -1,24 +1,16 @@ use crate::borrow_set::LocalsStateAtExit; use rustc_hir as hir; +use rustc_macros::extension; use rustc_middle::mir::ProjectionElem; use rustc_middle::mir::{Body, Mutability, Place}; use rustc_middle::ty::{self, TyCtxt}; -/// Extension methods for the `Place` type. -pub trait PlaceExt<'tcx> { +#[extension] +pub impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { /// Returns `true` if we can safely ignore borrows of this place. /// This is true whenever there is no action that the user can do /// to the place `self` that would invalidate the borrow. This is true /// for borrows of raw pointer dereferents as well as shared references. - fn ignore_borrow( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - locals_state_at_exit: &LocalsStateAtExit, - ) -> bool; -} - -impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { fn ignore_borrow( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index cd2fe56ca4916..4aac392ef392e 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -6,6 +6,7 @@ use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::InferCtxt; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::traits::{Obligation, ObligationCause}; +use rustc_macros::extension; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; @@ -225,15 +226,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } -pub trait InferCtxtExt<'tcx> { - fn infer_opaque_definition_from_instantiation( - &self, - opaque_type_key: OpaqueTypeKey<'tcx>, - instantiated_ty: OpaqueHiddenType<'tcx>, - ) -> Ty<'tcx>; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Given the fully resolved, instantiated type for an opaque /// type, i.e., the value of an inference variable like C1 or C2 /// (*), computes the "definition type" for an opaque type diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 90e8f1b93b294..f9a8543e28d2b 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -22,6 +22,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::BodyOwnerKind; use rustc_index::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_macros::extension; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt}; @@ -793,26 +794,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } } -trait InferCtxtExt<'tcx> { - fn replace_free_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - value: T, - ) -> T - where - T: TypeFoldable>; - - fn replace_bound_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - all_outlive_scope: LocalDefId, - value: ty::Binder<'tcx, T>, - indices: &mut UniversalRegionIndices<'tcx>, - ) -> T - where - T: TypeFoldable>; -} - +#[extension] impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars( diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 287cb8809086a..9fb6103183bbc 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -14,6 +14,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; +use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; @@ -27,16 +28,7 @@ use std::fmt; use crate::errors; -trait RegionExt { - fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg); - - fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg); - - fn id(&self) -> Option; - - fn shifted(self, amount: u32) -> ResolvedArg; -} - +#[extension] impl RegionExt for ResolvedArg { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { debug!("ResolvedArg::early: def_id={:?}", param.def_id); diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index f6b583151fdf3..54940a2b4988c 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -13,12 +13,16 @@ use rustc_middle::ty::{self, TyCtxt}; /// FIXME(-Znext-solver): This or public because it is shared with the /// new trait solver implementation. We should deduplicate canonicalization. -pub trait CanonicalExt<'tcx, V> { +#[extension] +pub impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V where - V: TypeFoldable>; + V: TypeFoldable>, + { + self.instantiate_projected(tcx, var_values, |value| value.clone()) + } /// Allows one to apply a instantiation to some subset of /// `self.value`. Invoke `projection_fn` with `self.value` to get @@ -26,24 +30,6 @@ pub trait CanonicalExt<'tcx, V> { /// variables bound in `self` (usually this extracts from subset /// of `self`). Apply the instantiation `var_values` to this value /// V, replacing each of the canonical variables. - fn instantiate_projected( - &self, - tcx: TyCtxt<'tcx>, - var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> T, - ) -> T - where - T: TypeFoldable>; -} - -impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { - fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V - where - V: TypeFoldable>, - { - self.instantiate_projected(tcx, var_values, |value| value.clone()) - } - fn instantiate_projected( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 104bf4a5be873..37efafc5972f2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2786,19 +2786,8 @@ pub enum FailureCode { Error0644, } -pub trait ObligationCauseExt<'tcx> { - fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; - - fn as_failure_code_diag( - &self, - terr: TypeError<'tcx>, - span: Span, - subdiags: Vec, - ) -> ObligationCauseFailureCode; - fn as_requirement_str(&self) -> &'static str; -} - -impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { +#[extension] +pub impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2caf3b3cc9364..b9ebd685ca9f2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -626,11 +626,8 @@ pub struct InferCtxtBuilder<'tcx> { next_trait_solver: bool, } -pub trait TyCtxtInferExt<'tcx> { - fn infer_ctxt(self) -> InferCtxtBuilder<'tcx>; -} - -impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { +#[extension] +pub impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 64b9714c7c086..79a29e2496807 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -52,18 +52,8 @@ pub trait TraitEngine<'tcx>: 'tcx { ) -> Vec>; } -pub trait TraitEngineExt<'tcx> { - fn register_predicate_obligations( - &mut self, - infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator>, - ); - - #[must_use] - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; -} - -impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { +#[extension] +pub impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { fn register_predicate_obligations( &mut self, infcx: &InferCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2b34f5daaf63f..1fb04f5bbfe34 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -23,20 +23,8 @@ use std::fmt; use std::num::NonZero; use std::ops::Bound; -pub trait IntegerExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>; - fn from_int_ty(cx: &C, ity: ty::IntTy) -> Integer; - fn from_uint_ty(cx: &C, uty: ty::UintTy) -> Integer; - fn repr_discr<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - repr: &ReprOptions, - min: i128, - max: i128, - ) -> (Integer, bool); -} - -impl IntegerExt for Integer { +#[extension] +pub impl IntegerExt for Integer { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> { match (*self, signed) { @@ -123,12 +111,8 @@ impl IntegerExt for Integer { } } -pub trait PrimitiveExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; -} - -impl PrimitiveExt for Primitive { +#[extension] +pub impl PrimitiveExt for Primitive { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2addfa37f8b4d..98d19083aaba7 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -96,13 +96,8 @@ impl<'tcx> Discr<'tcx> { } } -pub trait IntTypeExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option>) -> Option>; - fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx>; -} - -impl IntTypeExt for IntegerType { +#[extension] +pub impl IntTypeExt for IntegerType { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { IntegerType::Pointer(true) => tcx.types.isize, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index ef4a0f52f9ea7..8406880477e4d 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -17,49 +17,8 @@ use std::fmt::Debug; pub use rustc_infer::infer::*; -pub trait InferCtxtExt<'tcx> { - fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; - - fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; - - /// Check whether a `ty` implements given trait(trait_def_id) without side-effects. - /// - /// The inputs are: - /// - /// - the def-id of the trait - /// - the type parameters of the trait, including the self-type - /// - the parameter environment - /// - /// Invokes `evaluate_obligation`, so in the event that evaluating - /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent - /// (or EvaluatedToAmbigStackDependent) will be returned. - fn type_implements_trait( - &self, - trait_def_id: DefId, - params: impl IntoIterator>>, - param_env: ty::ParamEnv<'tcx>, - ) -> traits::EvaluationResult; - - /// Returns `Some` if a type implements a trait shallowly, without side-effects, - /// along with any errors that would have been reported upon further obligation - /// processing. - /// - /// - If this returns `Some([])`, then the trait holds modulo regions. - /// - If this returns `Some([errors..])`, then the trait has an impl for - /// the self type, but some nested obligations do not hold. - /// - If this returns `None`, no implementation that applies could be found. - /// - /// FIXME(-Znext-solver): Due to the recursive nature of the new solver, - /// this will probably only ever return `Some([])` or `None`. - fn type_implements_trait_shallow( - &self, - trait_def_id: DefId, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Option>>; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); @@ -81,6 +40,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } + /// Check whether a `ty` implements given trait(trait_def_id) without side-effects. + /// + /// The inputs are: + /// + /// - the def-id of the trait + /// - the type parameters of the trait, including the self-type + /// - the parameter environment + /// + /// Invokes `evaluate_obligation`, so in the event that evaluating + /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent + /// (or EvaluatedToAmbigStackDependent) will be returned. #[instrument(level = "debug", skip(self, params), ret)] fn type_implements_trait( &self, @@ -99,6 +69,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) } + /// Returns `Some` if a type implements a trait shallowly, without side-effects, + /// along with any errors that would have been reported upon further obligation + /// processing. + /// + /// - If this returns `Some([])`, then the trait holds modulo regions. + /// - If this returns `Some([errors..])`, then the trait has an impl for + /// the self type, but some nested obligations do not hold. + /// - If this returns `None`, no implementation that applies could be found. + /// + /// FIXME(-Znext-solver): Due to the recursive nature of the new solver, + /// this will probably only ever return `Some([])` or `None`. fn type_implements_trait_shallow( &self, trait_def_id: DefId, @@ -124,19 +105,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } } -pub trait InferCtxtBuilderExt<'tcx> { - fn enter_canonical_trait_query( - self, - canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result, - ) -> Result, NoSolution> - where - K: TypeFoldable>, - R: Debug + TypeFoldable>, - Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>; -} - -impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { /// The "main method" for a canonicalized trait query. Given the /// canonical key `canonical_key`, this method will create a new /// inference context, instantiate the key, and run your operation diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 756db7cc2063f..dc9edb6063d75 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -3,20 +3,14 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; -pub trait InferCtxtRegionExt<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { /// Resolve regions, using the deep normalizer to normalize any type-outlives /// obligations in the process. This is in `rustc_trait_selection` because /// we need to normalize. /// /// Prefer this method over `resolve_regions_with_normalize`, unless you are /// doing something specific for normalization. - fn resolve_regions( - &self, - outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Vec>; -} - -impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { fn resolve_regions( &self, outlives_env: &OutlivesEnvironment<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 803379af005f9..3abdc4a333053 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -131,22 +131,12 @@ pub enum GenerateProofTree { Never, } -pub trait InferCtxtEvalExt<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. /// /// Using this while inside of the solver is wrong as it uses a new /// search graph which would break cycle detection. - fn evaluate_root_goal( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - generate_proof_tree: GenerateProofTree, - ) -> ( - Result<(bool, Certainty, Vec>>), NoSolution>, - Option>, - ); -} - -impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index eab5962443696..406f4c2f6151e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -17,14 +17,8 @@ use crate::solve::inspect::ProofTreeBuilder; use crate::traits::StructurallyNormalizeExt; use crate::traits::TraitEngineExt; -pub trait InferCtxtSelectExt<'tcx> { - fn select_in_new_trait_solver( - &self, - obligation: &PolyTraitObligation<'tcx>, - ) -> SelectionResult<'tcx, Selection<'tcx>>; -} - -impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { fn select_in_new_trait_solver( &self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index f33d0f397ce9e..1c6c2ff594a1b 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -216,15 +216,8 @@ pub trait ProofTreeVisitor<'tcx> { fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow; } -pub trait ProofTreeInferCtxtExt<'tcx> { - fn visit_proof_tree>( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - visitor: &mut V, - ) -> ControlFlow; -} - -impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension] +pub impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> { fn visit_proof_tree>( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 94a3cef8ad14e..11e1e72e04e23 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -61,10 +61,7 @@ enum GoalEvaluationKind { Nested { is_normalizes_to_hack: IsNormalizesToHack }, } -trait CanonicalResponseExt { - fn has_no_inference_or_external_constraints(&self) -> bool; -} - +#[extension] impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { fn has_no_inference_or_external_constraints(&self) -> bool { self.value.external_constraints.region_constraints.is_empty() diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index caf950037fdfd..b234b8a9d0327 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -27,11 +27,8 @@ use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::Variance; use rustc_middle::ty::{self, Ty, TyCtxt}; -pub trait TraitEngineExt<'tcx> { - fn new(infcx: &InferCtxt<'tcx>) -> Box; -} - -impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { +#[extension] +pub impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { fn new(infcx: &InferCtxt<'tcx>) -> Box { if infcx.next_trait_solver() { Box::new(NextFulfillmentCtxt::new(infcx)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 15d064d4036ea..80581d01f6b0a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -11,38 +11,8 @@ use super::ArgKind; pub use rustc_infer::traits::error_reporting::*; -pub trait InferCtxtExt<'tcx> { - /// Given some node representing a fn-like thing in the HIR map, - /// returns a span and `ArgKind` information that describes the - /// arguments it expects. This can be supplied to - /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option, Vec)>; - - /// Reports an error when the number of arguments needed by a - /// trait match doesn't match the number that the expression - /// provides. - fn report_arg_count_mismatch( - &self, - span: Span, - found_span: Option, - expected_args: Vec, - found_args: Vec, - is_closure: bool, - closure_pipe_span: Option, - ) -> DiagnosticBuilder<'tcx>; - - /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` - /// in that order, and returns the generic type corresponding to the - /// argument of that trait (corresponding to the closure arguments). - fn type_implements_fn_trait( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Binder<'tcx, Ty<'tcx>>, - polarity: ty::ImplPolarity, - ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Given some node representing a fn-like thing in the HIR map, /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to @@ -229,6 +199,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { err } + /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` + /// in that order, and returns the generic type corresponding to the + /// argument of that trait (corresponding to the closure arguments). fn type_implements_fn_trait( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index f0773fd1671e2..7d7f415c7bb7a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -23,24 +23,6 @@ use crate::errors::{ use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; -pub trait TypeErrCtxtExt<'tcx> { - /*private*/ - fn impl_similar_to( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> Option<(DefId, GenericArgsRef<'tcx>)>; - - /*private*/ - fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str>; - - fn on_unimplemented_note( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> OnUnimplementedNote; -} - /// The symbols which are always allowed in a format string static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ kw::SelfUpper, @@ -56,7 +38,8 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ sym::Trait, ]; -impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension] +pub impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, trait_ref: ty::PolyTraitRef<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 335e6ff28226e..58c731a8ed7f4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -106,279 +106,6 @@ impl<'tcx, 'a> CoroutineData<'tcx, 'a> { } } -// This trait is public to expose the diagnostics methods to clippy. -pub trait TypeErrCtxtExt<'tcx> { - fn suggest_restricting_param_bound( - &self, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - associated_item: Option<(&'static str, Ty<'tcx>)>, - body_id: LocalDefId, - ); - - fn suggest_dereferences( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn get_closure_name( - &self, - def_id: DefId, - err: &mut Diagnostic, - msg: Cow<'static, str>, - ) -> Option; - - fn suggest_fn_call( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn check_for_binding_assigned_block_without_tail_expression( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_add_clone_to_arg( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn extract_callable_info( - &self, - body_id: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - found: Ty<'tcx>, - ) -> Option<(DefIdOrName, Ty<'tcx>, Vec>)>; - - fn suggest_add_reference_to_arg( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - has_custom_message: bool, - ) -> bool; - - fn suggest_borrowing_for_object_cast( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - self_ty: Ty<'tcx>, - object_ty: Ty<'tcx>, - ); - - fn suggest_remove_reference( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic); - - fn suggest_change_mut( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_semicolon_removal( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - span: Span, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option; - - fn suggest_impl_trait( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn point_at_returns_when_relevant( - &self, - err: &mut DiagnosticBuilder<'tcx>, - obligation: &PredicateObligation<'tcx>, - ); - - fn report_closure_arg_mismatch( - &self, - span: Span, - found_span: Option, - found: ty::PolyTraitRef<'tcx>, - expected: ty::PolyTraitRef<'tcx>, - cause: &ObligationCauseCode<'tcx>, - found_node: Option>, - param_env: ty::ParamEnv<'tcx>, - ) -> DiagnosticBuilder<'tcx>; - - fn note_conflicting_fn_args( - &self, - err: &mut Diagnostic, - cause: &ObligationCauseCode<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ); - - fn note_conflicting_closure_bounds( - &self, - cause: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - ); - - fn suggest_fully_qualified_path( - &self, - err: &mut Diagnostic, - item_def_id: DefId, - span: Span, - trait_ref: DefId, - ); - - fn maybe_note_obligation_cause_for_async_await( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - ) -> bool; - - fn note_obligation_cause_for_async_await( - &self, - err: &mut Diagnostic, - interior_or_upvar_span: CoroutineInteriorOrUpvar, - is_async: bool, - outer_coroutine: Option, - trait_pred: ty::TraitPredicate<'tcx>, - target_ty: Ty<'tcx>, - obligation: &PredicateObligation<'tcx>, - next_code: Option<&ObligationCauseCode<'tcx>>, - ); - - fn note_obligation_cause_code( - &self, - body_id: LocalDefId, - err: &mut Diagnostic, - predicate: T, - param_env: ty::ParamEnv<'tcx>, - cause_code: &ObligationCauseCode<'tcx>, - obligated_types: &mut Vec>, - seen_requirements: &mut FxHashSet, - ) where - T: ToPredicate<'tcx>; - - /// Suggest to await before try: future? => future.await? - fn suggest_await_before_try( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - trait_pred: ty::PolyTraitPredicate<'tcx>, - span: Span, - ); - - fn suggest_floating_point_literal( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_ref: &ty::PolyTraitRef<'tcx>, - ); - - fn suggest_derive( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_dereferencing_index( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ); - - fn suggest_option_method_if_applicable( - &self, - failed_pred: ty::Predicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, - err: &mut Diagnostic, - expr: &hir::Expr<'_>, - ); - - fn note_function_argument_obligation( - &self, - body_id: LocalDefId, - err: &mut Diagnostic, - arg_hir_id: HirId, - parent_code: &ObligationCauseCode<'tcx>, - param_env: ty::ParamEnv<'tcx>, - predicate: ty::Predicate<'tcx>, - call_hir_id: HirId, - ); - - fn look_for_iterator_item_mistakes( - &self, - assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>], - typeck_results: &TypeckResults<'tcx>, - type_diffs: &[TypeError<'tcx>], - param_env: ty::ParamEnv<'tcx>, - path_segment: &hir::PathSegment<'_>, - args: &[hir::Expr<'_>], - err: &mut Diagnostic, - ); - - fn point_at_chain( - &self, - expr: &hir::Expr<'_>, - typeck_results: &TypeckResults<'tcx>, - type_diffs: Vec>, - param_env: ty::ParamEnv<'tcx>, - err: &mut Diagnostic, - ); - - fn probe_assoc_types_at_expr( - &self, - type_diffs: &[TypeError<'tcx>], - span: Span, - prev_ty: Ty<'tcx>, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - ) -> Vec))>>; - - fn suggest_convert_to_slice( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - candidate_impls: &[ImplCandidate<'tcx>], - span: Span, - ); - - fn explain_hrtb_projection( - &self, - diag: &mut Diagnostic, - pred: ty::PolyTraitPredicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: &ObligationCause<'tcx>, - ); - - fn suggest_desugaring_async_fn_in_trait( - &self, - err: &mut Diagnostic, - trait_ref: ty::PolyTraitRef<'tcx>, - ); -} - fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { ( generics.tail_span_for_predicate_suggestion(), @@ -509,7 +236,8 @@ pub fn suggest_restriction<'tcx>( } } -impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension] +pub impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_restricting_param_bound( &self, err: &mut Diagnostic, 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 68b1a0d4e61cd..92992de64ffb9 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 @@ -57,78 +57,8 @@ use super::{ pub use rustc_infer::traits::error_reporting::*; -pub trait TypeErrCtxtExt<'tcx> { - fn build_overflow_error( - &self, - predicate: &T, - span: Span, - suggest_increasing_limit: bool, - ) -> DiagnosticBuilder<'tcx> - where - T: fmt::Display + TypeFoldable> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>; - - fn report_overflow_error( - &self, - predicate: &T, - span: Span, - suggest_increasing_limit: bool, - mutate: impl FnOnce(&mut Diagnostic), - ) -> ! - where - T: fmt::Display + TypeFoldable> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>; - - fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed; - - fn report_fulfillment_errors(&self, errors: Vec>) -> ErrorGuaranteed; - - fn report_overflow_obligation( - &self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool, - ) -> ! - where - T: ToPredicate<'tcx> + Clone; - - fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); - - fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; - - /// The `root_obligation` parameter should be the `root_obligation` field - /// from a `FulfillmentError`. If no `FulfillmentError` is available, - /// then it should be the same as `obligation`. - fn report_selection_error( - &self, - obligation: PredicateObligation<'tcx>, - root_obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - ) -> ErrorGuaranteed; - - fn emit_specialized_closure_kind_error( - &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Option; - - fn fn_arg_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result<(), ErrorGuaranteed>; - - fn try_conversion_context( - &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - err: &mut Diagnostic, - ) -> bool; - - fn report_const_param_not_wf( - &self, - ty: Ty<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> DiagnosticBuilder<'tcx>; -} - -impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension] +pub impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn report_fulfillment_errors( &self, mut errors: Vec>, @@ -382,6 +312,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.emit() } + /// The `root_obligation` parameter should be the `root_obligation` field + /// from a `FulfillmentError`. If no `FulfillmentError` is available, + /// then it should be the same as `obligation`. fn report_selection_error( &self, mut obligation: PredicateObligation<'tcx>, @@ -1393,209 +1326,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } -pub(super) trait InferCtxtPrivExt<'tcx> { - // returns if `cond` not occurring implies that `error` does not occur - i.e., that - // `error` occurring implies that `cond` occurs. - fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; - - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed; - - fn report_projection_error( - &self, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - ) -> ErrorGuaranteed; - - fn maybe_detailed_projection_msg( - &self, - pred: ty::ProjectionPredicate<'tcx>, - normalized_ty: ty::Term<'tcx>, - expected_ty: ty::Term<'tcx>, - ) -> Option; - - fn fuzzy_match_tys( - &self, - a: Ty<'tcx>, - b: Ty<'tcx>, - ignoring_lifetimes: bool, - ) -> Option; - - fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str; - - fn find_similar_impl_candidates( - &self, - trait_pred: ty::PolyTraitPredicate<'tcx>, - ) -> Vec>; - - fn report_similar_impl_candidates( - &self, - impl_candidates: &[ImplCandidate<'tcx>], - trait_ref: ty::PolyTraitRef<'tcx>, - body_def_id: LocalDefId, - err: &mut Diagnostic, - other: bool, - param_env: ty::ParamEnv<'tcx>, - ) -> bool; - - fn report_similar_impl_candidates_for_root_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, - body_def_id: LocalDefId, - err: &mut Diagnostic, - ); - - /// Gets the parent trait chain start - fn get_parent_trait_ref( - &self, - code: &ObligationCauseCode<'tcx>, - ) -> Option<(Ty<'tcx>, Option)>; - - /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait - /// with the same path as `trait_ref`, a help message about - /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut Diagnostic, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> bool; - - /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the - /// `trait_ref`. - /// - /// For this to work, `new_self_ty` must have no escaping bound variables. - fn mk_trait_obligation_with_new_self_ty( - &self, - param_env: ty::ParamEnv<'tcx>, - trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, - ) -> PredicateObligation<'tcx>; - - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed; - - fn predicate_can_apply( - &self, - param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitPredicate<'tcx>, - ) -> bool; - - fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>); - - fn suggest_unsized_bound_if_applicable( - &self, - err: &mut Diagnostic, - obligation: &PredicateObligation<'tcx>, - ); - - fn annotate_source_of_ambiguity( - &self, - err: &mut Diagnostic, - impls: &[ambiguity::Ambiguity], - predicate: ty::Predicate<'tcx>, - ); - - fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>); - - fn maybe_indirection_for_unsized( - &self, - err: &mut Diagnostic, - item: &'tcx Item<'tcx>, - param: &'tcx GenericParam<'tcx>, - ) -> bool; - - fn is_recursive_obligation( - &self, - obligated_types: &mut Vec>, - cause_code: &ObligationCauseCode<'tcx>, - ) -> bool; - - fn get_standard_error_message( - &self, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, - message: Option, - predicate_is_const: bool, - append_const_msg: Option, - post_message: String, - ) -> String; - - fn get_safe_transmute_error_and_reason( - &self, - obligation: PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - span: Span, - ) -> GetSafeTransmuteErrorAndReason; - - fn add_tuple_trait_message( - &self, - obligation_cause_code: &ObligationCauseCode<'tcx>, - err: &mut Diagnostic, - ); - - fn try_to_add_help_message( - &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, - err: &mut Diagnostic, - span: Span, - is_fn_trait: bool, - suggested: bool, - unsatisfied_const: bool, - ); - - fn add_help_message_for_fn_trait( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - err: &mut Diagnostic, - implemented_kind: ty::ClosureKind, - params: ty::Binder<'tcx, Ty<'tcx>>, - ); - - fn maybe_add_note_for_unsatisfied_const( - &self, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, - err: &mut Diagnostic, - span: Span, - ) -> UnsatisfiedConst; - - fn report_closure_error( - &self, - obligation: &PredicateObligation<'tcx>, - closure_def_id: DefId, - found_kind: ty::ClosureKind, - kind: ty::ClosureKind, - trait_prefix: &'static str, - ) -> DiagnosticBuilder<'tcx>; - - fn report_cyclic_signature_error( - &self, - obligation: &PredicateObligation<'tcx>, - found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - terr: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx>; - - fn report_opaque_type_auto_trait_leakage( - &self, - obligation: &PredicateObligation<'tcx>, - def_id: DefId, - ) -> DiagnosticBuilder<'tcx>; - - fn report_signature_mismatch_error( - &self, - obligation: &PredicateObligation<'tcx>, - span: Span, - found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ) -> Result, ErrorGuaranteed>; - - fn report_not_const_evaluatable_error( - &self, - obligation: &PredicateObligation<'tcx>, - span: Span, - ) -> Result, ErrorGuaranteed>; -} - -impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension] +pub(super) impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { @@ -2414,6 +2146,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggested } + /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the + /// `trait_ref`. + /// + /// For this to work, `new_self_ty` must have no escaping bound variables. fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 52631d4353bfa..c4e8ea45dd32e 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -11,25 +11,6 @@ pub use rustc_middle::traits::query::OutlivesBound; pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator> + 'a; pub type Bounds<'a, 'tcx: 'a> = impl Iterator> + 'a; -pub trait InferCtxtExt<'a, 'tcx> { - /// Do *NOT* call this directly. - fn implied_bounds_tys_compat( - &'a self, - param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, - tys: &'a FxIndexSet>, - compat: bool, - ) -> BoundsCompat<'a, 'tcx>; - - /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat` - /// with `compat` set to `true`, otherwise `false`. - fn implied_bounds_tys( - &'a self, - param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, - tys: &'a FxIndexSet>, - ) -> Bounds<'a, 'tcx>; -} /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a @@ -130,7 +111,9 @@ fn implied_outlives_bounds<'a, 'tcx>( bounds } -impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { +#[extension] +pub impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { + /// Do *NOT* call this directly. fn implied_bounds_tys_compat( &'a self, param_env: ParamEnv<'tcx>, @@ -142,6 +125,8 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat)) } + /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat` + /// with `compat` set to `true`, otherwise `false`. fn implied_bounds_tys( &'a self, param_env: ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 049877bc5fed4..807540a1720a2 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -52,12 +52,22 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>; pub(super) struct InProgress; -pub trait NormalizeExt<'tcx> { +#[extension] +pub impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> { /// Normalize a value using the `AssocTypeNormalizer`. /// /// This normalization should be used when the type contains inference variables or the /// projection may be fallible. - fn normalize>>(&self, t: T) -> InferOk<'tcx, T>; + fn normalize>>(&self, value: T) -> InferOk<'tcx, T> { + if self.infcx.next_trait_solver() { + InferOk { value, obligations: Vec::new() } + } else { + let mut selcx = SelectionContext::new(self.infcx); + let Normalized { value, obligations } = + normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); + InferOk { value, obligations } + } + } /// Deeply normalizes `value`, replacing all aliases which can by normalized in /// the current environment. In the new solver this errors in case normalization @@ -73,25 +83,6 @@ pub trait NormalizeExt<'tcx> { /// existing fulfillment context in the old solver. Once we also eagerly prove goals with /// the old solver or have removed the old solver, remove `traits::fully_normalize` and /// rename this function to `At::fully_normalize`. - fn deeply_normalize>>( - self, - value: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result>>; -} - -impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> { - fn normalize>>(&self, value: T) -> InferOk<'tcx, T> { - if self.infcx.next_trait_solver() { - InferOk { value, obligations: Vec::new() } - } else { - let mut selcx = SelectionContext::new(self.infcx); - let Normalized { value, obligations } = - normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); - InferOk { value, obligations } - } - } - fn deeply_normalize>>( self, value: T, diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index a050b30317a05..e56ad101d2997 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -4,32 +4,8 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; -pub trait InferCtxtExt<'tcx> { - fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool; - - fn predicate_must_hold_considering_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool; - - fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool; - - fn evaluate_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result; - - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. - /*crate*/ - fn evaluate_obligation_no_overflow( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> EvaluationResult; -} - -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension] +pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { @@ -114,9 +90,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } } - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. + /// Helper function that canonicalizes and runs the query. If an + /// overflow results, we re-run it in the local context so we can + /// report a nice error. fn evaluate_obligation_no_overflow( &self, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 0b73fefd2da9d..7dd8a990c3fd6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -22,20 +22,8 @@ use super::NoSolution; pub use rustc_middle::traits::query::NormalizationResult; -pub trait QueryNormalizeExt<'tcx> { - /// Normalize a value using the `QueryNormalizer`. - /// - /// This normalization should *only* be used when the projection does not - /// have possible ambiguity or may not be well-formed. - /// - /// After codegen, when lifetimes do not matter, it is preferable to instead - /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. - fn query_normalize(self, value: T) -> Result, NoSolution> - where - T: TypeFoldable>; -} - -impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { +#[extension] +pub impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { /// Normalize `value` in the context of the inference context, /// yielding a resulting type, or an error if `value` cannot be /// normalized. If you don't care about regions, you should prefer diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index e9a592bdee799..57e3f72a2f3de 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -33,19 +33,7 @@ enum Inserted<'tcx> { ShouldRecurseOn(DefId), } -trait ChildrenExt<'tcx> { - fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); - fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); - - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - simplified_self: Option, - overlap_mode: OverlapMode, - ) -> Result, OverlapError<'tcx>>; -} - +#[extension] impl<'tcx> ChildrenExt<'tcx> for Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { @@ -247,22 +235,8 @@ where } } -pub trait GraphExt<'tcx> { - /// Insert a local impl into the specialization graph. If an existing impl - /// conflicts with it (has overlap, but neither specializes the other), - /// information about the area of overlap is returned in the `Err`. - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - overlap_mode: OverlapMode, - ) -> Result>, OverlapError<'tcx>>; - - /// Insert cached metadata mapping from a child impl back to its parent. - fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId); -} - -impl<'tcx> GraphExt<'tcx> for Graph { +#[extension] +pub impl<'tcx> GraphExt<'tcx> for Graph { /// Insert a local impl into the specialization graph. If an existing impl /// conflicts with it (has overlap, but neither specializes the other), /// information about the area of overlap is returned in the `Err`. diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index ed5d01d7048e6..7b0a4a69501ad 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -5,15 +5,8 @@ use rustc_middle::ty::{self, Ty}; use crate::traits::{NormalizeExt, Obligation}; -pub trait StructurallyNormalizeExt<'tcx> { - fn structurally_normalize( - &self, - ty: Ty<'tcx>, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result, Vec>>; -} - -impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { +#[extension] +pub impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { fn structurally_normalize( &self, ty: Ty<'tcx>, From a9dbf63087049549a74c0f31705df92bcf15098f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Feb 2024 17:18:56 +0000 Subject: [PATCH 06/15] Move trait into attr so it's greppable --- compiler/rustc_ast_lowering/src/lib.rs | 4 +-- compiler/rustc_borrowck/src/facts.rs | 4 +-- compiler/rustc_borrowck/src/place_ext.rs | 4 +-- .../src/region_infer/opaque_types.rs | 4 +-- .../rustc_borrowck/src/universal_regions.rs | 4 +-- .../src/collect/resolve_bound_vars.rs | 4 +-- .../src/infer/canonical/instantiate.rs | 4 +-- .../src/infer/error_reporting/mod.rs | 4 +-- compiler/rustc_infer/src/infer/mod.rs | 4 +-- compiler/rustc_infer/src/traits/engine.rs | 4 +-- compiler/rustc_macros/src/extension.rs | 35 ++++++++++++------- compiler/rustc_macros/src/lib.rs | 4 +-- compiler/rustc_middle/src/ty/layout.rs | 8 ++--- compiler/rustc_middle/src/ty/util.rs | 4 +-- compiler/rustc_trait_selection/src/infer.rs | 8 ++--- compiler/rustc_trait_selection/src/regions.rs | 4 +-- .../src/solve/eval_ctxt/mod.rs | 4 +-- .../src/solve/eval_ctxt/select.rs | 4 +-- .../src/solve/inspect/analyse.rs | 4 +-- .../rustc_trait_selection/src/solve/mod.rs | 4 +-- .../src/traits/engine.rs | 4 +-- .../traits/error_reporting/infer_ctxt_ext.rs | 4 +-- .../error_reporting/on_unimplemented.rs | 4 +-- .../src/traits/error_reporting/suggestions.rs | 4 +-- .../error_reporting/type_err_ctxt_ext.rs | 8 ++--- .../src/traits/outlives_bounds.rs | 4 +-- .../src/traits/project.rs | 4 +-- .../src/traits/query/evaluate_obligation.rs | 4 +-- .../src/traits/query/normalize.rs | 4 +-- .../traits/specialize/specialization_graph.rs | 8 ++--- .../src/traits/structural_normalize.rs | 4 +-- 31 files changed, 91 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e6a7c08429bd4..a5be91bb87209 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -191,8 +191,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } -#[extension] -impl ResolverAstLoweringExt for ResolverAstLowering { +#[extension(trait ResolverAstLoweringExt)] +impl ResolverAstLowering { fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { if let ExprKind::Path(None, path) = &expr.kind { // Don't perform legacy const generics rewriting if the path already diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index da14408fb6961..e7faec7bbac1e 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -25,8 +25,8 @@ impl polonius_engine::FactTypes for RustcFacts { pub type AllFacts = PoloniusFacts; -#[extension] -pub(crate) impl AllFactsExt for AllFacts { +#[extension(pub(crate) trait AllFactsExt)] +impl AllFacts { /// Returns `true` if there is a need to gather `AllFacts` given the /// current `-Z` flags. fn enabled(tcx: TyCtxt<'_>) -> bool { diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index ac8991ccf00bd..0f806df9da1da 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -5,8 +5,8 @@ use rustc_middle::mir::ProjectionElem; use rustc_middle::mir::{Body, Mutability, Place}; use rustc_middle::ty::{self, TyCtxt}; -#[extension] -pub impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { +#[extension(pub trait PlaceExt<'tcx>)] +impl<'tcx> Place<'tcx> { /// Returns `true` if we can safely ignore borrows of this place. /// This is true whenever there is no action that the user can do /// to the place `self` that would invalidate the borrow. This is true diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 4aac392ef392e..a5a906658b89f 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -226,8 +226,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } -#[extension] -pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Given the fully resolved, instantiated type for an opaque /// type, i.e., the value of an inference variable like C1 or C2 /// (*), computes the "definition type" for an opaque type diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index f9a8543e28d2b..a69f5335f7186 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -794,8 +794,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } } -#[extension] -impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { +#[extension(trait InferCtxtExt<'tcx>)] +impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars( &self, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 9fb6103183bbc..325a0ee9a18fd 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -28,8 +28,8 @@ use std::fmt; use crate::errors; -#[extension] -impl RegionExt for ResolvedArg { +#[extension(trait RegionExt)] +impl ResolvedArg { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { debug!("ResolvedArg::early: def_id={:?}", param.def_id); (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id())) diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index 54940a2b4988c..c8adbf7f57ab4 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -13,8 +13,8 @@ use rustc_middle::ty::{self, TyCtxt}; /// FIXME(-Znext-solver): This or public because it is shared with the /// new trait solver implementation. We should deduplicate canonicalization. -#[extension] -pub impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { +#[extension(pub trait CanonicalExt<'tcx, V>)] +impl<'tcx, V> Canonical<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 37efafc5972f2..8f06a5eeb5f43 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2786,8 +2786,8 @@ pub enum FailureCode { Error0644, } -#[extension] -pub impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { +#[extension(pub trait ObligationCauseExt<'tcx>)] +impl<'tcx> ObligationCause<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b9ebd685ca9f2..243558b11a863 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -626,8 +626,8 @@ pub struct InferCtxtBuilder<'tcx> { next_trait_solver: bool, } -#[extension] -pub impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { +#[extension(pub trait TyCtxtInferExt<'tcx>)] +impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 79a29e2496807..ffd120fa4a42c 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -52,8 +52,8 @@ pub trait TraitEngine<'tcx>: 'tcx { ) -> Vec>; } -#[extension] -pub impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { +#[extension(pub trait TraitEngineExt<'tcx>)] +impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { fn register_predicate_obligations( &mut self, infcx: &InferCtxt<'tcx>, diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs index 7bb07285ae205..7830137f21891 100644 --- a/compiler/rustc_macros/src/extension.rs +++ b/compiler/rustc_macros/src/extension.rs @@ -8,10 +8,12 @@ use syn::{ Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, }; -pub(crate) fn extension(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - // Parse the input tokens into a syntax tree - let Extension { attrs, generics, vis, trait_, self_ty, items } = - parse_macro_input!(input as Extension); +pub(crate) fn extension( + attr: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr); + let Impl { attrs, generics, self_ty, items } = parse_macro_input!(input as Impl); let headers: Vec<_> = items .iter() .map(|item| match item { @@ -105,23 +107,32 @@ fn scrub_header(mut sig: Signature) -> Signature { sig } -struct Extension { - attrs: Vec, +struct ExtensionAttr { vis: Visibility, - generics: Generics, trait_: Path, +} + +impl Parse for ExtensionAttr { + fn parse(input: ParseStream<'_>) -> syn::Result { + let vis = input.parse()?; + let _: Token![trait] = input.parse()?; + let trait_ = input.parse()?; + Ok(ExtensionAttr { vis, trait_ }) + } +} + +struct Impl { + attrs: Vec, + generics: Generics, self_ty: Type, items: Vec, } -impl Parse for Extension { +impl Parse for Impl { fn parse(input: ParseStream<'_>) -> syn::Result { let attrs = input.call(Attribute::parse_outer)?; - let vis = input.parse()?; let _: Token![impl] = input.parse()?; let generics = input.parse()?; - let trait_ = input.parse()?; - let _: Token![for] = input.parse()?; let self_ty = input.parse()?; let content; @@ -131,6 +142,6 @@ impl Parse for Extension { items.push(content.parse()?); } - Ok(Extension { attrs, generics, vis, trait_, self_ty, items }) + Ok(Impl { attrs, generics, self_ty, items }) } } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 841f5c06126c2..619f93c8a533a 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -42,8 +42,8 @@ pub fn symbols(input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn extension(_attr: TokenStream, input: TokenStream) -> TokenStream { - extension::extension(input) +pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { + extension::extension(attr, input) } decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 1fb04f5bbfe34..c1e33fe114fb5 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -23,8 +23,8 @@ use std::fmt; use std::num::NonZero; use std::ops::Bound; -#[extension] -pub impl IntegerExt for Integer { +#[extension(pub trait IntegerExt)] +impl Integer { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> { match (*self, signed) { @@ -111,8 +111,8 @@ pub impl IntegerExt for Integer { } } -#[extension] -pub impl PrimitiveExt for Primitive { +#[extension(pub trait PrimitiveExt)] +impl Primitive { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 98d19083aaba7..3f539945841b6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -96,8 +96,8 @@ impl<'tcx> Discr<'tcx> { } } -#[extension] -pub impl IntTypeExt for IntegerType { +#[extension(pub trait IntTypeExt)] +impl IntegerType { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { IntegerType::Pointer(true) => tcx.types.isize, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 8406880477e4d..f694dd0070363 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -17,8 +17,8 @@ use std::fmt::Debug; pub use rustc_infer::infer::*; -#[extension] -pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); @@ -105,8 +105,8 @@ pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } } -#[extension] -pub impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { +#[extension(pub trait InferCtxtBuilderExt<'tcx>)] +impl<'tcx> InferCtxtBuilder<'tcx> { /// The "main method" for a canonicalized trait query. Given the /// canonical key `canonical_key`, this method will create a new /// inference context, instantiate the key, and run your operation diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index dc9edb6063d75..222d0b4d5e75d 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -3,8 +3,8 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; -#[extension] -pub impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtRegionExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Resolve regions, using the deep normalizer to normalize any type-outlives /// obligations in the process. This is in `rustc_trait_selection` because /// we need to normalize. diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 3abdc4a333053..5c1e8bf616fd4 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -131,8 +131,8 @@ pub enum GenerateProofTree { Never, } -#[extension] -pub impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtEvalExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. /// /// Using this while inside of the solver is wrong as it uses a new diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 406f4c2f6151e..7196a5af259fe 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -17,8 +17,8 @@ use crate::solve::inspect::ProofTreeBuilder; use crate::traits::StructurallyNormalizeExt; use crate::traits::TraitEngineExt; -#[extension] -pub impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtSelectExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { fn select_in_new_trait_solver( &self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 1c6c2ff594a1b..47f207e1d75c1 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -216,8 +216,8 @@ pub trait ProofTreeVisitor<'tcx> { fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow; } -#[extension] -pub impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait ProofTreeInferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { fn visit_proof_tree>( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 11e1e72e04e23..8b163d47d3475 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -61,8 +61,8 @@ enum GoalEvaluationKind { Nested { is_normalizes_to_hack: IsNormalizesToHack }, } -#[extension] -impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { +#[extension(trait CanonicalResponseExt)] +impl<'tcx> Canonical<'tcx, Response<'tcx>> { fn has_no_inference_or_external_constraints(&self) -> bool { self.value.external_constraints.region_constraints.is_empty() && self.value.var_values.is_identity() diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index b234b8a9d0327..1aaadf6cf044a 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -27,8 +27,8 @@ use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::Variance; use rustc_middle::ty::{self, Ty, TyCtxt}; -#[extension] -pub impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { +#[extension(pub trait TraitEngineExt<'tcx>)] +impl<'tcx> dyn TraitEngine<'tcx> { fn new(infcx: &InferCtxt<'tcx>) -> Box { if infcx.next_trait_solver() { Box::new(NextFulfillmentCtxt::new(infcx)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 80581d01f6b0a..4788ecbe3e290 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -11,8 +11,8 @@ use super::ArgKind; pub use rustc_infer::traits::error_reporting::*; -#[extension] -pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Given some node representing a fn-like thing in the HIR map, /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 7d7f415c7bb7a..4ba2da95fb324 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -38,8 +38,8 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ sym::Trait, ]; -#[extension] -pub impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, trait_ref: ty::PolyTraitRef<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 58c731a8ed7f4..7de13bf0c0299 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -236,8 +236,8 @@ pub fn suggest_restriction<'tcx>( } } -#[extension] -pub impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_restricting_param_bound( &self, err: &mut Diagnostic, 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 92992de64ffb9..bec6cda5fece9 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 @@ -57,8 +57,8 @@ use super::{ pub use rustc_infer::traits::error_reporting::*; -#[extension] -pub impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn report_fulfillment_errors( &self, mut errors: Vec>, @@ -1326,8 +1326,8 @@ pub impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } -#[extension] -pub(super) impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { +#[extension(pub(super) trait InferCtxtPrivExt<'tcx>)] +impl<'tcx> TypeErrCtxt<'_, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index c4e8ea45dd32e..6825dd4ac713d 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -111,8 +111,8 @@ fn implied_outlives_bounds<'a, 'tcx>( bounds } -#[extension] -pub impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'a, 'tcx>)] +impl<'a, 'tcx: 'a> InferCtxt<'tcx> { /// Do *NOT* call this directly. fn implied_bounds_tys_compat( &'a self, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 807540a1720a2..279c00031875a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -52,8 +52,8 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>; pub(super) struct InProgress; -#[extension] -pub impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> { +#[extension(pub trait NormalizeExt<'tcx>)] +impl<'tcx> At<'_, 'tcx> { /// Normalize a value using the `AssocTypeNormalizer`. /// /// This normalization should be used when the type contains inference variables or the diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index e56ad101d2997..16ee9fadab4fc 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -4,8 +4,8 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; -#[extension] -pub impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +#[extension(pub trait InferCtxtExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 7dd8a990c3fd6..6ed9ac910272b 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -22,8 +22,8 @@ use super::NoSolution; pub use rustc_middle::traits::query::NormalizationResult; -#[extension] -pub impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { +#[extension(pub trait QueryNormalizeExt<'tcx>)] +impl<'cx, 'tcx> At<'cx, 'tcx> { /// Normalize `value` in the context of the inference context, /// yielding a resulting type, or an error if `value` cannot be /// normalized. If you don't care about regions, you should prefer diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 57e3f72a2f3de..f3b77d689225c 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -33,8 +33,8 @@ enum Inserted<'tcx> { ShouldRecurseOn(DefId), } -#[extension] -impl<'tcx> ChildrenExt<'tcx> for Children { +#[extension(trait ChildrenExt<'tcx>)] +impl<'tcx> Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); @@ -235,8 +235,8 @@ where } } -#[extension] -pub impl<'tcx> GraphExt<'tcx> for Graph { +#[extension(pub trait GraphExt<'tcx>)] +impl<'tcx> Graph { /// Insert a local impl into the specialization graph. If an existing impl /// conflicts with it (has overlap, but neither specializes the other), /// information about the area of overlap is returned in the `Err`. diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 7b0a4a69501ad..2f428564ae736 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -5,8 +5,8 @@ use rustc_middle::ty::{self, Ty}; use crate::traits::{NormalizeExt, Obligation}; -#[extension] -pub impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { +#[extension(pub trait StructurallyNormalizeExt<'tcx>)] +impl<'tcx> At<'_, 'tcx> { fn structurally_normalize( &self, ty: Ty<'tcx>, From f624d55ea77b1b24e9294818ee1d6b1da9d0ec2d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 16 Feb 2024 15:07:32 +0000 Subject: [PATCH 07/15] Nits --- compiler/rustc_infer/src/traits/engine.rs | 1 + compiler/rustc_macros/src/extension.rs | 9 ++++++++- .../rustc_trait_selection/src/traits/query/normalize.rs | 6 ++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index ffd120fa4a42c..c495810858f7f 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -64,6 +64,7 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { } } + #[must_use] fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { let errors = self.select_where_possible(infcx); if !errors.is_empty() { diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs index 7830137f21891..5377bbdfeabd0 100644 --- a/compiler/rustc_macros/src/extension.rs +++ b/compiler/rustc_macros/src/extension.rs @@ -68,7 +68,14 @@ pub(crate) fn extension( /// Only keep `#[doc]` attrs. fn scrub_attrs(attrs: &[Attribute]) -> Vec { - attrs.into_iter().cloned().filter(|attr| attr.path().segments[0].ident == "doc").collect() + attrs + .into_iter() + .cloned() + .filter(|attr| { + let ident = &attr.path().segments[0].ident; + ident == "doc" || ident == "must_use" + }) + .collect() } /// Scrub arguments so that they're valid for trait signatures. diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 6ed9ac910272b..0f6c0abd280e4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -37,6 +37,12 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { /// normalizing, but for now should be used only when we actually /// know that normalization will succeed, since error reporting /// and other details are still "under development". + /// + /// This normalization should *only* be used when the projection does not + /// have possible ambiguity or may not be well-formed. + /// + /// After codegen, when lifetimes do not matter, it is preferable to instead + /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. fn query_normalize(self, value: T) -> Result, NoSolution> where T: TypeFoldable>, From 4b732c990d9bf6b2de86f05db714da896fb113ce Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 18:26:34 +0100 Subject: [PATCH 08/15] Let rustbot ping me on changes to match lowering --- triagebot.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 383b89b18df57..94d8601e193bb 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -480,12 +480,16 @@ cc = ["@lcnr", "@compiler-errors"] message = "Some changes occurred in diagnostic error codes" cc = ["@GuillaumeGomez"] +[mentions."compiler/rustc_mir_build/src/build/matches"] +message = "Some changes occurred in match lowering" +cc = ["@Nadrieril"] + [mentions."compiler/rustc_mir_build/src/thir/pattern"] -message = "Some changes might have occurred in exhaustiveness checking" +message = "Some changes occurred in match checking" cc = ["@Nadrieril"] [mentions."compiler/rustc_pattern_analysis"] -message = "Some changes might have occurred in exhaustiveness checking" +message = "Some changes occurred in exhaustiveness checking" cc = ["@Nadrieril"] [mentions."library/core/src/intrinsics/simd.rs"] From 6c7827c03e11135a27e446d806ada126bf64a7c1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 18:31:13 +0100 Subject: [PATCH 09/15] Add myself to review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 94d8601e193bb..32b22e52a20a2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -662,6 +662,7 @@ compiler-team = [ ] compiler-team-contributors = [ "@TaKO8Ki", + "@Nadrieril", "@nnethercote", "@fmease", ] From d855ca044da4ed42eb60dbd20cc1341f35d8e0fc Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 16 Feb 2024 18:51:22 +0000 Subject: [PATCH 10/15] Ensure `./configure` works when `configure.py` path contains spaces --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 81e2001e4a583..e8627c9f0d50c 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #!/bin/sh -script="$(dirname $0)"/src/bootstrap/configure.py +script="$(dirname "$0")"/src/bootstrap/configure.py try() { cmd=$1 @@ -15,4 +15,4 @@ try python3 "$@" try python2.7 "$@" try python27 "$@" try python2 "$@" -exec python $script "$@" +exec python "$script" "$@" From 6a671bdbf1c0b68af05dd34595e4c10d6fe3abe7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 16 Feb 2024 17:29:34 +0000 Subject: [PATCH 11/15] Give the `assume` intrinsic a fallback body --- .../rustc_hir_analysis/src/check/intrinsic.rs | 2 +- library/core/src/intrinsics.rs | 36 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f0f6bfff64aaa..fcc0ec69d5e6f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -407,7 +407,7 @@ pub fn check_intrinsic_type( } sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), - sym::assume => (0, 0, vec![tcx.types.bool], Ty::new_unit(tcx)), + sym::assume => (0, 1, vec![tcx.types.bool], Ty::new_unit(tcx)), sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index fc6c1eab803d7..7b73396afc688 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -937,20 +937,30 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn unreachable() -> !; - /// Informs the optimizer that a condition is always true. - /// If the condition is false, the behavior is undefined. - /// - /// No code is generated for this intrinsic, but the optimizer will try - /// to preserve it (and its condition) between passes, which may interfere - /// with optimization of surrounding code and reduce performance. It should - /// not be used if the invariant can be discovered by the optimizer on its - /// own, or if it does not enable any significant optimizations. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_const_stable(feature = "const_assume", since = "1.77.0")] - #[rustc_nounwind] - pub fn assume(b: bool); +} + +/// Informs the optimizer that a condition is always true. +/// If the condition is false, the behavior is undefined. +/// +/// No code is generated for this intrinsic, but the optimizer will try +/// to preserve it (and its condition) between passes, which may interfere +/// with optimization of surrounding code and reduce performance. It should +/// not be used if the invariant can be discovered by the optimizer on its +/// own, or if it does not enable any significant optimizations. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_const_stable(feature = "const_assume", since = "1.77.0")] +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub const unsafe fn assume(b: bool) { + if !b { + // SAFETY: the caller must guarantee the argument is never `false` + unsafe { unreachable() } + } +} +extern "rust-intrinsic" { /// Hints to the compiler that branch condition is likely to be true. /// Returns the value passed to it. /// From dd40a80102950a06d0467a2e7d7203ee85911470 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 16 Feb 2024 17:45:46 +0000 Subject: [PATCH 12/15] Give the (`un`)`likely` intrinsics fallback bodies --- .../rustc_hir_analysis/src/check/intrinsic.rs | 4 +- library/core/src/intrinsics.rs | 68 ++++++++++--------- .../ui/intrinsics/safe-intrinsic-mismatch.rs | 8 +-- .../intrinsics/safe-intrinsic-mismatch.stderr | 21 +++--- tests/ui/reify-intrinsic.rs | 5 +- tests/ui/reify-intrinsic.stderr | 11 ++- 6 files changed, 61 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index fcc0ec69d5e6f..903c98e8317fb 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -408,8 +408,8 @@ pub fn check_intrinsic_type( sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), sym::assume => (0, 1, vec![tcx.types.bool], Ty::new_unit(tcx)), - sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), - sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), + sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool), + sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 7b73396afc688..ce1876d5a2f2f 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -960,39 +960,45 @@ pub const unsafe fn assume(b: bool) { } } -extern "rust-intrinsic" { - /// Hints to the compiler that branch condition is likely to be true. - /// Returns the value passed to it. - /// - /// Any use other than with `if` statements will probably not have an effect. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_likely", issue = "none")] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn likely(b: bool) -> bool; +/// Hints to the compiler that branch condition is likely to be true. +/// Returns the value passed to it. +/// +/// Any use other than with `if` statements will probably not have an effect. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_const_unstable(feature = "const_likely", issue = "none")] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_nounwind] +pub const fn likely(b: bool) -> bool { + b +} - /// Hints to the compiler that branch condition is likely to be false. - /// Returns the value passed to it. - /// - /// Any use other than with `if` statements will probably not have an effect. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_likely", issue = "none")] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn unlikely(b: bool) -> bool; +/// Hints to the compiler that branch condition is likely to be false. +/// Returns the value passed to it. +/// +/// Any use other than with `if` statements will probably not have an effect. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_const_unstable(feature = "const_likely", issue = "none")] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_nounwind] +pub const fn unlikely(b: bool) -> bool { + b +} +extern "rust-intrinsic" { /// Executes a breakpoint trap, for inspection by a debugger. /// /// This intrinsic does not have a stable counterpart. diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs index fcd6612f1259d..23cd5f1083534 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs @@ -5,12 +5,12 @@ extern "rust-intrinsic" { fn size_of() -> usize; //~ ERROR intrinsic safety mismatch //~^ ERROR intrinsic safety mismatch - - #[rustc_safe_intrinsic] - fn assume(b: bool); //~ ERROR intrinsic safety mismatch - //~^ ERROR intrinsic safety mismatch } +#[rustc_intrinsic] +const fn assume(_b: bool) {} //~ ERROR intrinsic safety mismatch +//~| ERROR intrinsic has wrong type + #[rustc_intrinsic] const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} //~^ ERROR intrinsic safety mismatch diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr index 0b579121ac18e..2e0812d6472b6 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr @@ -4,12 +4,6 @@ error: intrinsic safety mismatch between list of intrinsics within the compiler LL | fn size_of() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume` - --> $DIR/safe-intrinsic-mismatch.rs:10:5 - | -LL | fn assume(b: bool); - | ^^^^^^^^^^^^^^^^^^ - error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of` --> $DIR/safe-intrinsic-mismatch.rs:6:5 | @@ -19,12 +13,19 @@ LL | fn size_of() -> usize; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume` - --> $DIR/safe-intrinsic-mismatch.rs:10:5 + --> $DIR/safe-intrinsic-mismatch.rs:11:1 | -LL | fn assume(b: bool); - | ^^^^^^^^^^^^^^^^^^ +LL | const fn assume(_b: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: intrinsic has wrong type + --> $DIR/safe-intrinsic-mismatch.rs:11:16 | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +LL | const fn assume(_b: bool) {} + | ^ expected unsafe fn, found normal fn + | + = note: expected signature `unsafe fn(_)` + found signature `fn(_)` error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `const_deallocate` --> $DIR/safe-intrinsic-mismatch.rs:15:1 diff --git a/tests/ui/reify-intrinsic.rs b/tests/ui/reify-intrinsic.rs index 9eb2f724017ed..d8a268bd33a81 100644 --- a/tests/ui/reify-intrinsic.rs +++ b/tests/ui/reify-intrinsic.rs @@ -13,10 +13,9 @@ fn b() { } fn c() { - let _ = [ - std::intrinsics::likely, + let _: [unsafe extern "rust-intrinsic" fn(bool) -> bool; 2] = [ + std::intrinsics::likely, //~ ERROR cannot coerce std::intrinsics::unlikely, - //~^ ERROR cannot coerce ]; } diff --git a/tests/ui/reify-intrinsic.stderr b/tests/ui/reify-intrinsic.stderr index 310b6c224e0e7..0119a1a6650d0 100644 --- a/tests/ui/reify-intrinsic.stderr +++ b/tests/ui/reify-intrinsic.stderr @@ -16,14 +16,13 @@ LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: cannot coerce intrinsics to function pointers - --> $DIR/reify-intrinsic.rs:18:9 + --> $DIR/reify-intrinsic.rs:17:9 | -LL | std::intrinsics::unlikely, - | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers +LL | std::intrinsics::likely, + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers | - = note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}` - found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}` - = note: different fn items have unique types, even if their signatures are the same + = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(_) -> _` + found fn item `fn(_) -> _ {likely}` error: aborting due to 3 previous errors From 40719384e1da64776d0ee67a84ffdfacc67816b0 Mon Sep 17 00:00:00 2001 From: Steven Date: Sat, 16 Dec 2023 19:29:45 -0500 Subject: [PATCH 13/15] Use a hardcoded constant instead of calling OpenProcessToken. Now that Win 7 support is dropped, we can resurrect #90144. GetCurrentProcessToken is defined in processthreadsapi.h as: FORCEINLINE HANDLE GetCurrentProcessToken ( VOID ) { return (HANDLE)(LONG_PTR) -4; } Since it's very unlikely that this constant will ever change, let's just use it instead of making calls to get the same information. --- library/std/src/sys/pal/windows/os.rs | 31 ++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 829dd5eb97ac2..58163f7a73faf 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -1,5 +1,6 @@ //! Implementation of `std::os` functionality for Windows. +#![cfg_attr(bootstrap, allow(unexpected_cfgs))] #![allow(nonstandard_style)] #[cfg(test)] @@ -318,13 +319,33 @@ pub fn temp_dir() -> PathBuf { super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap() } -#[cfg(not(target_vendor = "uwp"))] +#[cfg(all(not(target_vendor = "uwp"), not(target_vendor = "win7")))] +fn home_dir_crt() -> Option { + unsafe { + // Defined in processthreadsapi.h. + const CURRENT_PROCESS_TOKEN: usize = -4_isize as usize; + + super::fill_utf16_buf( + |buf, mut sz| { + match c::GetUserProfileDirectoryW( + ptr::invalid_mut(CURRENT_PROCESS_TOKEN), + buf, + &mut sz, + ) { + 0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0, + 0 => sz, + _ => sz - 1, // sz includes the null terminator + } + }, + super::os2path, + ) + .ok() + } +} + +#[cfg(target_vendor = "win7")] fn home_dir_crt() -> Option { unsafe { - // The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below - // instead of us having to go through these multiple steps to get a token. However this is - // not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7 - // we can simplify this code. See #90144 for details. use crate::sys::handle::Handle; let me = c::GetCurrentProcess(); From 3b63edeb9999b5b29826f018b2eabe702bee4e97 Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 16 Feb 2024 23:55:58 +0000 Subject: [PATCH 14/15] Remove cfg_attr --- library/std/src/sys/pal/windows/os.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 58163f7a73faf..73cb2db8b79e5 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -1,6 +1,5 @@ //! Implementation of `std::os` functionality for Windows. -#![cfg_attr(bootstrap, allow(unexpected_cfgs))] #![allow(nonstandard_style)] #[cfg(test)] From 340f8aac7e2da164134338986b46fb4a26fe185b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Feb 2024 14:27:08 +0100 Subject: [PATCH 15/15] const_mut_refs: allow mutable refs to statics --- .../src/transform/check_consts/check.rs | 37 ++++++++++++++-- .../src/transform/check_consts/qualifs.rs | 24 +++++++++++ .../const-ref-to-static-linux-vtable.rs | 43 +++++++++++++++++++ .../ui/consts/issue-17718-const-bad-values.rs | 1 + .../issue-17718-const-bad-values.stderr | 12 +++++- tests/ui/consts/miri_unleashed/box.stderr | 2 +- .../mutable_references_err.32bit.stderr | 2 +- .../mutable_references_err.64bit.stderr | 2 +- tests/ui/consts/mut-ptr-to-static.rs | 40 +++++++++++++++++ tests/ui/error-codes/E0017.rs | 8 ++-- tests/ui/error-codes/E0017.stderr | 36 +++------------- tests/ui/error-codes/E0388.rs | 4 +- tests/ui/error-codes/E0388.stderr | 24 +++-------- 13 files changed, 173 insertions(+), 62 deletions(-) create mode 100644 tests/ui/consts/const-ref-to-static-linux-vtable.rs create mode 100644 tests/ui/consts/mut-ptr-to-static.rs 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 96c9e740568cc..a3c4734f0a391 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -344,7 +344,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { visitor.visit_ty(ty); } - fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) { + fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) { match self.const_kind() { // In a const fn all borrows are transient or point to the places given via // references in the arguments (so we already checked them with @@ -355,10 +355,19 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // to mutable memory. hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), _ => { + // For indirect places, we are not creating a new permanent borrow, it's just as + // transient as the already existing one. For reborrowing references this is handled + // at the top of `visit_rvalue`, but for raw pointers we handle it here. + // Pointers/references to `static mut` and cases where the `*` is not the first + // projection also end up here. // Locals with StorageDead do not live beyond the evaluation and can // thus safely be borrowed without being able to be leaked to the final // value of the constant. - if self.local_has_storage_dead(local) { + // Note: This is only sound if every local that has a `StorageDead` has a + // `StorageDead` in every control flow path leading to a `return` terminator. + // The good news is that interning will detect if any unexpected mutable + // pointer slips through. + if place.is_indirect() || self.local_has_storage_dead(place.local) { self.check_op(ops::TransientMutBorrow(kind)); } else { self.check_op(ops::MutBorrow(kind)); @@ -390,6 +399,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); // Special-case reborrows to be more like a copy of a reference. + // FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost + // projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`. + // All those cases are handled below with shared/mutable borrows. + // Once `const_mut_refs` is stable, we should be able to entirely remove this special case. + // (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.) match *rvalue { Rvalue::Ref(_, kind, place) => { if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { @@ -460,7 +474,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if !is_allowed { self.check_mut_borrow( - place.local, + place, if matches!(rvalue, Rvalue::Ref(..)) { hir::BorrowKind::Ref } else { @@ -478,7 +492,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { place.as_ref(), ); - if borrowed_place_has_mut_interior { + // If the place is indirect, this is basically a reborrow. We have a reborrow + // special case above, but for raw pointers and pointers/references to `static` and + // when the `*` is not the first projection, `place_as_reborrow` does not recognize + // them as such, so we end up here. This should probably be considered a + // `TransientCellBorrow` (we consider the equivalent mutable case a + // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and + // it is too much of a breaking change to take back. + if borrowed_place_has_mut_interior && !place.is_indirect() { match self.const_kind() { // In a const fn all borrows are transient or point to the places given via // references in the arguments (so we already checked them with @@ -495,6 +516,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // final value. // Note: This is only sound if every local that has a `StorageDead` has a // `StorageDead` in every control flow path leading to a `return` terminator. + // The good news is that interning will detect if any unexpected mutable + // pointer slips through. if self.local_has_storage_dead(place.local) { self.check_op(ops::TransientCellBorrow); } else { @@ -948,6 +971,12 @@ fn place_as_reborrow<'tcx>( ) -> Option> { match place.as_ref().last_projection() { Some((place_base, ProjectionElem::Deref)) => { + // FIXME: why do statics and raw pointers get excluded here? This makes + // some code involving mutable pointers unstable, but it is unclear + // why that code is treated differently from mutable references. + // Once TransientMutBorrow and TransientCellBorrow are stable, + // this can probably be cleaned up without any behavioral changes. + // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` // that points to the allocation for the static. Don't treat these as reborrows. if body.local_decls[place_base.local].is_ref_to_static() { 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 67fef20807910..7eb3c181d6958 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -74,6 +74,13 @@ pub trait Qualif { adt: AdtDef<'tcx>, args: GenericArgsRef<'tcx>, ) -> bool; + + /// Returns `true` if this `Qualif` behaves sructurally for pointers and references: + /// the pointer/reference qualifies if and only if the pointee qualifies. + /// + /// (This is currently `false` for all our instances, but that may change in the future. Also, + /// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.) + fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool; } /// Constant containing interior mutability (`UnsafeCell`). @@ -103,6 +110,10 @@ impl Qualif for HasMutInterior { // It arises structurally for all other types. adt.is_unsafe_cell() } + + fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { + false + } } /// Constant containing an ADT that implements `Drop`. @@ -131,6 +142,10 @@ impl Qualif for NeedsDrop { ) -> bool { adt.has_dtor(cx.tcx) } + + fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { + false + } } /// Constant containing an ADT that implements non-const `Drop`. @@ -210,6 +225,10 @@ impl Qualif for NeedsNonConstDrop { ) -> bool { adt.has_non_const_dtor(cx.tcx) } + + fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { + false + } } // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. @@ -303,6 +322,11 @@ where return false; } + if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) { + // We have to assume that this qualifies. + return true; + } + place = place_base; } diff --git a/tests/ui/consts/const-ref-to-static-linux-vtable.rs b/tests/ui/consts/const-ref-to-static-linux-vtable.rs new file mode 100644 index 0000000000000..9325746c1e725 --- /dev/null +++ b/tests/ui/consts/const-ref-to-static-linux-vtable.rs @@ -0,0 +1,43 @@ +//@check-pass +//! This is the reduced version of the "Linux kernel vtable" use-case. +#![feature(const_mut_refs, const_refs_to_static)] +use std::ptr::addr_of_mut; + +#[repr(C)] +struct ThisModule(i32); + +trait Module { + const THIS_MODULE_PTR: *mut ThisModule; +} + +struct MyModule; + +// Generated by a macro. +extern "C" { + static mut THIS_MODULE: ThisModule; +} + +// Generated by a macro. +impl Module for MyModule { + const THIS_MODULE_PTR: *mut ThisModule = unsafe { addr_of_mut!(THIS_MODULE) }; +} + +struct Vtable { + module: *mut ThisModule, + foo_fn: fn(*mut ()) -> i32, +} + +trait Foo { + type Mod: Module; + + fn foo(&mut self) -> i32; +} + +fn generate_vtable() -> &'static Vtable { + &Vtable { + module: T::Mod::THIS_MODULE_PTR, + foo_fn: |ptr| unsafe { &mut *ptr.cast::() }.foo(), + } +} + +fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 0299bfef1b49a..e112a346b656d 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -6,5 +6,6 @@ const C1: &'static mut [usize] = &mut []; static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; //~^ ERROR: referencing statics in constants +//~| ERROR: mutable references are not allowed fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 57fcb1c7e9a52..e755e5601a87d 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -16,7 +16,17 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. = help: to fix this, the value can be extracted to a `const` and then used. -error: aborting due to 2 previous errors +error[E0658]: mutable references are not allowed in constants + --> $DIR/issue-17718-const-bad-values.rs:7:41 + | +LL | const C2: &'static mut usize = unsafe { &mut S }; + | ^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` 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 Some errors have detailed explanations: E0658, E0764. For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/miri_unleashed/box.stderr b/tests/ui/consts/miri_unleashed/box.stderr index 5229f1e50cd44..a0518c99cda56 100644 --- a/tests/ui/consts/miri_unleashed/box.stderr +++ b/tests/ui/consts/miri_unleashed/box.stderr @@ -16,7 +16,7 @@ help: skipping check for `const_mut_refs` feature | LL | &mut *(Box::new(0)) | ^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate +help: skipping check for `const_mut_refs` feature --> $DIR/box.rs:8:5 | LL | &mut *(Box::new(0)) diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index 401cf46710afd..82739c08cf1bd 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -114,7 +114,7 @@ help: skipping check for `const_refs_to_static` feature | LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ^^^ -help: skipping check that does not even have a feature gate +help: skipping check for `const_mut_refs` feature --> $DIR/mutable_references_err.rs:32:35 | LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index 0eb01f5b77388..844483d88e934 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -114,7 +114,7 @@ help: skipping check for `const_refs_to_static` feature | LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ^^^ -help: skipping check that does not even have a feature gate +help: skipping check for `const_mut_refs` feature --> $DIR/mutable_references_err.rs:32:35 | LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; diff --git a/tests/ui/consts/mut-ptr-to-static.rs b/tests/ui/consts/mut-ptr-to-static.rs new file mode 100644 index 0000000000000..d8a788bb37d1b --- /dev/null +++ b/tests/ui/consts/mut-ptr-to-static.rs @@ -0,0 +1,40 @@ +//@run-pass +#![feature(const_mut_refs)] +#![feature(sync_unsafe_cell)] + +use std::cell::SyncUnsafeCell; +use std::ptr; + +#[repr(C)] +struct SyncPtr { + foo: *mut u32, +} +unsafe impl Sync for SyncPtr {} + +static mut STATIC: u32 = 42; + +static INTERIOR_MUTABLE_STATIC: SyncUnsafeCell = SyncUnsafeCell::new(42); + +// A static that mutably points to STATIC. +static PTR: SyncPtr = SyncPtr { + foo: unsafe { ptr::addr_of_mut!(STATIC) }, +}; +static INTERIOR_MUTABLE_PTR: SyncPtr = SyncPtr { + foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32, +}; + +fn main() { + let ptr = PTR.foo; + unsafe { + assert_eq!(*ptr, 42); + *ptr = 0; + assert_eq!(*PTR.foo, 0); + } + + let ptr = INTERIOR_MUTABLE_PTR.foo; + unsafe { + assert_eq!(*ptr, 42); + *ptr = 0; + assert_eq!(*INTERIOR_MUTABLE_PTR.foo, 0); + } +} diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs index 9d3433fa543fd..c128c2779e245 100644 --- a/tests/ui/error-codes/E0017.rs +++ b/tests/ui/error-codes/E0017.rs @@ -1,3 +1,5 @@ +#![feature(const_mut_refs)] + static X: i32 = 1; const C: i32 = 2; static mut M: i32 = 3; @@ -5,14 +7,12 @@ static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed //~| WARN taking a mutable -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 -//~| ERROR cannot borrow -//~| ERROR mutable references are not allowed +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow immutable static item `X` as mutable static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed //~| WARN taking a mutable -static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR mutable references are not +static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index 2a70f2ee0ae82..eb626a7fe3a98 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -14,7 +14,7 @@ LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { addr_of_mut!(M) }; | ~~~~~~~~~~~~~~~ warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:5:30 + --> $DIR/E0017.rs:7:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ @@ -22,36 +22,20 @@ LL | const CR: &'static mut i32 = &mut C; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/E0017.rs:2:1 + --> $DIR/E0017.rs:4:1 | LL | const C: i32 = 2; | ^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/E0017.rs:5:30 + --> $DIR/E0017.rs:7:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ -error[E0658]: mutation through a reference is not allowed in statics - --> $DIR/E0017.rs:8:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` 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[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:8:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:8:39 + --> $DIR/E0017.rs:10:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable @@ -65,7 +49,7 @@ LL | static CONST_REF: &'static mut i32 = &mut C; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/E0017.rs:2:1 + --> $DIR/E0017.rs:4:1 | LL | const C: i32 = 2; | ^^^^^^^^^^^^ @@ -76,13 +60,7 @@ error[E0764]: mutable references are not allowed in the final value of statics LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:15:52 - | -LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; - | ^^^^^^ - -error: aborting due to 6 previous errors; 3 warnings emitted +error: aborting due to 3 previous errors; 3 warnings emitted -Some errors have detailed explanations: E0596, E0658, E0764. +Some errors have detailed explanations: E0596, E0764. For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/error-codes/E0388.rs b/tests/ui/error-codes/E0388.rs index 6049d95f0d277..bd371328e6bc9 100644 --- a/tests/ui/error-codes/E0388.rs +++ b/tests/ui/error-codes/E0388.rs @@ -3,9 +3,7 @@ const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed //~| WARN taking a mutable -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow - //~| ERROR E0658 - //~| ERROR mutable references are not allowed +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed //~| WARN taking a mutable diff --git a/tests/ui/error-codes/E0388.stderr b/tests/ui/error-codes/E0388.stderr index 1f7b688899ed0..3e89e3f804b21 100644 --- a/tests/ui/error-codes/E0388.stderr +++ b/tests/ui/error-codes/E0388.stderr @@ -19,7 +19,7 @@ error[E0764]: mutable references are not allowed in the final value of constants LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ -error[E0658]: mutation through a reference is not allowed in statics +error[E0658]: mutable references are not allowed in statics --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; @@ -29,20 +29,8 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` 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[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0388.rs:6:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - -error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0388.rs:6:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ cannot borrow as mutable - warning: taking a mutable reference to a `const` item - --> $DIR/E0388.rs:10:38 + --> $DIR/E0388.rs:8:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -56,12 +44,12 @@ LL | const C: i32 = 2; | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0388.rs:10:38 + --> $DIR/E0388.rs:8:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ -error: aborting due to 5 previous errors; 2 warnings emitted +error: aborting due to 3 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0596, E0658, E0764. -For more information about an error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`.