From cfcb0a2135da6d4bdbf5f28806dea0cc70c5b6c5 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 20 Oct 2022 00:30:00 -0400 Subject: [PATCH 01/10] Use a faster allocation size check in slice::from_raw_parts --- library/core/src/intrinsics.rs | 10 ++++++++++ library/core/src/lib.rs | 1 + library/core/src/slice/raw.rs | 10 +++++----- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 2399262c05b46..3a7a179c98be9 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2229,6 +2229,16 @@ pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { !ptr.is_null() && ptr.is_aligned() } +/// Checks whether an allocation of `len` instances of `T` exceeds +/// the maximum allowed allocation size. +pub(crate) fn is_valid_allocation_size(len: usize) -> bool { + let max_len = const { + let size = crate::mem::size_of::(); + if size == 0 { usize::MAX } else { isize::MAX as usize / size } + }; + len <= max_len +} + /// Checks whether the regions of memory starting at `src` and `dst` of size /// `count * size_of::()` do *not* overlap. pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) -> bool { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2fd8180f8b2a2..aa197c990b20b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -191,6 +191,7 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(if_let_guard)] +#![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 3c5abd215a4b7..dace748fed455 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -1,7 +1,9 @@ //! Free functions to create `&[T]` and `&mut [T]`. use crate::array; -use crate::intrinsics::{assert_unsafe_precondition, is_aligned_and_not_null}; +use crate::intrinsics::{ + assert_unsafe_precondition, is_aligned_and_not_null, is_valid_allocation_size, +}; use crate::ops::Range; use crate::ptr; @@ -91,8 +93,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { assert_unsafe_precondition!([T](data: *const T, len: usize) => - is_aligned_and_not_null(data) - && crate::mem::size_of::().saturating_mul(len) <= isize::MAX as usize + is_aligned_and_not_null(data) && is_valid_allocation_size::(len) ); &*ptr::slice_from_raw_parts(data, len) } @@ -135,8 +136,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { assert_unsafe_precondition!([T](data: *mut T, len: usize) => - is_aligned_and_not_null(data) - && crate::mem::size_of::().saturating_mul(len) <= isize::MAX as usize + is_aligned_and_not_null(data) && is_valid_allocation_size::(len) ); &mut *ptr::slice_from_raw_parts_mut(data, len) } From 74d4eefc1346a8b9242e072df16de4f664b0873c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 23 Oct 2022 09:22:19 +0000 Subject: [PATCH 02/10] Workaround unstable stmt_expr_attributes for method receiver expressions. --- compiler/rustc_ast/src/mut_visit.rs | 14 ++++- compiler/rustc_ast/src/visit.rs | 5 ++ compiler/rustc_builtin_macros/src/cfg_eval.rs | 9 ++- compiler/rustc_expand/src/config.rs | 10 ++- compiler/rustc_expand/src/expand.rs | 63 +++++++++++++++++++ compiler/rustc_expand/src/placeholders.rs | 8 +++ src/test/ui/cfg/cfg-method-receiver-ok.rs | 14 +++++ src/test/ui/cfg/cfg-method-receiver.rs | 3 +- src/test/ui/cfg/cfg-method-receiver.stderr | 14 +---- 9 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/cfg/cfg-method-receiver-ok.rs diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 25022a02f4bb7..b970e57e0173c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -152,6 +152,12 @@ pub trait MutVisitor: Sized { noop_visit_expr(e, self); } + /// This method is a hack to workaround unstable of `stmt_expr_attributes`. + /// It can be removed once that feature is stabilized. + fn visit_method_receiver_expr(&mut self, ex: &mut P) { + self.visit_expr(ex) + } + fn filter_map_expr(&mut self, e: P) -> Option> { noop_filter_map_expr(e, self) } @@ -1301,7 +1307,7 @@ pub fn noop_visit_expr( vis.visit_ident(ident); vis.visit_id(id); visit_opt(args, |args| vis.visit_generic_args(args)); - vis.visit_expr(receiver); + vis.visit_method_receiver_expr(receiver); visit_exprs(exprs, vis); vis.visit_span(span); } @@ -1589,3 +1595,9 @@ impl DummyAstNode for Crate { } } } + +impl DummyAstNode for crate::ast_traits::AstNodeWrapper { + fn dummy() -> Self { + crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy()) + } +} diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e752cc7dc2dcd..6f56c1ef0e8da 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -140,6 +140,11 @@ pub trait Visitor<'ast>: Sized { fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) } + /// This method is a hack to workaround unstable of `stmt_expr_attributes`. + /// It can be removed once that feature is stabilized. + fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) { + self.visit_expr(ex) + } fn visit_expr_post(&mut self, _ex: &'ast Expr) {} fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 009f3c783d4c8..750f1fe121f6d 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -210,8 +210,15 @@ impl CfgEval<'_, '_> { } impl MutVisitor for CfgEval<'_, '_> { + #[instrument(level = "trace", skip(self))] fn visit_expr(&mut self, expr: &mut P) { - self.cfg.configure_expr(expr); + self.cfg.configure_expr(expr, false); + mut_visit::noop_visit_expr(expr, self); + } + + #[instrument(level = "trace", skip(self))] + fn visit_method_receiver_expr(&mut self, expr: &mut P) { + self.cfg.configure_expr(expr, true); mut_visit::noop_visit_expr(expr, self); } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8d4e364074863..1d2b1298a68f6 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -469,6 +469,7 @@ impl<'a> StripUnconfigured<'a> { } /// If attributes are not allowed on expressions, emit an error for `attr` + #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { if !self.features.map_or(true, |features| features.stmt_expr_attributes) { let mut err = feature_err( @@ -486,9 +487,12 @@ impl<'a> StripUnconfigured<'a> { } } - pub fn configure_expr(&self, expr: &mut P) { - for attr in expr.attrs.iter() { - self.maybe_emit_expr_attr_err(attr); + #[instrument(level = "trace", skip(self))] + pub fn configure_expr(&self, expr: &mut P, method_receiver: bool) { + if !method_receiver { + for attr in expr.attrs.iter() { + self.maybe_emit_expr_attr_err(attr); + } } // If an expr is valid to cfg away it will have been removed by the diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 15e9a8db3c602..57713fb3cd61d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -50,6 +50,7 @@ macro_rules! ast_fragments { /// Can also serve as an input and intermediate result for macro expansion operations. pub enum AstFragment { OptExpr(Option>), + MethodReceiverExpr(P), $($Kind($AstTy),)* } @@ -57,6 +58,7 @@ macro_rules! ast_fragments { #[derive(Copy, Clone, PartialEq, Eq)] pub enum AstFragmentKind { OptExpr, + MethodReceiverExpr, $($Kind,)* } @@ -64,6 +66,7 @@ macro_rules! ast_fragments { pub fn name(self) -> &'static str { match self { AstFragmentKind::OptExpr => "expression", + AstFragmentKind::MethodReceiverExpr => "expression", $(AstFragmentKind::$Kind => $kind_name,)* } } @@ -72,6 +75,8 @@ macro_rules! ast_fragments { match self { AstFragmentKind::OptExpr => result.make_expr().map(Some).map(AstFragment::OptExpr), + AstFragmentKind::MethodReceiverExpr => + result.make_expr().map(AstFragment::MethodReceiverExpr), $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)* } } @@ -98,6 +103,13 @@ macro_rules! ast_fragments { } } + pub fn make_method_receiver_expr(self) -> P { + match self { + AstFragment::MethodReceiverExpr(expr) => expr, + _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), + } + } + $(pub fn $make_ast(self) -> $AstTy { match self { AstFragment::$Kind(ast) => ast, @@ -120,6 +132,7 @@ macro_rules! ast_fragments { } }); } + AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr), $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)* $($(AstFragment::$Kind(ast) => ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)* @@ -130,6 +143,7 @@ macro_rules! ast_fragments { match *self { AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), AstFragment::OptExpr(None) => {} + AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr), $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { visitor.$visit_ast_elt(ast_elt, $($args)*); @@ -222,6 +236,7 @@ impl AstFragmentKind { match self { AstFragmentKind::OptExpr | AstFragmentKind::Expr + | AstFragmentKind::MethodReceiverExpr | AstFragmentKind::Stmts | AstFragmentKind::Ty | AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false }, @@ -285,6 +300,9 @@ impl AstFragmentKind { AstFragmentKind::Expr => AstFragment::Expr( items.next().expect("expected exactly one expression").expect_expr(), ), + AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr( + items.next().expect("expected exactly one expression").expect_expr(), + ), AstFragmentKind::OptExpr => { AstFragment::OptExpr(items.next().map(Annotatable::expect_expr)) } @@ -893,6 +911,7 @@ pub fn parse_ast_fragment<'a>( AstFragment::Stmts(stmts) } AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?), + AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(this.parse_expr()?), AstFragmentKind::OptExpr => { if this.token != token::Eof { AstFragment::OptExpr(Some(this.parse_expr()?)) @@ -1477,6 +1496,42 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { } } +/// This struct is a hack to workaround unstable of `stmt_expr_attributes`. +/// It can be removed once that feature is stabilized. +struct MethodReceiverTag; +impl DummyAstNode for MethodReceiverTag { + fn dummy() -> MethodReceiverTag { + MethodReceiverTag + } +} +impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> { + type OutputTy = Self; + type AttrsTy = ast::AttrVec; + const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr; + fn descr() -> &'static str { + "an expression" + } + fn to_annotatable(self) -> Annotatable { + Annotatable::Expr(self.wrapped) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag) + } + fn noop_visit(&mut self, visitor: &mut V) { + noop_visit_expr(&mut self.wrapped, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) + } + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { + let node = self.wrapped.into_inner(); + match node.kind { + ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } +} + struct InvocationCollector<'a, 'b> { cx: &'a mut ExtCtxt<'b>, invocations: Vec<(Invocation, Option>)>, @@ -1840,6 +1895,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.visit_node(node) } + fn visit_method_receiver_expr(&mut self, node: &mut P) { + visit_clobber(node, |node| { + let mut wrapper = AstNodeWrapper::new(node, MethodReceiverTag); + self.visit_node(&mut wrapper); + wrapper.wrapped + }) + } + fn filter_map_expr(&mut self, node: P) -> Option> { self.flat_map_node(AstNodeWrapper::new(node, OptExprTag)) } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 3b0d5ddb97b4e..faaf3b3fea589 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -55,6 +55,7 @@ pub fn placeholder( }), AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), + AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(expr_placeholder()), AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item { id, span, @@ -296,6 +297,13 @@ impl MutVisitor for PlaceholderExpander { } } + fn visit_method_receiver_expr(&mut self, expr: &mut P) { + match expr.kind { + ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(), + _ => noop_visit_expr(expr, self), + } + } + fn filter_map_expr(&mut self, expr: P) -> Option> { match expr.kind { ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(), diff --git a/src/test/ui/cfg/cfg-method-receiver-ok.rs b/src/test/ui/cfg/cfg-method-receiver-ok.rs new file mode 100644 index 0000000000000..61ad3b8c17ab2 --- /dev/null +++ b/src/test/ui/cfg/cfg-method-receiver-ok.rs @@ -0,0 +1,14 @@ +// check-pass + +macro_rules! foo { + () => { + #[allow(unreachable_patterns)] + { + 123i32 + } + }; +} + +fn main() { + let _ = foo!().abs(); +} diff --git a/src/test/ui/cfg/cfg-method-receiver.rs b/src/test/ui/cfg/cfg-method-receiver.rs index 78a072f503fab..71134ff17b527 100644 --- a/src/test/ui/cfg/cfg-method-receiver.rs +++ b/src/test/ui/cfg/cfg-method-receiver.rs @@ -7,6 +7,5 @@ macro_rules! cbor_map { fn main() { cbor_map! { #[cfg(test)] 4}; - //~^ ERROR attributes on expressions are experimental - //~| ERROR removing an expression is not supported in this position + //~^ ERROR removing an expression is not supported in this position } diff --git a/src/test/ui/cfg/cfg-method-receiver.stderr b/src/test/ui/cfg/cfg-method-receiver.stderr index 517fc8168e72d..5767a7c1b4b1c 100644 --- a/src/test/ui/cfg/cfg-method-receiver.stderr +++ b/src/test/ui/cfg/cfg-method-receiver.stderr @@ -1,12 +1,3 @@ -error[E0658]: attributes on expressions are experimental - --> $DIR/cfg-method-receiver.rs:9:17 - | -LL | cbor_map! { #[cfg(test)] 4}; - | ^^^^^^^^^^^^ - | - = note: see issue #15701 for more information - = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable - error: removing an expression is not supported in this position --> $DIR/cfg-method-receiver.rs:9:17 | @@ -28,7 +19,6 @@ help: you must specify a concrete type for this numeric value, like `i32` LL | cbor_map! { #[cfg(test)] 4_i32}; | ~~~~~ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0658, E0689. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0689`. From 8bc43f99e91a94868fe08bb72b7ce66d7656d0b5 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Mon, 17 Oct 2022 19:41:49 +0200 Subject: [PATCH 03/10] Allow specifying multiple alternative suggestions This allows porting uses of span_suggestions() to diagnostic structs. Doesn't work for multipart_suggestions() because the rank would be reversed - the struct would specify multiple spans, each of which has multiple possible replacements, while multipart_suggestions() creates multiple possible replacements, each with multiple spans. --- compiler/rustc_errors/src/diagnostic.rs | 26 ++++- .../src/diagnostics/diagnostic_builder.rs | 2 +- .../src/diagnostics/subdiagnostic.rs | 21 ++-- .../rustc_macros/src/diagnostics/utils.rs | 105 ++++++++++++++++-- .../session-diagnostic/diagnostic-derive.rs | 38 +++++++ .../diagnostic-derive.stderr | 20 +++- .../subdiagnostic-derive.rs | 45 ++++++++ .../subdiagnostic-derive.stderr | 32 +++++- 8 files changed, 263 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a63fc0ca285da..23f29a24fe79f 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -690,6 +690,24 @@ impl Diagnostic { msg: impl Into, suggestions: impl Iterator, applicability: Applicability, + ) -> &mut Self { + self.span_suggestions_with_style( + sp, + msg, + suggestions, + applicability, + SuggestionStyle::ShowCode, + ) + } + + /// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`]. + pub fn span_suggestions_with_style( + &mut self, + sp: Span, + msg: impl Into, + suggestions: impl Iterator, + applicability: Applicability, + style: SuggestionStyle, ) -> &mut Self { let mut suggestions: Vec<_> = suggestions.collect(); suggestions.sort(); @@ -706,14 +724,15 @@ impl Diagnostic { self.push_suggestion(CodeSuggestion { substitutions, msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style: SuggestionStyle::ShowCode, + style, applicability, }); self } - /// Prints out a message with multiple suggested edits of the code. - /// See also [`Diagnostic::span_suggestion()`]. + /// Prints out a message with multiple suggested edits of the code, where each edit consists of + /// multiple parts. + /// See also [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestions( &mut self, msg: impl Into, @@ -745,6 +764,7 @@ impl Diagnostic { }); self } + /// Prints out a message with a suggested edit of the code. If the suggestion is presented /// inline, it will only show the message and not the suggestion. /// diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 9f7d2661a3e8b..3ea83fd09c794 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -454,7 +454,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { self.formatting_init.extend(code_init); Ok(quote! { - #diag.span_suggestion_with_style( + #diag.span_suggestions_with_style( #span_field, rustc_errors::fluent::#slug, #code_field, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index d1acb71384220..fa0ca5a52423a 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -11,9 +11,11 @@ use crate::diagnostics::utils::{ }; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path}; +use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; +use super::utils::{build_suggestion_code, AllowMultipleAlternatives}; + /// The central struct for constructing the `add_to_diagnostic` method from an annotated struct. pub(crate) struct SubdiagnosticDeriveBuilder { diag: syn::Ident, @@ -414,15 +416,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let nested_name = meta.path().segments.last().unwrap().ident.to_string(); let nested_name = nested_name.as_str(); - let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else { - throw_invalid_nested_attr!(attr, &nested_attr); - }; - match nested_name { "code" => { - let formatted_str = self.build_format(&value.value(), value.span()); let code_field = new_code_ident(); - code.set_once((code_field, formatted_str), span); + let formatting_init = build_suggestion_code( + &code_field, + meta, + self, + AllowMultipleAlternatives::No, + ); + code.set_once((code_field, formatting_init), span); } _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { diag.help("`code` is the only valid nested attribute") @@ -430,14 +433,14 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } } - let Some((code_field, formatted_str)) = code.value() else { + let Some((code_field, formatting_init)) = code.value() else { span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") .emit(); return Ok(quote! {}); }; let binding = info.binding; - self.formatting_init.extend(quote! { let #code_field = #formatted_str; }); + self.formatting_init.extend(formatting_init); let code_field = if clone_suggestion_code { quote! { #code_field.clone() } } else { diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 61d5007fc30f0..374c795d0a638 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -2,7 +2,7 @@ use crate::diagnostics::error::{ span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError, }; use proc_macro::Span; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, ToTokens}; use std::cell::RefCell; use std::collections::{BTreeSet, HashMap}; @@ -395,6 +395,82 @@ pub(super) fn build_field_mapping<'v>(variant: &VariantInfo<'v>) -> HashMap TokenStream { + let values = match meta { + // `code = "foo"` + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s], + // `code("foo", "bar")` + Meta::List(MetaList { nested, .. }) => { + if let AllowMultipleAlternatives::No = allow_multiple { + span_err( + meta.span().unwrap(), + "expected exactly one string literal for `code = ...`", + ) + .emit(); + vec![] + } else if nested.is_empty() { + span_err( + meta.span().unwrap(), + "expected at least one string literal for `code(...)`", + ) + .emit(); + vec![] + } else { + nested + .into_iter() + .filter_map(|item| { + if let NestedMeta::Lit(syn::Lit::Str(s)) = item { + Some(s) + } else { + span_err( + item.span().unwrap(), + "`code(...)` must contain only string literals", + ) + .emit(); + None + } + }) + .collect() + } + } + _ => { + span_err( + meta.span().unwrap(), + r#"`code = "..."`/`code(...)` must contain only string literals"#, + ) + .emit(); + vec![] + } + }; + + if let AllowMultipleAlternatives::Yes = allow_multiple { + let formatted_strings: Vec<_> = values + .into_iter() + .map(|value| fields.build_format(&value.value(), value.span())) + .collect(); + quote! { let #code_field = [#(#formatted_strings),*].into_iter(); } + } else if let [value] = values.as_slice() { + let formatted_str = fields.build_format(&value.value(), value.span()); + quote! { let #code_field = #formatted_str; } + } else { + // error handled previously + quote! { let #code_field = String::new(); } + } +} + /// Possible styles for suggestion subdiagnostics. #[derive(Clone, Copy)] pub(super) enum SuggestionKind { @@ -571,21 +647,23 @@ impl SubdiagnosticKind { let nested_name = meta.path().segments.last().unwrap().ident.to_string(); let nested_name = nested_name.as_str(); - let value = match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value, + let string_value = match meta { + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value), + Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { diag.help("a diagnostic slug must be the first argument to the attribute") }), - _ => { - invalid_nested_attr(attr, &nested_attr).emit(); - continue; - } + _ => None, }; match (nested_name, &mut kind) { ("code", SubdiagnosticKind::Suggestion { code_field, .. }) => { - let formatted_str = fields.build_format(&value.value(), value.span()); - let code_init = quote! { let #code_field = #formatted_str; }; + let code_init = build_suggestion_code( + code_field, + meta, + fields, + AllowMultipleAlternatives::Yes, + ); code.set_once(code_init, span); } ( @@ -593,6 +671,11 @@ impl SubdiagnosticKind { SubdiagnosticKind::Suggestion { ref mut applicability, .. } | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. }, ) => { + let Some(value) = string_value else { + invalid_nested_attr(attr, &nested_attr).emit(); + continue; + }; + let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| { span_err(span, "invalid applicability").emit(); Applicability::Unspecified @@ -623,7 +706,7 @@ impl SubdiagnosticKind { init } else { span_err(span, "suggestion without `code = \"...\"`").emit(); - quote! { let #code_field: String = unreachable!(); } + quote! { let #code_field = std::iter::empty(); } }; } SubdiagnosticKind::Label @@ -644,7 +727,7 @@ impl quote::IdentFragment for SubdiagnosticKind { SubdiagnosticKind::Note => write!(f, "note"), SubdiagnosticKind::Help => write!(f, "help"), SubdiagnosticKind::Warn => write!(f, "warn"), - SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"), + SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"), SubdiagnosticKind::MultipartSuggestion { .. } => { write!(f, "multipart_suggestion_with_style") } diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 46164d573b0bd..ca77e483d6ff8 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -758,3 +758,41 @@ struct WithDocComment { #[primary_span] span: Span, } + +#[derive(Diagnostic)] +#[diag(compiletest_example)] +struct SuggestionsGood { + #[suggestion(code("foo", "bar"))] + sub: Span, +} + +#[derive(Diagnostic)] +#[diag(compiletest_example)] +struct SuggestionsSingleItem { + #[suggestion(code("foo"))] + sub: Span, +} + +#[derive(Diagnostic)] +#[diag(compiletest_example)] +struct SuggestionsNoItem { + #[suggestion(code())] + //~^ ERROR expected at least one string literal for `code(...)` + sub: Span, +} + +#[derive(Diagnostic)] +#[diag(compiletest_example)] +struct SuggestionsInvalidItem { + #[suggestion(code(foo))] + //~^ ERROR `code(...)` must contain only string literals + sub: Span, +} + +#[derive(Diagnostic)] +#[diag(compiletest_example)] +struct SuggestionsInvalidLiteral { + #[suggestion(code = 3)] + //~^ ERROR `code = "..."`/`code(...)` must contain only string literals + sub: Span, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 0a1c4bddb06a0..859c272b6ba9c 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -573,6 +573,24 @@ LL | #[subdiagnostic(eager)] | = help: eager subdiagnostics are not supported on lints +error: expected at least one string literal for `code(...)` + --> $DIR/diagnostic-derive.rs:779:18 + | +LL | #[suggestion(code())] + | ^^^^^^ + +error: `code(...)` must contain only string literals + --> $DIR/diagnostic-derive.rs:787:23 + | +LL | #[suggestion(code(foo))] + | ^^^ + +error: `code = "..."`/`code(...)` must contain only string literals + --> $DIR/diagnostic-derive.rs:795:18 + | +LL | #[suggestion(code = 3)] + | ^^^^^^^^ + error: cannot find attribute `nonsense` in this scope --> $DIR/diagnostic-derive.rs:55:3 | @@ -647,7 +665,7 @@ LL | arg: impl IntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg` = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 80 previous errors +error: aborting due to 83 previous errors Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index 9088ca6ce462b..efec85eb52c2e 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -661,3 +661,48 @@ enum BL { span: Span, } } + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parser_add_paren)] +struct BM { + #[suggestion_part(code("foo"))] + //~^ ERROR expected exactly one string literal for `code = ...` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parser_add_paren)] +struct BN { + #[suggestion_part(code("foo", "bar"))] + //~^ ERROR expected exactly one string literal for `code = ...` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parser_add_paren)] +struct BO { + #[suggestion_part(code(3))] + //~^ ERROR expected exactly one string literal for `code = ...` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parser_add_paren)] +struct BP { + #[suggestion_part(code())] + //~^ ERROR expected exactly one string literal for `code = ...` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parser_add_paren)] +struct BQ { + #[suggestion_part(code = 3)] + //~^ ERROR `code = "..."`/`code(...)` must contain only string literals + span: Span, + r#type: String, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index b21f9cc94a98c..a85a8711eaca4 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -415,6 +415,36 @@ error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_sugg LL | #[applicability] | ^^^^^^^^^^^^^^^^ +error: expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive.rs:668:23 + | +LL | #[suggestion_part(code("foo"))] + | ^^^^^^^^^^^ + +error: expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive.rs:677:23 + | +LL | #[suggestion_part(code("foo", "bar"))] + | ^^^^^^^^^^^^^^^^^^ + +error: expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive.rs:686:23 + | +LL | #[suggestion_part(code(3))] + | ^^^^^^^ + +error: expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive.rs:695:23 + | +LL | #[suggestion_part(code())] + | ^^^^^^ + +error: `code = "..."`/`code(...)` must contain only string literals + --> $DIR/subdiagnostic-derive.rs:704:23 + | +LL | #[suggestion_part(code = 3)] + | ^^^^^^^^ + error: cannot find attribute `foo` in this scope --> $DIR/subdiagnostic-derive.rs:63:3 | @@ -475,6 +505,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent` LL | #[label(slug)] | ^^^^ not found in `rustc_errors::fluent` -error: aborting due to 67 previous errors +error: aborting due to 72 previous errors For more information about this error, try `rustc --explain E0425`. From f54c336c8019432803dd9a67b575053ffc03c372 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 22 Oct 2022 07:56:26 +0800 Subject: [PATCH 04/10] fix #103425, remove extra type error after missing semicolon error --- compiler/rustc_parse/src/parser/stmt.rs | 65 ++++++++++++++----------- src/test/ui/parser/issue-103425.rs | 15 ++++++ src/test/ui/parser/issue-103425.stderr | 29 +++++++++++ 3 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 src/test/ui/parser/issue-103425.rs create mode 100644 src/test/ui/parser/issue-103425.stderr diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index a61e77b7c3bfb..12753c6785c9a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -553,39 +553,46 @@ impl<'a> Parser<'a> { match stmt.kind { // Expression without semicolon. StmtKind::Expr(ref mut expr) - if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => - { + if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet. - if let Err(mut e) = - self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) - { - if let TokenKind::DocComment(..) = self.token.kind { - if let Ok(snippet) = self.span_to_snippet(self.token.span) { - let sp = self.token.span; - let marker = &snippet[..3]; - let (comment_marker, doc_comment_marker) = marker.split_at(2); - - e.span_suggestion( - sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), - &format!( - "add a space before `{}` to use a regular comment", - doc_comment_marker, - ), - format!("{} {}", comment_marker, doc_comment_marker), - Applicability::MaybeIncorrect, - ); + // `expect_one_of` returns PResult<'a, bool /* recovered */> + let replace_with_err = + match self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) { + // Recover from parser, skip type error to avoid extra errors. + Ok(true) => true, + Err(mut e) => { + if let TokenKind::DocComment(..) = self.token.kind && + let Ok(snippet) = self.span_to_snippet(self.token.span) { + let sp = self.token.span; + let marker = &snippet[..3]; + let (comment_marker, doc_comment_marker) = marker.split_at(2); + + e.span_suggestion( + sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), + &format!( + "add a space before `{}` to use a regular comment", + doc_comment_marker, + ), + format!("{} {}", comment_marker, doc_comment_marker), + Applicability::MaybeIncorrect, + ); } - } - if let Err(mut e) = - self.check_mistyped_turbofish_with_multiple_type_params(e, expr) - { - if recover.no() { - return Err(e); + + if let Err(mut e) = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr) + { + if recover.no() { + return Err(e); + } + e.emit(); + self.recover_stmt(); } - e.emit(); - self.recover_stmt(); + true } - // Don't complain about type errors in body tail after parse error (#57383). + _ => false + }; + if replace_with_err { + // We already emitted an error, so don't emit another type error let sp = expr.span.to(self.prev_token.span); *expr = self.mk_expr_err(sp); } diff --git a/src/test/ui/parser/issue-103425.rs b/src/test/ui/parser/issue-103425.rs new file mode 100644 index 0000000000000..c2f8123ca4e67 --- /dev/null +++ b/src/test/ui/parser/issue-103425.rs @@ -0,0 +1,15 @@ +fn f() -> f32 { + 3 + //~^ ERROR expected `;` + 5.0 +} + +fn k() -> f32 { + 2_u32 + //~^ ERROR expected `;` + 3_i8 + //~^ ERROR expected `;` + 5.0 +} + +fn main() {} diff --git a/src/test/ui/parser/issue-103425.stderr b/src/test/ui/parser/issue-103425.stderr new file mode 100644 index 0000000000000..0efe3e3ca7117 --- /dev/null +++ b/src/test/ui/parser/issue-103425.stderr @@ -0,0 +1,29 @@ +error: expected `;`, found `5.0` + --> $DIR/issue-103425.rs:2:6 + | +LL | 3 + | ^ help: add `;` here +LL | +LL | 5.0 + | --- unexpected token + +error: expected `;`, found `3_i8` + --> $DIR/issue-103425.rs:8:10 + | +LL | 2_u32 + | ^ help: add `;` here +LL | +LL | 3_i8 + | ---- unexpected token + +error: expected `;`, found `5.0` + --> $DIR/issue-103425.rs:10:9 + | +LL | 3_i8 + | ^ help: add `;` here +LL | +LL | 5.0 + | --- unexpected token + +error: aborting due to 3 previous errors + From 0fca075ce8a2247b6d59cd8eaf2fd1d6b89855d8 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Wed, 12 Oct 2022 17:07:30 +0800 Subject: [PATCH 05/10] suggest type annotation for local statement initialed by ref expression --- compiler/rustc_hir_typeck/src/demand.rs | 19 ++++++- .../src/fn_ctxt/suggestions.rs | 47 ++++++++++++++- src/test/ui/suggestions/format-borrow.stderr | 16 ++++++ src/test/ui/suggestions/issue-102892.rs | 25 ++++++++ src/test/ui/suggestions/issue-102892.stderr | 57 +++++++++++++++++++ 5 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/suggestions/issue-102892.rs create mode 100644 src/test/ui/suggestions/issue-102892.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 2974ac97f2368..be14234afe28d 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -714,7 +714,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, - ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> { + ) -> Option<( + Span, + String, + String, + Applicability, + bool, /* verbose */ + bool, /* suggest `&` or `&mut` type annotation */ + )> { let sess = self.sess(); let sp = expr.span; @@ -746,6 +753,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::new(), Applicability::MachineApplicable, true, + false, )); } } @@ -760,6 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "b".to_string(), Applicability::MachineApplicable, true, + false, )); } } @@ -817,6 +826,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg.2, Applicability::MachineApplicable, false, + false, )); } @@ -844,6 +854,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{prefix}&mut {sugg_expr}"), Applicability::MachineApplicable, false, + false, ), hir::Mutability::Not => ( sp, @@ -851,6 +862,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{prefix}&{sugg_expr}"), Applicability::MachineApplicable, false, + false, ), }); } @@ -880,6 +892,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::new(), Applicability::MachineApplicable, true, + true )); } return None; @@ -893,6 +906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::new(), Applicability::MachineApplicable, true, + true, )); } } @@ -959,6 +973,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { src, applicability, true, + false, )); } } @@ -999,6 +1014,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable }, true, + false, )); } @@ -1050,6 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggestion, Applicability::MachineApplicable, true, + false, )); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index cd2e41aff0f12..4db9c56f98fee 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -327,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let expr = expr.peel_blocks(); - if let Some((sp, msg, suggestion, applicability, verbose)) = + if let Some((sp, msg, suggestion, applicability, verbose, annotation)) = self.check_ref(expr, found, expected) { if verbose { @@ -335,9 +335,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_suggestion(sp, &msg, suggestion, applicability); } + if annotation { + let suggest_annotation = match expr.peel_drop_temps().kind { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&", + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ", + _ => return true, + }; + let mut tuple_indexes = Vec::new(); + let mut expr_id = expr.hir_id; + for (parent_id, node) in self.tcx.hir().parent_iter(expr.hir_id) { + match node { + Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => { + tuple_indexes.push( + subs.iter() + .enumerate() + .find(|(_, sub_expr)| sub_expr.hir_id == expr_id) + .unwrap() + .0, + ); + expr_id = parent_id; + } + Node::Local(local) => { + if let Some(mut ty) = local.ty { + while let Some(index) = tuple_indexes.pop() { + match ty.kind { + TyKind::Tup(tys) => ty = &tys[index], + _ => return true, + } + } + let annotation_span = ty.span; + err.span_suggestion( + annotation_span.with_hi(annotation_span.lo()), + format!("alternatively, consider changing the type annotation"), + suggest_annotation, + Applicability::MaybeIncorrect, + ); + } + break; + } + _ => break, + } + } + } return true; - } else if self.suggest_else_fn_with_closure(err, expr, found, expected) - { + } else if self.suggest_else_fn_with_closure(err, expr, found, expected) { return true; } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected)) && let ty::FnDef(def_id, ..) = &found.kind() diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr index fac6a5a5f48cb..8ed2b9c9a6330 100644 --- a/src/test/ui/suggestions/format-borrow.stderr +++ b/src/test/ui/suggestions/format-borrow.stderr @@ -11,6 +11,10 @@ help: consider removing the borrow LL - let a: String = &String::from("a"); LL + let a: String = String::from("a"); | +help: alternatively, consider changing the type annotation + | +LL | let a: &String = &String::from("a"); + | + error[E0308]: mismatched types --> $DIR/format-borrow.rs:4:21 @@ -25,6 +29,10 @@ help: consider removing the borrow LL - let b: String = &format!("b"); LL + let b: String = format!("b"); | +help: alternatively, consider changing the type annotation + | +LL | let b: &String = &format!("b"); + | + error[E0308]: mismatched types --> $DIR/format-borrow.rs:6:21 @@ -39,6 +47,10 @@ help: consider removing the borrow LL - let c: String = &mut format!("c"); LL + let c: String = format!("c"); | +help: alternatively, consider changing the type annotation + | +LL | let c: &mut String = &mut format!("c"); + | ++++ error[E0308]: mismatched types --> $DIR/format-borrow.rs:8:21 @@ -53,6 +65,10 @@ help: consider removing the borrow LL - let d: String = &mut (format!("d")); LL + let d: String = format!("d")); | +help: alternatively, consider changing the type annotation + | +LL | let d: &mut String = &mut (format!("d")); + | ++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/issue-102892.rs b/src/test/ui/suggestions/issue-102892.rs new file mode 100644 index 0000000000000..c1a791d8d857a --- /dev/null +++ b/src/test/ui/suggestions/issue-102892.rs @@ -0,0 +1,25 @@ +#![allow(dead_code, unused_variables)] + +use std::sync::Arc; + +#[derive(Debug)] +struct A; +#[derive(Debug)] +struct B; + +fn process_without_annot(arc: &Arc<(A, B)>) { + let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed! +} + +fn process_with_annot(arc: &Arc<(A, B)>) { + let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too + //~^ ERROR mismatched types +} + +fn process_with_tuple_annot(mutation: &mut (A, B), arc: &Arc<(A, B)>) { + let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too + //~^ ERROR mismatched types + //~| ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-102892.stderr b/src/test/ui/suggestions/issue-102892.stderr new file mode 100644 index 0000000000000..a3dbc7cb861ff --- /dev/null +++ b/src/test/ui/suggestions/issue-102892.stderr @@ -0,0 +1,57 @@ +error[E0308]: mismatched types + --> $DIR/issue-102892.rs:15:26 + | +LL | let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too + | ------ ^^^^^^ expected tuple, found `&(A, B)` + | | + | expected due to this + | + = note: expected tuple `(A, B)` + found reference `&(A, B)` +help: consider removing the borrow + | +LL - let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too +LL + let (a, b): (A, B) = **arc; // suggests putting `&**arc` here too + | +help: alternatively, consider changing the type annotation + | +LL | let (a, b): &(A, B) = &**arc; // suggests putting `&**arc` here too + | + + +error[E0308]: mismatched types + --> $DIR/issue-102892.rs:20:32 + | +LL | let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too + | ^^^^^^^^^^^^^^ expected tuple, found `&mut (A, B)` + | + = note: expected tuple `(A, B)` + found mutable reference `&mut (A, B)` +help: consider removing the borrow + | +LL - let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too +LL + let (a, b): ((A, B), A) = (*mutation, &(**arc).0); // suggests putting `&**arc` here too + | +help: alternatively, consider changing the type annotation + | +LL | let (a, b): (&mut (A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too + | ++++ + +error[E0308]: mismatched types + --> $DIR/issue-102892.rs:20:48 + | +LL | let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too + | ^^^^^^^^^^ expected struct `A`, found `&A` + | +help: consider removing the borrow + | +LL - let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too +LL + let (a, b): ((A, B), A) = (&mut *mutation, (**arc).0); // suggests putting `&**arc` here too + | +help: alternatively, consider changing the type annotation + | +LL | let (a, b): ((A, B), &A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too + | + + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From 919673ea03e2c376931161a9301a9d6f089f8984 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 25 Oct 2022 14:45:02 +0400 Subject: [PATCH 06/10] rustc_middle: Rearrange resolver outputs structures slightly --- compiler/rustc_interface/src/passes.rs | 14 ++------- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 41 +++++++++++++------------ compiler/rustc_middle/src/ty/mod.rs | 11 ++++++- compiler/rustc_resolve/src/lib.rs | 27 ++++++++-------- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a47c3e3253ecd..9d2325e8265e7 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -16,7 +16,6 @@ use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; use rustc_hir::def_id::StableCrateId; -use rustc_hir::definitions::Definitions; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; @@ -30,7 +29,7 @@ use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType}; -use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn}; +use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; @@ -135,10 +134,7 @@ mod boxed_resolver { f((&mut *resolver).as_mut().unwrap()) } - pub fn to_resolver_outputs( - resolver: Rc>, - ) -> (Definitions, Box, ty::ResolverOutputs, ty::ResolverAstLowering) - { + pub fn to_resolver_outputs(resolver: Rc>) -> ty::ResolverOutputs { match Rc::try_unwrap(resolver) { Ok(resolver) => { let mut resolver = resolver.into_inner(); @@ -788,8 +784,7 @@ pub fn create_global_ctxt<'tcx>( // incr. comp. yet. dep_graph.assert_ignored(); - let (definitions, cstore, resolver_outputs, resolver_for_lowering) = - BoxedResolver::to_resolver_outputs(resolver); + let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver); let sess = &compiler.session(); let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); @@ -816,10 +811,7 @@ pub fn create_global_ctxt<'tcx>( lint_store, arena, hir_arena, - definitions, - cstore, resolver_outputs, - resolver_for_lowering, krate, dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2ab3b0d27c88a..67c85ef0d3b50 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -23,7 +23,7 @@ rustc_queries! { desc { "triggering a delay span bug" } } - query resolutions(_: ()) -> &'tcx ty::ResolverOutputs { + query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { eval_always no_hash desc { "getting the resolver outputs" } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0816a5cb8f16e..94e3f3b63c813 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -79,7 +79,7 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -use super::{ImplPolarity, RvalueScopes}; +use super::{ImplPolarity, ResolverOutputs, RvalueScopes}; pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. @@ -1067,10 +1067,9 @@ pub struct GlobalCtxt<'tcx> { pub consts: CommonConsts<'tcx>, definitions: RwLock, - cstore: Box, /// Output of the resolver. - pub(crate) untracked_resolutions: ty::ResolverOutputs, + pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt, untracked_resolver_for_lowering: Steal, /// The entire crate as AST. This field serves as the input for the hir_crate query, /// which lowers it from AST to HIR. It must not be read or used by anything else. @@ -1233,10 +1232,7 @@ impl<'tcx> TyCtxt<'tcx> { lint_store: Lrc, arena: &'tcx WorkerLocal>, hir_arena: &'tcx WorkerLocal>, - definitions: Definitions, - cstore: Box, - untracked_resolutions: ty::ResolverOutputs, - untracked_resolver_for_lowering: ty::ResolverAstLowering, + resolver_outputs: ResolverOutputs, krate: Lrc, dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, @@ -1245,6 +1241,11 @@ impl<'tcx> TyCtxt<'tcx> { crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { + let ResolverOutputs { + definitions, + global_ctxt: untracked_resolutions, + ast_lowering: untracked_resolver_for_lowering, + } = resolver_outputs; let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { s.emit_fatal(err); }); @@ -1253,7 +1254,7 @@ impl<'tcx> TyCtxt<'tcx> { &interners, s, &definitions, - &*cstore, + &*untracked_resolutions.cstore, // This is only used to create a stable hashing context. &untracked_resolutions.source_span, ); @@ -1268,7 +1269,6 @@ impl<'tcx> TyCtxt<'tcx> { interners, dep_graph, definitions: RwLock::new(definitions), - cstore, prof: s.prof.clone(), types: common_types, lifetimes: common_lifetimes, @@ -1369,7 +1369,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = id.as_local() { self.definitions_untracked().def_key(id) } else { - self.cstore.def_key(id) + self.untracked_resolutions.cstore.def_key(id) } } @@ -1383,7 +1383,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = id.as_local() { self.definitions_untracked().def_path(id) } else { - self.cstore.def_path(id) + self.untracked_resolutions.cstore.def_path(id) } } @@ -1393,7 +1393,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(def_id) = def_id.as_local() { self.definitions_untracked().def_path_hash(def_id) } else { - self.cstore.def_path_hash(def_id) + self.untracked_resolutions.cstore.def_path_hash(def_id) } } @@ -1402,7 +1402,7 @@ impl<'tcx> TyCtxt<'tcx> { if crate_num == LOCAL_CRATE { self.sess.local_stable_crate_id() } else { - self.cstore.stable_crate_id(crate_num) + self.untracked_resolutions.cstore.stable_crate_id(crate_num) } } @@ -1413,7 +1413,7 @@ impl<'tcx> TyCtxt<'tcx> { if stable_crate_id == self.sess.local_stable_crate_id() { LOCAL_CRATE } else { - self.cstore.stable_crate_id_to_crate_num(stable_crate_id) + self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id) } } @@ -1432,8 +1432,9 @@ impl<'tcx> TyCtxt<'tcx> { } else { // If this is a DefPathHash from an upstream crate, let the CrateStore map // it to a DefId. - let cnum = self.cstore.stable_crate_id_to_crate_num(stable_crate_id); - self.cstore.def_path_hash_to_def_id(cnum, hash) + let cstore = &*self.untracked_resolutions.cstore; + let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + cstore.def_path_hash_to_def_id(cnum, hash) } } @@ -1445,7 +1446,7 @@ impl<'tcx> TyCtxt<'tcx> { let (crate_name, stable_crate_id) = if def_id.is_local() { (self.crate_name, self.sess.local_stable_crate_id()) } else { - let cstore = &self.cstore; + let cstore = &*self.untracked_resolutions.cstore; (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate)) }; @@ -1520,7 +1521,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn { - &*self.cstore + &*self.untracked_resolutions.cstore } /// Note that this is *untracked* and should only be used within the query @@ -1546,7 +1547,7 @@ impl<'tcx> TyCtxt<'tcx> { let hcx = StableHashingContext::new( self.sess, &*definitions, - &*self.cstore, + &*self.untracked_resolutions.cstore, &self.untracked_resolutions.source_span, ); f(hcx) @@ -2364,7 +2365,7 @@ impl<'tcx> TyCtxt<'tcx> { st, self.sess, &self.definitions.read(), - &*self.cstore, + &*self.untracked_resolutions.cstore, // This is only used to create a stable hashing context. &self.untracked_resolutions.source_span, ) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c2aef8178e2c7..9671d3a32f945 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -38,11 +38,13 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::definitions::Definitions; use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; +use rustc_session::cstore::CrateStoreDyn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; @@ -142,8 +144,15 @@ mod sty; pub type RegisteredTools = FxHashSet; -#[derive(Debug)] pub struct ResolverOutputs { + pub definitions: Definitions, + pub global_ctxt: ResolverGlobalCtxt, + pub ast_lowering: ResolverAstLowering, +} + +#[derive(Debug)] +pub struct ResolverGlobalCtxt { + pub cstore: Box, pub visibilities: FxHashMap, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1c1976af5054c..c2213e8d1e2e3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -42,9 +42,10 @@ use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::span_bug; -use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs}; +use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools}; +use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; use rustc_query_system::ich::StableHashingContext; -use rustc_session::cstore::{CrateStore, CrateStoreDyn, MetadataLoaderDyn}; +use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_session::lint::LintBuffer; use rustc_session::Session; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; @@ -1376,9 +1377,7 @@ impl<'a> Resolver<'a> { Default::default() } - pub fn into_outputs( - self, - ) -> (Definitions, Box, ResolverOutputs, ty::ResolverAstLowering) { + pub fn into_outputs(self) -> ResolverOutputs { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); let definitions = self.definitions; let cstore = Box::new(self.crate_loader.into_cstore()); @@ -1394,7 +1393,8 @@ impl<'a> Resolver<'a> { let main_def = self.main_def; let confused_type_with_std_module = self.confused_type_with_std_module; let access_levels = self.access_levels; - let resolutions = ResolverOutputs { + let global_ctxt = ResolverGlobalCtxt { + cstore, source_span, expn_that_defined, visibilities, @@ -1416,7 +1416,7 @@ impl<'a> Resolver<'a> { confused_type_with_std_module, registered_tools: self.registered_tools, }; - let resolutions_lowering = ty::ResolverAstLowering { + let ast_lowering = ty::ResolverAstLowering { legacy_const_generic_args: self.legacy_const_generic_args, partial_res_map: self.partial_res_map, import_res_map: self.import_res_map, @@ -1429,16 +1429,15 @@ impl<'a> Resolver<'a> { trait_map: self.trait_map, builtin_macro_kinds: self.builtin_macro_kinds, }; - (definitions, cstore, resolutions, resolutions_lowering) + ResolverOutputs { definitions, global_ctxt, ast_lowering } } - pub fn clone_outputs( - &self, - ) -> (Definitions, Box, ResolverOutputs, ty::ResolverAstLowering) { + pub fn clone_outputs(&self) -> ResolverOutputs { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); let definitions = self.definitions.clone(); let cstore = Box::new(self.cstore().clone()); - let resolutions = ResolverOutputs { + let global_ctxt = ResolverGlobalCtxt { + cstore, source_span: self.source_span.clone(), expn_that_defined: self.expn_that_defined.clone(), visibilities: self.visibilities.clone(), @@ -1460,7 +1459,7 @@ impl<'a> Resolver<'a> { registered_tools: self.registered_tools.clone(), access_levels: self.access_levels.clone(), }; - let resolutions_lowering = ty::ResolverAstLowering { + let ast_lowering = ty::ResolverAstLowering { legacy_const_generic_args: self.legacy_const_generic_args.clone(), partial_res_map: self.partial_res_map.clone(), import_res_map: self.import_res_map.clone(), @@ -1473,7 +1472,7 @@ impl<'a> Resolver<'a> { trait_map: self.trait_map.clone(), builtin_macro_kinds: self.builtin_macro_kinds.clone(), }; - (definitions, cstore, resolutions, resolutions_lowering) + ResolverOutputs { definitions, global_ctxt, ast_lowering } } fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { From 5378c82d808f01bbb0d1c03ea03b2865f10db8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Christopher=20K=C3=B6hl?= Date: Tue, 25 Oct 2022 18:31:11 +0200 Subject: [PATCH 07/10] Use &self instead of &mut self for cast methods --- compiler/rustc_const_eval/src/interpret/cast.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index f980e606b932d..cb33c4d4c465a 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -139,7 +139,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } pub fn int_to_int_or_float( - &mut self, + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate> { @@ -154,7 +154,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } pub fn float_to_float_or_int( - &mut self, + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate> { @@ -176,7 +176,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. pub fn ptr_to_ptr( - &mut self, + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate> { @@ -226,7 +226,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } pub fn pointer_from_exposed_address_cast( - &mut self, + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate> { From 726bf18d2d97eec43196e8ba48be5f28892b6729 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Oct 2022 21:38:05 +0000 Subject: [PATCH 08/10] Name impl trait in region bound suggestion --- .../nice_region_error/static_impl_trait.rs | 21 +++++++++---------- .../ret-impl-trait-one.stderr | 2 +- .../ui/impl-trait/hidden-lifetimes.stderr | 4 ++-- .../ordinary-bounds-unrelated.stderr | 2 +- .../ordinary-bounds-unsuited.stderr | 2 +- .../must_outlive_least_region_or_bound.stderr | 14 ++++++------- .../impl-trait/region-escape-via-bound.stderr | 2 +- .../static-return-lifetime-infered.stderr | 8 +++---- .../ty-outlives/impl-trait-captures.stderr | 2 +- ...types_pin_lifetime_impl_trait-async.stderr | 2 +- ..._self_types_pin_lifetime_impl_trait.stderr | 2 +- .../missing-lifetimes-in-signature.stderr | 2 +- .../trait-object-nested-in-impl-trait.stderr | 4 ++-- 13 files changed, 33 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 6bb736687d6e5..a74c172fa0c13 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -286,8 +286,8 @@ pub fn suggest_new_region_bound( ) { debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); // FIXME: account for the need of parens in `&(dyn Trait + '_)` - let consider = "consider changing the"; - let declare = "to declare that the"; + let consider = "consider changing"; + let declare = "to declare that"; let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name); let explicit_static = arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg)); @@ -305,6 +305,10 @@ pub fn suggest_new_region_bound( return; }; + // Get the identity type for this RPIT + let did = item_id.def_id.to_def_id(); + let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did)); + if let Some(span) = opaque .bounds .iter() @@ -321,7 +325,7 @@ pub fn suggest_new_region_bound( if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( span, - &format!("{} `impl Trait`'s {}", consider, explicit_static), + &format!("{consider} `{ty}`'s {explicit_static}"), &lifetime_name, Applicability::MaybeIncorrect, ); @@ -351,12 +355,7 @@ pub fn suggest_new_region_bound( } else { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), - &format!( - "{declare} `impl Trait` {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), + &format!("{declare} `{ty}` {captures}, {explicit}",), &plus_lt, Applicability::MaybeIncorrect, ); @@ -367,7 +366,7 @@ pub fn suggest_new_region_bound( err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), &format!( - "{declare} trait object {captures}, {explicit}", + "{declare} the trait object {captures}, {explicit}", declare = declare, captures = captures, explicit = explicit, @@ -384,7 +383,7 @@ pub fn suggest_new_region_bound( if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( lt.span, - &format!("{} trait object's {}", consider, explicit_static), + &format!("{} the trait object's {}", consider, explicit_static), &lifetime_name, Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index 3128b4df4e2d1..ae4d0d5853ca6 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -25,7 +25,7 @@ LL | | (a, b) LL | | } | |_^ | -help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound +help: to declare that `impl Trait<'a>` captures `'b`, you can add an explicit `'b` lifetime bound | LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { | ++++ diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr index de06ded7acdb6..3cc47e1e89da8 100644 --- a/src/test/ui/impl-trait/hidden-lifetimes.stderr +++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr @@ -6,7 +6,7 @@ LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { LL | x | ^ | -help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound +help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound | LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b { | ++++ @@ -19,7 +19,7 @@ LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl S LL | x | ^ | -help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound +help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound | LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a + 'b { | ++++ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr index cb1dc0b7d50ae..ec49a61795a0c 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -7,7 +7,7 @@ LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> im LL | if condition() { a } else { b } | ^ | -help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound +help: to declare that `impl Trait<'d, 'e>` captures `'b`, you can add an explicit `'b` lifetime bound | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b | ++++ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr index 4388e6601a6cf..c36f9bc6957c6 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -7,7 +7,7 @@ LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, LL | if condition() { a } else { b } | ^ | -help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound +help: to declare that `impl Trait<'a, 'b>` captures `'b`, you can add an explicit `'b` lifetime bound | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b | ++++ diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 16767abd72241..9c81791fbcba5 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -6,7 +6,7 @@ LL | fn elided(x: &i32) -> impl Copy { x } | | | hidden type `&i32` captures the anonymous lifetime defined here | -help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound +help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound | LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ++++ @@ -19,7 +19,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | | | hidden type `&'a i32` captures the lifetime `'a` as defined here | -help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound +help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ++++ @@ -32,7 +32,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | | | let's call the lifetime of this reference `'1` | -help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` +help: consider changing `impl Copy + 'static`'s explicit `'static` bound to the lifetime of argument `x` | LL | fn elided2(x: &i32) -> impl Copy + '_ { x } | ~~ @@ -47,7 +47,7 @@ error: lifetime may not live long enough LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` | -help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` +help: consider changing `impl Copy + 'static`'s explicit `'static` bound to the lifetime of argument `x` | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } | ~~ @@ -76,7 +76,7 @@ help: to declare that the trait object captures data from argument `x`, you can | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } | ++++ -help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound +help: to declare that `impl Debug` captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided5(x: &i32) -> (Box, impl Debug + '_) { (Box::new(x), x) } | ++++ @@ -87,7 +87,7 @@ error: lifetime may not live long enough LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` | -help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` +help: consider changing `impl LifetimeTrait<'a> + 'static`'s explicit `'static` bound to the lifetime of argument `x` | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } | ~~ @@ -104,7 +104,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 LL | move |_| println!("{}", y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound +help: to declare that `impl Fn(&'a u32)` captures `'b`, you can add an explicit `'b` lifetime bound | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b { | ++++ diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index fdb2fe022b4d2..44a790cb1a43a 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -7,7 +7,7 @@ LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> LL | x | ^ | -help: to declare that the `impl Trait` captures `'x`, you can add an explicit `'x` lifetime bound +help: to declare that `impl Trait<'y>` captures `'x`, you can add an explicit `'x` lifetime bound | LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x | ++++ diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index b868152315503..b365bd8845480 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -6,7 +6,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator { LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound +help: to declare that `impl Iterator` captures `'_`, you can add an explicit `'_` lifetime bound | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ++++ @@ -19,7 +19,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator { LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound +help: to declare that `impl Iterator` captures `'_`, you can add an explicit `'_` lifetime bound | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ++++ @@ -32,7 +32,7 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator { LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound +help: to declare that `impl Iterator` captures `'a`, you can add an explicit `'a` lifetime bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { | ++++ @@ -45,7 +45,7 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator { LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound +help: to declare that `impl Iterator` captures `'a`, you can add an explicit `'a` lifetime bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { | ++++ diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index 6a8a1ad1caadd..737cb35841cf5 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -6,7 +6,7 @@ LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { LL | x | ^ | -help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound +help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) { | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 7e7d60d0ff90a..eb3d3e4a67a98 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -6,7 +6,7 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self } | | | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here | -help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound +help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound | LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self } | ++++ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 30d2250c0c81d..2c0b2a0d91938 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -6,7 +6,7 @@ LL | fn f(self: Pin<&Self>) -> impl Clone { self } | | | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here | -help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound +help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } | ++++ diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 171f4b333db4e..fa758bf05df5a 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -18,7 +18,7 @@ LL | | *dest = g.get(); LL | | } | |_____^ | -help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound +help: to declare that `impl FnOnce()` captures `'_`, you can add an explicit `'_` lifetime bound | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ | ++++ diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr index f49876bcd3f14..c77ef79e7ed18 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr @@ -10,7 +10,7 @@ LL | | remaining: self.0.iter(), LL | | } | |_________^ returning this value requires that `'1` must outlive `'static` | -help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound +help: to declare that `impl Iterator>` captures data from argument `self`, you can add an explicit `'_` lifetime bound | LL | fn iter(&self) -> impl Iterator> + '_ { | ++++ @@ -65,7 +65,7 @@ LL | | remaining: self.0.iter(), LL | | } | |_________^ returning this value requires that `'a` must outlive `'static` | -help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound +help: to declare that `impl Iterator>` captures data from argument `self`, you can add an explicit `'a` lifetime bound | LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { | ++++ From 43e17454e2d8f650142cb671e13ca70fcbe42fcc Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 24 Oct 2022 20:59:22 +0200 Subject: [PATCH 09/10] Remove `rustc_driver::set_sigpipe_handler()` Its usage was removed in 5e624bf4ba and 093b075d32, so we do not need to keep it around any longer. According to [preliminary input](https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Find.20.60rustc_driver.60.20dependent.20projects.3F/near/304490764), we do not need to worry about any deprecation cycle for this API and can just straight up remove it. Migration instructions for remaining clients -------------------------------------------- Change from ```rust extern crate rustc_driver; fn main() { rustc_driver::set_sigpipe_handler(); // ... ``` to ```rust fn main() { // ... ``` --- compiler/rustc_driver/src/lib.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 7edbb6f757ce1..cfa734c7df39c 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -427,18 +427,6 @@ fn run_compiler( }) } -#[cfg(unix)] -pub fn set_sigpipe_handler() { - unsafe { - // Set the SIGPIPE signal handler, so that an EPIPE - // will cause rustc to terminate, as expected. - assert_ne!(libc::signal(libc::SIGPIPE, libc::SIG_DFL), libc::SIG_ERR); - } -} - -#[cfg(windows)] -pub fn set_sigpipe_handler() {} - // Extract output directory and file from matches. fn make_output(matches: &getopts::Matches) -> (Option, Option) { let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); From 5064648624c94008d54a2f1d754168d1a0d1df26 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 25 Oct 2022 12:16:25 -0700 Subject: [PATCH 10/10] Pinning tests for some macro_rules things discussed in the lang meeting --- .../ui/macros/macro_rules-unmatchable-literals.rs | 14 ++++++++++++++ .../macros/macro_rules-unmatchable-literals.stderr | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/test/ui/macros/macro_rules-unmatchable-literals.rs create mode 100644 src/test/ui/macros/macro_rules-unmatchable-literals.stderr diff --git a/src/test/ui/macros/macro_rules-unmatchable-literals.rs b/src/test/ui/macros/macro_rules-unmatchable-literals.rs new file mode 100644 index 0000000000000..bde0fe1a01574 --- /dev/null +++ b/src/test/ui/macros/macro_rules-unmatchable-literals.rs @@ -0,0 +1,14 @@ +// Pinning tests for things that don't work to make sure we notice if that changes + +#![crate_type = "lib"] + +macro_rules! octal_with_bad_digit { + ( 0o1238 ) => {}; //~ ERROR invalid digit +} + +macro_rules! binary_with_bad_digit { + ( 0b012 ) => {}; //~ ERROR invalid digit +} + +// This can't happen for Hex and Decimal as things like `123A` and `0xFFG` +// get treated as unknown *suffixes*, rather than digits. diff --git a/src/test/ui/macros/macro_rules-unmatchable-literals.stderr b/src/test/ui/macros/macro_rules-unmatchable-literals.stderr new file mode 100644 index 0000000000000..956a669791d0e --- /dev/null +++ b/src/test/ui/macros/macro_rules-unmatchable-literals.stderr @@ -0,0 +1,14 @@ +error: invalid digit for a base 8 literal + --> $DIR/macro_rules-unmatchable-literals.rs:6:12 + | +LL | ( 0o1238 ) => {}; + | ^ + +error: invalid digit for a base 2 literal + --> $DIR/macro_rules-unmatchable-literals.rs:10:11 + | +LL | ( 0b012 ) => {}; + | ^ + +error: aborting due to 2 previous errors +