diff --git a/Cargo.lock b/Cargo.lock index ebacd32db4fc7..9d91dcde9b413 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4321,6 +4321,7 @@ dependencies = [ "rustc_ast", "rustc_errors", "rustc_lint", + "rustc_macros", "rustc_metadata", "rustc_session", "rustc_span", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 598bf771008db..fb521073a428d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1751,7 +1751,8 @@ pub enum LitFloatType { /// E.g., `"foo"`, `42`, `12.34`, or `bool`. #[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)] pub enum LitKind { - /// A string literal (`"foo"`). + /// A string literal (`"foo"`). The symbol is unescaped, and so may differ + /// from the original token's symbol. Str(Symbol, StrStyle), /// A byte string (`b"foo"`). ByteStr(Lrc<[u8]>), @@ -1761,12 +1762,13 @@ pub enum LitKind { Char(char), /// An integer literal (`1`). Int(u128, LitIntType), - /// A float literal (`1f64` or `1E10f64`). + /// A float literal (`1f64` or `1E10f64`). Stored as a symbol rather than + /// `f64` so that `LitKind` can impl `Eq` and `Hash`. Float(Symbol, LitFloatType), /// A boolean literal. Bool(bool), /// Placeholder for a literal that wasn't well-formed in some way. - Err(Symbol), + Err, } impl LitKind { @@ -1805,7 +1807,7 @@ impl LitKind { | LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) | LitKind::Bool(..) - | LitKind::Err(..) => false, + | LitKind::Err => false, } } } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index e6351d89c6c31..6a02a3b56f616 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -146,7 +146,7 @@ impl LitKind { LitKind::ByteStr(bytes.into()) } - token::Err => LitKind::Err(symbol), + token::Err => LitKind::Err, }) } @@ -199,7 +199,7 @@ impl LitKind { let symbol = if value { kw::True } else { kw::False }; (token::Bool, symbol, None) } - LitKind::Err(symbol) => (token::Err, symbol, None), + LitKind::Err => unreachable!(), }; token::Lit::new(kind, symbol, suffix) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1ac1d689efbdb..8ab1daf23e86e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -928,7 +928,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { Lit { token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None), - kind: LitKind::Err(kw::Empty), + kind: LitKind::Err, span: DUMMY_SP, } }; diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index a23dd1d1213b7..41f4e8c234d5a 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -39,7 +39,7 @@ pub fn expand_concat( ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => { cx.span_err(e.span, "cannot concatenate a byte string literal"); } - ast::LitKind::Err(_) => { + ast::LitKind::Err => { has_errors = true; } }, diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index c0f35d122f8e6..66e86bf218267 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -42,7 +42,7 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne ast::LitKind::Bool(_) => { cx.span_err(expr.span, "cannot concatenate boolean literals"); } - ast::LitKind::Err(_) => {} + ast::LitKind::Err => {} ast::LitKind::Int(_, _) if !is_nested => { let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals"); if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index fd517c1e12136..2816f81fef121 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -413,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> { /// Verifies one piece of a parse string, and remembers it if valid. /// All errors are not emitted as fatal so we can continue giving errors /// about this and possibly other format strings. - fn verify_piece(&mut self, p: &parse::Piece<'_>) { + fn verify_piece(&mut self, p: &parse::Piece<'a>) { match *p { parse::String(..) => {} parse::NextArgument(ref arg) => { @@ -433,6 +433,11 @@ impl<'a, 'b> Context<'a, 'b> { let has_precision = arg.format.precision != Count::CountImplied; let has_width = arg.format.width != Count::CountImplied; + if has_precision || has_width { + // push before named params are resolved to aid diagnostics + self.arg_with_formatting.push(arg.format); + } + // argument second, if it's an implicit positional parameter // it's written second, so it should come after width/precision. let pos = match arg.position { @@ -581,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> { let mut zero_based_note = false; let count = self.pieces.len() - + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count(); + + self + .arg_with_formatting + .iter() + .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_))) + .count(); if self.names.is_empty() && !numbered_position_args && count != self.num_args() { e = self.ecx.struct_span_err( sp, @@ -647,7 +656,7 @@ impl<'a, 'b> Context<'a, 'b> { + self .arg_with_formatting .iter() - .filter(|fmt| fmt.precision_span.is_some()) + .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_))) .count(); e.span_label( span, @@ -899,26 +908,22 @@ impl<'a, 'b> Context<'a, 'b> { }, position_span: arg.position_span, format: parse::FormatSpec { - fill: arg.format.fill, + fill: None, align: parse::AlignUnknown, flags: 0, precision: parse::CountImplied, - precision_span: None, + precision_span: arg.format.precision_span, width: parse::CountImplied, - width_span: None, + width_span: arg.format.width_span, ty: arg.format.ty, ty_span: arg.format.ty_span, }, }; let fill = arg.format.fill.unwrap_or(' '); - let pos_simple = arg.position.index() == simple_arg.position.index(); - if arg.format.precision_span.is_some() || arg.format.width_span.is_some() { - self.arg_with_formatting.push(arg.format); - } - if !pos_simple || arg.format != simple_arg.format || fill != ' ' { + if !pos_simple || arg.format != simple_arg.format { self.all_pieces_simple = false; } diff --git a/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl new file mode 100644 index 0000000000000..8db32a42c1dea --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl @@ -0,0 +1,4 @@ +plugin_impl_load_plugin_error = {$msg} + +plugin_impl_malformed_plugin_attribute = malformed `plugin` attribute + .label = malformed attribute diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 3569c7f063064..3e66d12bb37ec 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -41,6 +41,7 @@ fluent_messages! { lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", + plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", typeck => "../locales/en-US/typeck.ftl", } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index df56e032988c6..2bb522caa2d41 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1227,7 +1227,7 @@ pub fn expr_to_spanned_string<'a>( ); Some((err, true)) } - ast::LitKind::Err(_) => None, + ast::LitKind::Err => None, _ => Some((cx.struct_span_err(l.span, err_msg), false)), }, ast::ExprKind::Err => None, diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 130214a653f7c..e37c0cf0fd032 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { evaluation_cache: self.evaluation_cache.clone(), reported_trait_errors: self.reported_trait_errors.clone(), reported_closure_mismatch: self.reported_closure_mismatch.clone(), - tainted_by_errors_flag: self.tainted_by_errors_flag.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), err_count_on_creation: self.err_count_on_creation, in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 444817f396e56..c95738e0018c0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -32,7 +32,7 @@ pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::{Cell, Ref, RefCell}; use std::fmt; @@ -316,12 +316,12 @@ pub struct InferCtxt<'a, 'tcx> { /// /// Don't read this flag directly, call `is_tainted_by_errors()` /// and `set_tainted_by_errors()`. - tainted_by_errors_flag: Cell, + tainted_by_errors: Cell>, /// Track how many errors were reported when this infcx is created. /// If the number of errors increases, that's also a sign (line /// `tainted_by_errors`) to avoid reporting certain kinds of errors. - // FIXME(matthewjasper) Merge into `tainted_by_errors_flag` + // FIXME(matthewjasper) Merge into `tainted_by_errors` err_count_on_creation: usize, /// This flag is true while there is an active snapshot. @@ -624,7 +624,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { evaluation_cache: Default::default(), reported_trait_errors: Default::default(), reported_closure_mismatch: Default::default(), - tainted_by_errors_flag: Cell::new(false), + tainted_by_errors: Cell::new(None), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), skip_leak_check: Cell::new(false), @@ -1227,23 +1227,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn is_tainted_by_errors(&self) -> bool { debug!( "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors_flag={})", + tainted_by_errors={})", self.tcx.sess.err_count(), self.err_count_on_creation, - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() ); if self.tcx.sess.err_count() > self.err_count_on_creation { return true; // errors reported since this infcx was made } - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() } /// Set the "tainted by errors" flag to true. We call this when we /// observe an error from a prior pass. pub fn set_tainted_by_errors(&self) { debug!("set_tainted_by_errors()"); - self.tainted_by_errors_flag.set(true) + self.tainted_by_errors.set(Some( + self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"), + )); } pub fn skip_region_resolution(&self) { diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index a6912653368b5..52c93133f79c4 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -1,139 +1,17 @@ use proc_macro::TokenStream; -use proc_macro2::{Delimiter, TokenTree}; use quote::{quote, quote_spanned}; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error, - Expr, Ident, ReturnType, Token, Type, + braced, parenthesized, parse_macro_input, parse_quote, token, AttrStyle, Attribute, Block, + Error, Expr, Ident, Pat, ReturnType, Token, Type, }; mod kw { syn::custom_keyword!(query); } -/// Ident or a wildcard `_`. -struct IdentOrWild(Ident); - -impl Parse for IdentOrWild { - fn parse(input: ParseStream<'_>) -> Result { - Ok(if input.peek(Token![_]) { - let underscore = input.parse::()?; - IdentOrWild(Ident::new("_", underscore.span())) - } else { - IdentOrWild(input.parse()?) - }) - } -} - -/// A modifier for a query -enum QueryModifier { - /// The description of the query. - Desc(Option, Punctuated), - - /// Use this type for the in-memory cache. - Storage(Type), - - /// Cache the query to disk if the `Expr` returns true. - Cache(Option, Block), - - /// Custom code to load the query from disk. - LoadCached(Ident, Ident, Block), - - /// A cycle error for this query aborting the compilation with a fatal error. - FatalCycle(Ident), - - /// A cycle error results in a delay_bug call - CycleDelayBug(Ident), - - /// Don't hash the result, instead just mark a query red if it runs - NoHash(Ident), - - /// Generate a dep node based on the dependencies of the query - Anon(Ident), - - /// Always evaluate the query, ignoring its dependencies - EvalAlways(Ident), - - /// Use a separate query provider for local and extern crates - SeparateProvideExtern(Ident), - - /// Always remap the ParamEnv's constness before hashing and passing to the query provider - RemapEnvConstness(Ident), -} - -impl Parse for QueryModifier { - fn parse(input: ParseStream<'_>) -> Result { - let modifier: Ident = input.parse()?; - if modifier == "desc" { - // Parse a description modifier like: - // `desc { |tcx| "foo {}", tcx.item_path(key) }` - let attr_content; - braced!(attr_content in input); - let tcx = if attr_content.peek(Token![|]) { - attr_content.parse::()?; - let tcx = attr_content.parse()?; - attr_content.parse::()?; - Some(tcx) - } else { - None - }; - let desc = attr_content.parse_terminated(Expr::parse)?; - Ok(QueryModifier::Desc(tcx, desc)) - } else if modifier == "cache_on_disk_if" { - // Parse a cache modifier like: - // `cache(tcx, value) { |tcx| key.is_local() }` - let has_args = if let TokenTree::Group(group) = input.fork().parse()? { - group.delimiter() == Delimiter::Parenthesis - } else { - false - }; - let args = if has_args { - let args; - parenthesized!(args in input); - let tcx = args.parse()?; - Some(tcx) - } else { - None - }; - let block = input.parse()?; - Ok(QueryModifier::Cache(args, block)) - } else if modifier == "load_cached" { - // Parse a load_cached modifier like: - // `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }` - let args; - parenthesized!(args in input); - let tcx = args.parse()?; - args.parse::()?; - let id = args.parse()?; - let block = input.parse()?; - Ok(QueryModifier::LoadCached(tcx, id, block)) - } else if modifier == "storage" { - let args; - parenthesized!(args in input); - let ty = args.parse()?; - Ok(QueryModifier::Storage(ty)) - } else if modifier == "fatal_cycle" { - Ok(QueryModifier::FatalCycle(modifier)) - } else if modifier == "cycle_delay_bug" { - Ok(QueryModifier::CycleDelayBug(modifier)) - } else if modifier == "no_hash" { - Ok(QueryModifier::NoHash(modifier)) - } else if modifier == "anon" { - Ok(QueryModifier::Anon(modifier)) - } else if modifier == "eval_always" { - Ok(QueryModifier::EvalAlways(modifier)) - } else if modifier == "separate_provide_extern" { - Ok(QueryModifier::SeparateProvideExtern(modifier)) - } else if modifier == "remap_env_constness" { - Ok(QueryModifier::RemapEnvConstness(modifier)) - } else { - Err(Error::new(modifier.span(), "unknown query modifier")) - } - } -} - /// Ensures only doc comment attributes are used fn check_attributes(attrs: Vec) -> Result> { let inner = |attr: Attribute| { @@ -154,16 +32,16 @@ fn check_attributes(attrs: Vec) -> Result> { /// A compiler query. `query ... { ... }` struct Query { doc_comments: Vec, - modifiers: List, + modifiers: QueryModifiers, name: Ident, - key: IdentOrWild, + key: Pat, arg: Type, result: ReturnType, } impl Parse for Query { fn parse(input: ParseStream<'_>) -> Result { - let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; + let mut doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` input.parse::()?; @@ -178,7 +56,13 @@ impl Parse for Query { // Parse the query modifiers let content; braced!(content in input); - let modifiers = content.parse()?; + let modifiers = parse_query_modifiers(&content)?; + + // If there are no doc-comments, give at least some idea of what + // it does by showing the query description. + if doc_comments.is_empty() { + doc_comments.push(doc_comment_from_desc(&modifiers.desc.1)?); + } Ok(Query { doc_comments, modifiers, name, key, arg, result }) } @@ -205,7 +89,7 @@ struct QueryModifiers { storage: Option, /// Cache the query to disk if the `Block` returns true. - cache: Option<(Option, Block)>, + cache: Option<(Option, Block)>, /// Custom code to load the query from disk. load_cached: Option<(Ident, Ident, Block)>, @@ -232,8 +116,7 @@ struct QueryModifiers { remap_env_constness: Option, } -/// Process query modifiers into a struct, erroring on duplicates -fn process_modifiers(query: &mut Query) -> QueryModifiers { +fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut load_cached = None; let mut storage = None; let mut cache = None; @@ -245,117 +128,84 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { let mut eval_always = None; let mut separate_provide_extern = None; let mut remap_env_constness = None; - for modifier in query.modifiers.0.drain(..) { - match modifier { - QueryModifier::LoadCached(tcx, id, block) => { - if load_cached.is_some() { - panic!("duplicate modifier `load_cached` for query `{}`", query.name); - } - load_cached = Some((tcx, id, block)); - } - QueryModifier::Storage(ty) => { - if storage.is_some() { - panic!("duplicate modifier `storage` for query `{}`", query.name); - } - storage = Some(ty); - } - QueryModifier::Cache(args, expr) => { - if cache.is_some() { - panic!("duplicate modifier `cache` for query `{}`", query.name); - } - cache = Some((args, expr)); - } - QueryModifier::Desc(tcx, list) => { - if desc.is_some() { - panic!("duplicate modifier `desc` for query `{}`", query.name); - } - // If there are no doc-comments, give at least some idea of what - // it does by showing the query description. - if query.doc_comments.is_empty() { - use ::syn::*; - let mut list = list.iter(); - let format_str: String = match list.next() { - Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => { - lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency - } - _ => panic!("Expected a string literal"), - }; - let mut fmt_fragments = format_str.split("{}"); - let mut doc_string = fmt_fragments.next().unwrap().to_string(); - list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each( - |(tts, next_fmt_fragment)| { - use ::core::fmt::Write; - write!( - &mut doc_string, - " `{}` {}", - tts.to_string().replace(" . ", "."), - next_fmt_fragment, - ) - .unwrap(); - }, - ); - let doc_string = format!( - "[query description - consider adding a doc-comment!] {}", - doc_string - ); - let comment = parse_quote! { - #[doc = #doc_string] - }; - query.doc_comments.push(comment); - } - desc = Some((tcx, list)); - } - QueryModifier::FatalCycle(ident) => { - if fatal_cycle.is_some() { - panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name); - } - fatal_cycle = Some(ident); - } - QueryModifier::CycleDelayBug(ident) => { - if cycle_delay_bug.is_some() { - panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name); - } - cycle_delay_bug = Some(ident); - } - QueryModifier::NoHash(ident) => { - if no_hash.is_some() { - panic!("duplicate modifier `no_hash` for query `{}`", query.name); - } - no_hash = Some(ident); - } - QueryModifier::Anon(ident) => { - if anon.is_some() { - panic!("duplicate modifier `anon` for query `{}`", query.name); - } - anon = Some(ident); - } - QueryModifier::EvalAlways(ident) => { - if eval_always.is_some() { - panic!("duplicate modifier `eval_always` for query `{}`", query.name); - } - eval_always = Some(ident); - } - QueryModifier::SeparateProvideExtern(ident) => { - if separate_provide_extern.is_some() { - panic!( - "duplicate modifier `separate_provide_extern` for query `{}`", - query.name - ); - } - separate_provide_extern = Some(ident); - } - QueryModifier::RemapEnvConstness(ident) => { - if remap_env_constness.is_some() { - panic!("duplicate modifier `remap_env_constness` for query `{}`", query.name); + + while !input.is_empty() { + let modifier: Ident = input.parse()?; + + macro_rules! try_insert { + ($name:ident = $expr:expr) => { + if $name.is_some() { + return Err(Error::new(modifier.span(), "duplicate modifier")); } - remap_env_constness = Some(ident) - } + $name = Some($expr); + }; + } + + if modifier == "desc" { + // Parse a description modifier like: + // `desc { |tcx| "foo {}", tcx.item_path(key) }` + let attr_content; + braced!(attr_content in input); + let tcx = if attr_content.peek(Token![|]) { + attr_content.parse::()?; + let tcx = attr_content.parse()?; + attr_content.parse::()?; + Some(tcx) + } else { + None + }; + let list = attr_content.parse_terminated(Expr::parse)?; + try_insert!(desc = (tcx, list)); + } else if modifier == "cache_on_disk_if" { + // Parse a cache modifier like: + // `cache(tcx) { |tcx| key.is_local() }` + let args = if input.peek(token::Paren) { + let args; + parenthesized!(args in input); + let tcx = args.parse()?; + Some(tcx) + } else { + None + }; + let block = input.parse()?; + try_insert!(cache = (args, block)); + } else if modifier == "load_cached" { + // Parse a load_cached modifier like: + // `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }` + let args; + parenthesized!(args in input); + let tcx = args.parse()?; + args.parse::()?; + let id = args.parse()?; + let block = input.parse()?; + try_insert!(load_cached = (tcx, id, block)); + } else if modifier == "storage" { + let args; + parenthesized!(args in input); + let ty = args.parse()?; + try_insert!(storage = ty); + } else if modifier == "fatal_cycle" { + try_insert!(fatal_cycle = modifier); + } else if modifier == "cycle_delay_bug" { + try_insert!(cycle_delay_bug = modifier); + } else if modifier == "no_hash" { + try_insert!(no_hash = modifier); + } else if modifier == "anon" { + try_insert!(anon = modifier); + } else if modifier == "eval_always" { + try_insert!(eval_always = modifier); + } else if modifier == "separate_provide_extern" { + try_insert!(separate_provide_extern = modifier); + } else if modifier == "remap_env_constness" { + try_insert!(remap_env_constness = modifier); + } else { + return Err(Error::new(modifier.span(), "unknown query modifier")); } } - let desc = desc.unwrap_or_else(|| { - panic!("no description provided for query `{}`", query.name); - }); - QueryModifiers { + let Some(desc) = desc else { + return Err(input.error("no description provided")); + }; + Ok(QueryModifiers { load_cached, storage, cache, @@ -367,17 +217,41 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { eval_always, separate_provide_extern, remap_env_constness, - } + }) +} + +fn doc_comment_from_desc(list: &Punctuated) -> Result { + use ::syn::*; + let mut iter = list.iter(); + let format_str: String = match iter.next() { + Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => { + lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency + } + _ => return Err(Error::new(list.span(), "Expected a string literal")), + }; + let mut fmt_fragments = format_str.split("{}"); + let mut doc_string = fmt_fragments.next().unwrap().to_string(); + iter.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each( + |(tts, next_fmt_fragment)| { + use ::core::fmt::Write; + write!( + &mut doc_string, + " `{}` {}", + tts.to_string().replace(" . ", "."), + next_fmt_fragment, + ) + .unwrap(); + }, + ); + let doc_string = format!("[query description - consider adding a doc-comment!] {}", doc_string); + Ok(parse_quote! { #[doc = #doc_string] }) } /// Add the impl of QueryDescription for the query to `impls` if one is requested -fn add_query_description_impl( - query: &Query, - modifiers: QueryModifiers, - impls: &mut proc_macro2::TokenStream, -) { +fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) { let name = &query.name; - let key = &query.key.0; + let key = &query.key; + let modifiers = &query.modifiers; // Find out if we should cache the query on disk let cache = if let Some((args, expr)) = modifiers.cache.as_ref() { @@ -395,13 +269,7 @@ fn add_query_description_impl( } }; - let tcx = args - .as_ref() - .map(|t| { - let t = &t.0; - quote! { #t } - }) - .unwrap_or_else(|| quote! { _ }); + let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ }); // expr is a `Block`, meaning that `{ #expr }` gets expanded // to `{ { stmts... } }`, which triggers the `unused_braces` lint. quote! { @@ -427,7 +295,7 @@ fn add_query_description_impl( } }; - let (tcx, desc) = modifiers.desc; + let (tcx, desc) = &modifiers.desc; let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t }); let desc = quote! { @@ -456,10 +324,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut dep_node_def_stream = quote! {}; let mut cached_queries = quote! {}; - for mut query in queries.0 { - let modifiers = process_modifiers(&mut query); - let name = &query.name; - let arg = &query.arg; + for query in queries.0 { + let Query { name, arg, modifiers, .. } = &query; let result_full = &query.result; let result = match query.result { ReturnType::Default => quote! { -> () }, @@ -528,7 +394,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] #name(#arg), }); - add_query_description_impl(&query, modifiers, &mut query_description_stream); + add_query_description_impl(&query, &mut query_description_stream); } TokenStream::from(quote! { @@ -539,7 +405,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { $($other)* #query_stream - } } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 648d10b9e42a8..19d420f154d5c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -144,7 +144,7 @@ pub(crate) fn lit_to_mir_constant<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), - (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + (ast::LitKind::Err, _) => return Err(LitToConstError::Reported), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index a7e4403a242e1..f626571b5b2c5 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -44,7 +44,7 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), - (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + (ast::LitKind::Err, _) => return Err(LitToConstError::Reported), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index 56d7799a125b0..95fda2eafe8a1 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -84,7 +84,7 @@ where TerminatorKind::Unreachable } else if is_unreachable(otherwise) { // If there are multiple targets, don't delete unreachable branches (like an unreachable otherwise) - // unless otherwise is unrachable, in which case deleting a normal branch causes it to be merged with + // unless otherwise is unreachable, in which case deleting a normal branch causes it to be merged with // the otherwise, keeping its unreachable. // This looses information about reachability causing worse codegen. // For example (see src/test/codegen/match-optimizes-away.rs) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d61da7b6cc00d..f6516d3bd4543 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1383,7 +1383,7 @@ impl<'a> Parser<'a> { match self.parse_str_lit() { Ok(str_lit) => Some(str_lit), Err(Some(lit)) => match lit.kind { - ast::LitKind::Err(_) => None, + ast::LitKind::Err => None, _ => { self.struct_span_err(lit.span, "non-string ABI literal") .span_suggestion( diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e4842d2afb705..b63a173cc29e6 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -264,9 +264,7 @@ impl<'a> Iterator for Parser<'a> { } } else { if self.is_literal { - let start = self.to_span_index(self.cur_line_start); - let end = self.to_span_index(self.input.len()); - let span = start.to(end); + let span = self.span(self.cur_line_start, self.input.len()); if self.line_spans.last() != Some(&span) { self.line_spans.push(span); } @@ -384,6 +382,12 @@ impl<'a> Parser<'a> { InnerOffset(raw + pos + 1) } + fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan { + let start = self.to_span_index(start_pos); + let end = self.to_span_index(end_pos); + start.to(end) + } + /// Forces consumption of the specified character. If the character is not /// found, an error is emitted. fn must_consume(&mut self, c: char) -> Option { @@ -472,9 +476,7 @@ impl<'a> Parser<'a> { return &self.input[start..pos]; } '\n' if self.is_literal => { - let start = self.to_span_index(self.cur_line_start); - let end = self.to_span_index(pos); - self.line_spans.push(start.to(end)); + self.line_spans.push(self.span(self.cur_line_start, pos)); self.cur_line_start = pos + 1; self.cur.next(); } @@ -537,6 +539,10 @@ impl<'a> Parser<'a> { } } + fn current_pos(&mut self) -> usize { + if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() } + } + /// Parses a format specifier at the current position, returning all of the /// relevant information in the `FormatSpec` struct. fn format(&mut self) -> FormatSpec<'a> { @@ -590,39 +596,37 @@ impl<'a> Parser<'a> { // no '0' flag and '0$' as the width instead. if let Some(end) = self.consume_pos('$') { spec.width = CountIsParam(0); - - if let Some((pos, _)) = self.cur.peek().cloned() { - spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos))); - } + spec.width_span = Some(self.span(end - 1, end + 1)); havewidth = true; - spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1))); } else { spec.flags |= 1 << (FlagSignAwareZeroPad as u32); } } + if !havewidth { - let width_span_start = if let Some((pos, _)) = self.cur.peek() { *pos } else { 0 }; - let (w, sp) = self.count(width_span_start); - spec.width = w; - spec.width_span = sp; + let start = self.current_pos(); + spec.width = self.count(start); + if spec.width != CountImplied { + let end = self.current_pos(); + spec.width_span = Some(self.span(start, end)); + } } if let Some(start) = self.consume_pos('.') { - if let Some(end) = self.consume_pos('*') { + if self.consume('*') { // Resolve `CountIsNextParam`. // We can do this immediately as `position` is resolved later. let i = self.curarg; self.curarg += 1; spec.precision = CountIsParam(i); - spec.precision_span = - Some(self.to_span_index(start).to(self.to_span_index(end + 1))); } else { - let (p, sp) = self.count(start); - spec.precision = p; - spec.precision_span = sp; + spec.precision = self.count(start + 1); } + let end = self.current_pos(); + spec.precision_span = Some(self.span(start, end)); } - let ty_span_start = self.cur.peek().map(|(pos, _)| *pos); + + let ty_span_start = self.current_pos(); // Optional radix followed by the actual format specifier if self.consume('x') { if self.consume('?') { @@ -642,11 +646,9 @@ impl<'a> Parser<'a> { spec.ty = "?"; } else { spec.ty = self.word(); - let ty_span_end = self.cur.peek().map(|(pos, _)| *pos); if !spec.ty.is_empty() { - spec.ty_span = ty_span_start - .and_then(|s| ty_span_end.map(|e| (s, e))) - .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end))); + let ty_span_end = self.current_pos(); + spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); } } spec @@ -670,13 +672,11 @@ impl<'a> Parser<'a> { return spec; } - let ty_span_start = self.cur.peek().map(|(pos, _)| *pos); + let ty_span_start = self.current_pos(); spec.ty = self.word(); - let ty_span_end = self.cur.peek().map(|(pos, _)| *pos); if !spec.ty.is_empty() { - spec.ty_span = ty_span_start - .and_then(|s| ty_span_end.map(|e| (s, e))) - .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end))); + let ty_span_end = self.current_pos(); + spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); } spec @@ -685,26 +685,21 @@ impl<'a> Parser<'a> { /// Parses a `Count` parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. - fn count(&mut self, start: usize) -> (Count<'a>, Option) { + fn count(&mut self, start: usize) -> Count<'a> { if let Some(i) = self.integer() { - if let Some(end) = self.consume_pos('$') { - let span = self.to_span_index(start).to(self.to_span_index(end + 1)); - (CountIsParam(i), Some(span)) - } else { - (CountIs(i), None) - } + if self.consume('$') { CountIsParam(i) } else { CountIs(i) } } else { let tmp = self.cur.clone(); let word = self.word(); if word.is_empty() { self.cur = tmp; - (CountImplied, None) + CountImplied } else if let Some(end) = self.consume_pos('$') { - let span = self.to_span_index(start + 1).to(self.to_span_index(end)); - (CountIsName(word, span), None) + let name_span = self.span(start, end); + CountIsName(word, name_span) } else { self.cur = tmp; - (CountImplied, None) + CountImplied } } } @@ -737,7 +732,7 @@ impl<'a> Parser<'a> { "invalid argument name `_`", "invalid argument name", "argument name cannot be a single underscore", - self.to_span_index(start).to(self.to_span_index(end)), + self.span(start, end), ); } word diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index 578530696105d..44ef0cd0eb5d2 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -1,5 +1,6 @@ use super::*; +#[track_caller] fn same(fmt: &'static str, p: &[Piece<'static>]) { let parser = Parser::new(fmt, None, None, false, ParseMode::Format); assert_eq!(parser.collect::>>(), p); @@ -190,9 +191,9 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountImplied, - width: CountIs(10), precision_span: None, - width_span: None, + width: CountIs(10), + width_span: Some(InnerSpan { start: 3, end: 5 }), ty: "x", ty_span: None, }, @@ -208,9 +209,9 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountIs(10), + precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(10), - precision_span: None, - width_span: Some(InnerSpan::new(3, 6)), + width_span: Some(InnerSpan { start: 3, end: 6 }), ty: "x", ty_span: None, }, @@ -226,9 +227,9 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountIs(10), + precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(0), - precision_span: None, - width_span: Some(InnerSpan::new(4, 6)), + width_span: Some(InnerSpan { start: 4, end: 6 }), ty: "x", ty_span: None, }, @@ -244,8 +245,8 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountIsParam(0), + precision_span: Some(InnerSpan { start: 3, end: 5 }), width: CountImplied, - precision_span: Some(InnerSpan::new(3, 5)), width_span: None, ty: "x", ty_span: None, @@ -279,15 +280,33 @@ fn format_counts() { fill: None, align: AlignUnknown, flags: 0, - precision: CountIsName("b", InnerSpan::new(6, 7)), - width: CountIsName("a", InnerSpan::new(4, 4)), - precision_span: None, - width_span: None, + precision: CountIsName("b", InnerSpan { start: 6, end: 7 }), + precision_span: Some(InnerSpan { start: 5, end: 8 }), + width: CountIsName("a", InnerSpan { start: 3, end: 4 }), + width_span: Some(InnerSpan { start: 3, end: 5 }), ty: "?", ty_span: None, }, })], ); + same( + "{:.4}", + &[NextArgument(Argument { + position: ArgumentImplicitlyIs(0), + position_span: InnerSpan { start: 2, end: 2 }, + format: FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountIs(4), + precision_span: Some(InnerSpan { start: 3, end: 5 }), + width: CountImplied, + width_span: None, + ty: "", + ty_span: None, + }, + })], + ) } #[test] fn format_flags() { diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml index b6ea533c80bdd..c409b6c3e5440 100644 --- a/compiler/rustc_plugin_impl/Cargo.toml +++ b/compiler/rustc_plugin_impl/Cargo.toml @@ -11,6 +11,7 @@ doctest = false libloading = "0.7.1" rustc_errors = { path = "../rustc_errors" } rustc_lint = { path = "../rustc_lint" } +rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_ast = { path = "../rustc_ast" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs new file mode 100644 index 0000000000000..2bdb6e4feca9d --- /dev/null +++ b/compiler/rustc_plugin_impl/src/errors.rs @@ -0,0 +1,20 @@ +//! Errors emitted by plugin_impl + +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[diag(plugin_impl::load_plugin_error)] +pub struct LoadPluginError { + #[primary_span] + pub span: Span, + pub msg: String, +} + +#[derive(SessionDiagnostic)] +#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")] +pub struct MalformedPluginAttribute { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index 1195045bdea4a..9ac27c65da82e 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -8,9 +8,12 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use rustc_lint::LintStore; +mod errors; pub mod load; /// Structure used to register plugins. diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs index 618682da4e597..8e75e969ae032 100644 --- a/compiler/rustc_plugin_impl/src/load.rs +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -1,16 +1,14 @@ //! Used by `rustc` when loading a plugin. +use crate::errors::{LoadPluginError, MalformedPluginAttribute}; use crate::Registry; use libloading::Library; use rustc_ast::Crate; -use rustc_errors::struct_span_err; use rustc_metadata::locator; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; -use std::borrow::ToOwned; use std::env; use std::mem; use std::path::PathBuf; @@ -18,12 +16,6 @@ use std::path::PathBuf; /// Pointer to a registrar function. type PluginRegistrarFn = fn(&mut Registry<'_>); -fn call_malformed_plugin_attribute(sess: &Session, span: Span) { - struct_span_err!(sess, span, E0498, "malformed `plugin` attribute") - .span_label(span, "malformed attribute") - .emit(); -} - /// Read plugin metadata and dynamically load registrar functions. pub fn load_plugins( sess: &Session, @@ -42,7 +34,9 @@ pub fn load_plugins( Some(ident) if plugin.is_word() => { load_plugin(&mut plugins, sess, metadata_loader, ident) } - _ => call_malformed_plugin_attribute(sess, plugin.span()), + _ => { + sess.emit_err(MalformedPluginAttribute { span: plugin.span() }); + } } } } @@ -60,7 +54,7 @@ fn load_plugin( let fun = dylink_registrar(lib).unwrap_or_else(|err| { // This is fatal: there are almost certainly macros we need inside this crate, so // continuing would spew "macro undefined" errors. - sess.span_fatal(ident.span, &err.to_string()); + sess.emit_fatal(LoadPluginError { span: ident.span, msg: err.to_string() }); }); plugins.push(fun); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 325b0458638af..25013036d8749 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -511,7 +511,7 @@ impl<'a> Resolver<'a> { err.span_label(span, "use of generic parameter from outer function"); let sm = self.session.source_map(); - match outer_res { + let def_id = match outer_res { Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => { if let Some(impl_span) = maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) @@ -536,11 +536,13 @@ impl<'a> Resolver<'a> { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "type parameter from outer function"); } + def_id } Res::Def(DefKind::ConstParam, def_id) => { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "const parameter from outer function"); } + def_id } _ => { bug!( @@ -548,28 +550,23 @@ impl<'a> Resolver<'a> { DefKind::TyParam or DefKind::ConstParam" ); } - } + }; - if has_generic_params == HasGenericParams::Yes { + if let HasGenericParams::Yes(span) = has_generic_params { // Try to retrieve the span of the function signature and generate a new // message with a local type or const parameter. let sugg_msg = "try using a local generic parameter instead"; - if let Some((sugg_span, snippet)) = sm.generate_local_type_param_snippet(span) { - // Suggest the modification to the user - err.span_suggestion( - sugg_span, - sugg_msg, - snippet, - Applicability::MachineApplicable, - ); - } else if let Some(sp) = sm.generate_fn_name_span(span) { - err.span_label( - sp, - "try adding a local generic parameter in this method instead", - ); + let name = self.opt_name(def_id).unwrap_or(sym::T); + let (span, snippet) = if span.is_empty() { + let snippet = format!("<{}>", name); + (span, snippet) } else { - err.help("try using a local generic parameter instead"); - } + let span = sm.span_through_char(span, '<').shrink_to_hi(); + let snippet = format!("{}, ", name); + (span, snippet) + }; + // Suggest the modification to the user + err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect); } err diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6e6782881427b..41a0c76d83a95 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -13,7 +13,9 @@ use rustc_span::{Span, DUMMY_SP}; use std::ptr; -use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind}; +use crate::late::{ + ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind, +}; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; @@ -1103,7 +1105,7 @@ impl<'a> Resolver<'a> { | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. } - ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => { + ItemRibKind(_) | AssocItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -1168,10 +1170,10 @@ impl<'a> Resolver<'a> { let has_generic_params: HasGenericParams = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. continue; @@ -1180,7 +1182,9 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { // HACK(min_const_generics): If we encounter `Self` in an anonymous constant // we can't easily tell if it's generic at this stage, so we instead remember // this and then enforce the self type to be concrete later on. @@ -1207,7 +1211,6 @@ impl<'a> Resolver<'a> { // This was an attempt to use a type parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( @@ -1232,28 +1235,22 @@ impl<'a> Resolver<'a> { } } Res::Def(DefKind::ConstParam, _) => { - let mut ribs = ribs.iter().peekable(); - if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { - // When declaring const parameters inside function signatures, the first rib - // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it - // (spuriously) conflicting with the const param. - ribs.next(); - } - for rib in ribs { let has_generic_params = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => continue, ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { if let Some(span) = finalize { self.report_error( span, @@ -1272,7 +1269,6 @@ impl<'a> Resolver<'a> { } ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 58a4cff55db7d..693ec86616ee4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -91,13 +91,20 @@ enum PatBoundCtx { } /// Does this the item (from the item rib scope) allow generic parameters? -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug)] pub(crate) enum HasGenericParams { + Yes(Span), + No, +} + +/// May this constant have generics? +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum ConstantHasGenerics { Yes, No, } -impl HasGenericParams { +impl ConstantHasGenerics { fn force_yes_if(self, b: bool) -> Self { if b { Self::Yes } else { self } } @@ -125,10 +132,6 @@ pub(crate) enum RibKind<'a> { /// We passed through a closure. Disallow labels. ClosureOrAsyncRibKind, - /// We passed through a function definition. Disallow upvars. - /// Permit only those const parameters that are specified in the function's generics. - FnItemRibKind, - /// We passed through an item scope. Disallow upvars. ItemRibKind(HasGenericParams), @@ -136,7 +139,7 @@ pub(crate) enum RibKind<'a> { /// /// The item may reference generic parameters in trivial constant expressions. /// All other constants aren't allowed to use generic params at all. - ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>), + ConstantItemRibKind(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), /// We passed through a module. ModuleRibKind(Module<'a>), @@ -165,7 +168,6 @@ impl RibKind<'_> { match self { NormalRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ConstantItemRibKind(..) | ModuleRibKind(_) | MacroDefinition(_) @@ -182,7 +184,6 @@ impl RibKind<'_> { AssocItemRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ItemRibKind(..) | ConstantItemRibKind(..) | ModuleRibKind(..) @@ -751,7 +752,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Item, @@ -765,7 +766,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Function, @@ -786,7 +787,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) { - let rib_kind = match fn_kind { + let previous_value = self.diagnostic_metadata.current_function; + match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) @@ -809,20 +811,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ); return; } - FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, - FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, - FnKind::Closure(..) => ClosureOrAsyncRibKind, + FnKind::Fn(..) => { + self.diagnostic_metadata.current_function = Some((fn_kind, sp)); + } + // Do not update `current_function` for closures: it suggests `self` parameters. + FnKind::Closure(..) => {} }; - let previous_value = self.diagnostic_metadata.current_function; - if matches!(fn_kind, FnKind::Fn(..)) { - self.diagnostic_metadata.current_function = Some((fn_kind, sp)); - } debug!("(resolving function) entering function"); // Create a value rib for the function. - self.with_rib(ValueNS, rib_kind, |this| { + self.with_rib(ValueNS, ClosureOrAsyncRibKind, |this| { // Create a label rib for the function. - this.with_label_rib(FnItemRibKind, |this| { + this.with_label_rib(ClosureOrAsyncRibKind, |this| { match fn_kind { FnKind::Fn(_, _, sig, _, generics, body) => { this.visit_generics(generics); @@ -995,7 +995,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // non-trivial constants this is doesn't matter. self.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| { this.smart_resolve_path( @@ -2071,7 +2071,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2141,7 +2141,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2154,7 +2154,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Function, @@ -2186,7 +2186,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2210,7 +2210,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2251,7 +2251,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // so it doesn't matter whether this is a trivial constant. this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, Some((item.ident, constant_item_kind)), |this| this.visit_expr(expr), ); @@ -2450,7 +2450,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn with_constant_rib( &mut self, is_repeat: IsRepeatExpr, - may_use_generics: HasGenericParams, + may_use_generics: ConstantHasGenerics, item: Option<(Ident, ConstantItemKind)>, f: impl FnOnce(&mut Self), ) { @@ -2517,7 +2517,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -2598,7 +2598,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { span: generics.span, binder: item_id, @@ -2689,7 +2689,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -3696,9 +3696,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( is_repeat, if constant.value.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| visit::walk_anon_const(this, constant), @@ -3707,8 +3707,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_inline_const(&mut self, constant: &'ast AnonConst) { debug!("resolve_anon_const {constant:?}"); - self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { - visit::walk_anon_const(this, constant); + self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| { + visit::walk_anon_const(this, constant) }); } @@ -3814,9 +3814,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( IsRepeatExpr::No, if argument.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9c213da8c2a2c..eb727debc91bb 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1945,6 +1945,16 @@ impl<'a> Resolver<'a> { def_id.as_local().map(|def_id| self.source_span[def_id]) } + /// Retrieves the name of the given `DefId`. + #[inline] + pub fn opt_name(&self, def_id: DefId) -> Option { + let def_key = match def_id.as_local() { + Some(def_id) => self.definitions.def_key(def_id), + None => self.cstore().def_key(def_id), + }; + def_key.get_opt_name() + } + /// Checks if an expression refers to a function marked with /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 5f928707ea826..a32cabab4c407 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -982,93 +982,6 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn generate_fn_name_span(&self, span: Span) -> Option { - let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?; - if let Ok(snippet) = self.span_to_snippet(prev_span) { - debug!( - "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", - span, prev_span, snippet - ); - - if snippet.is_empty() { - return None; - }; - - let len = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))) - } else { - None - } - } - - /// Takes the span of a type parameter in a function signature and try to generate a span for - /// the function name (with generics) and a new snippet for this span with the pointed type - /// parameter as a new local type parameter. - /// - /// For instance: - /// ```rust,ignore (pseudo-Rust) - /// // Given span - /// fn my_function(param: T) - /// // ^ Original span - /// - /// // Result - /// fn my_function(param: T) - /// // ^^^^^^^^^^^ Generated span with snippet `my_function` - /// ``` - /// - /// Attention: The method used is very fragile since it essentially duplicates the work of the - /// parser. If you need to use this function or something similar, please consider updating the - /// `SourceMap` functions and this function to something more robust. - pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { - // Try to extend the span to the previous "fn" keyword to retrieve the function - // signature. - if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) { - if let Ok(snippet) = self.span_to_snippet(sugg_span) { - // Consume the function name. - let mut offset = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - - // Consume the generics part of the function signature. - let mut bracket_counter = 0; - let mut last_char = None; - for c in snippet[offset..].chars() { - match c { - '<' => bracket_counter += 1, - '>' => bracket_counter -= 1, - '(' => { - if bracket_counter == 0 { - break; - } - } - _ => {} - } - offset += c.len_utf8(); - last_char = Some(c); - } - - // Adjust the suggestion span to encompass the function name with its generics. - let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32)); - - // Prepare the new suggested snippet to append the type parameter that triggered - // the error in the generics of the function signature. - let mut new_snippet = if last_char == Some('>') { - format!("{}, ", &snippet[..(offset - '>'.len_utf8())]) - } else { - format!("{}<", &snippet[..offset]) - }; - new_snippet - .push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string())); - new_snippet.push('>'); - - return Some((sugg_span, new_snippet)); - } - } - - None - } pub fn ensure_source_file_source_present(&self, source_file: Lrc) -> bool { source_file.add_external_src(|| { match source_file.name { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 156f53ac48626..c8978845ffb0d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -280,6 +280,7 @@ symbols! { StructuralPartialEq, SubdiagnosticMessage, Sync, + T, Target, ToOwned, ToString, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 85ff6e23711ca..d922f893321a8 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -473,9 +473,6 @@ pub fn impossible_predicates<'tcx>( debug!("impossible_predicates(predicates={:?})", predicates); let result = tcx.infer_ctxt().enter(|infcx| { - // HACK: Set tainted by errors to gracefully exit in case of overflow. - infcx.set_tainted_by_errors(); - let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates); diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index dfef924f6993a..df171c2531a7a 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -858,8 +858,7 @@ fn compare_synthetic_generics<'tcx>( { if impl_synthetic != trait_synthetic { let impl_def_id = impl_def_id.expect_local(); - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id); - let impl_span = tcx.hir().span(impl_hir_id); + let impl_span = tcx.def_span(impl_def_id); let trait_span = tcx.def_span(trait_def_id); let mut err = struct_span_err!( tcx.sess, @@ -878,17 +877,16 @@ fn compare_synthetic_generics<'tcx>( // try taking the name from the trait impl // FIXME: this is obviously suboptimal since the name can already be used // as another generic argument - let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?; + let new_name = tcx.opt_item_name(trait_def_id)?; let trait_m = trait_m.def_id.as_local()?; - let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }); + let trait_m = tcx.hir().expect_trait_item(trait_m); let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); // in case there are no generics, take the spot between the function name // and the opening paren of the argument list - let new_generics_span = - tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi(); + let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi(); // in case there are generics, just replace them let generics_span = impl_m.generics.span.substitute_dummy(new_generics_span); @@ -900,7 +898,7 @@ fn compare_synthetic_generics<'tcx>( "try changing the `impl Trait` argument to a generic parameter", vec![ // replace `impl Trait` with `T` - (impl_span, new_name), + (impl_span, new_name.to_string()), // replace impl method generics with trait method generics // This isn't quite right, as users might have changed the names // of the generics, but it works for the common case @@ -917,7 +915,7 @@ fn compare_synthetic_generics<'tcx>( err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); (|| { let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); let input_tys = match impl_m.kind { hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs, _ => unreachable!(), diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 5ff62f36b4527..71ae54bedce46 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1556,7 +1556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut error_happened = false; // Type-check each field. - for field in ast_fields { + for (idx, field) in ast_fields.iter().enumerate() { let ident = tcx.adjust_ident(field.ident, variant.def_id); let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { seen_fields.insert(ident, field.span); @@ -1594,7 +1594,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue type-checking. - self.check_expr_coercable_to_type(&field.expr, field_type, None); + let ty = self.check_expr_with_hint(&field.expr, field_type); + let (_, diag) = + self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No); + + if let Some(mut diag) = diag { + if idx == ast_fields.len() - 1 && remaining_fields.is_empty() { + self.suggest_fru_from_range(field, variant, substs, &mut diag); + } + diag.emit(); + } } // Make sure the programmer specified correct number of fields. @@ -1822,25 +1831,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); - // If the last field is a range literal, but it isn't supposed to be, then they probably - // meant to use functional update syntax. - // + if let Some(last) = ast_fields.last() { + self.suggest_fru_from_range(last, variant, substs, &mut err); + } + + err.emit(); + } + + /// If the last field is a range literal, but it isn't supposed to be, then they probably + /// meant to use functional update syntax. + fn suggest_fru_from_range( + &self, + last_expr_field: &hir::ExprField<'tcx>, + variant: &ty::VariantDef, + substs: SubstsRef<'tcx>, + err: &mut Diagnostic, + ) { // I don't use 'is_range_literal' because only double-sided, half-open ranges count. - if let Some(( - last, - ExprKind::Struct( + if let ExprKind::Struct( QPath::LangItem(LangItem::Range, ..), &[ref range_start, ref range_end], _, - ), - )) = ast_fields.last().map(|last| (last, &last.expr.kind)) && - let variant_field = - variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) && - let range_def_id = self.tcx.lang_items().range_struct() && - variant_field - .and_then(|field| field.ty(self.tcx, substs).ty_adt_def()) - .map(|adt| adt.did()) - != range_def_id + ) = last_expr_field.expr.kind + && let variant_field = + variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident) + && let range_def_id = self.tcx.lang_items().range_struct() + && variant_field + .and_then(|field| field.ty(self.tcx, substs).ty_adt_def()) + .map(|adt| adt.did()) + != range_def_id { let instead = self .tcx @@ -1856,8 +1875,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - - err.emit(); } /// Report an error for a struct field expression when there are invisible fields. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3642b2ab03bfa..03bd485096a9c 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1136,7 +1136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_ty.unwrap_or_else(|| self.next_float_var()) } ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::Err(_) => tcx.ty_error(), + ast::LitKind::Err => tcx.ty_error(), } } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 3b2601e755a97..02090afc82f7e 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -73,10 +73,8 @@ impl UnixListener { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - #[cfg(target_os = "linux")] - const backlog: libc::c_int = -1; - #[cfg(not(target_os = "linux"))] - const backlog: libc::c_int = 128; + const backlog: libc::c_int = + if cfg!(any(target_os = "linux", target_os = "freebsd")) { -1 } else { 128 }; cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; diff --git a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr index a9f9787d87595..e3bf38b702e75 100644 --- a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr +++ b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr @@ -4,7 +4,7 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo() { | - const parameter from outer function LL | fn bar() -> u32 { - | --- try adding a local generic parameter in this method instead + | - help: try using a local generic parameter instead: `` LL | X | ^ use of generic parameter from outer function diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 81715621dd921..b0e2ef5b6f7e3 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bfnr, W: Fn()>(y: T) { - | --------------------------- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bfnr, W: Fn(), T>` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `T,` error[E0401]: can't use generic parameters from outer function --> $DIR/E0401.rs:9:16 @@ -15,7 +15,7 @@ LL | fn foo(x: T) { | - type parameter from outer function ... LL | fn baz Struct { | - type parameter from outer function LL | const CONST: fn() = || { LL | struct _Obligation where T:; - | ^ use of generic parameter from outer function - | - = help: try using a local generic parameter instead + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr index 4d8eb6360e640..aa0b5ce64b421 100644 --- a/src/test/ui/issues/issue-3214.stderr +++ b/src/test/ui/issues/issue-3214.stderr @@ -2,10 +2,9 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3214.rs:3:12 | LL | fn foo() { - | --- - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | struct Foo { + | - help: try using a local generic parameter instead: `` LL | x: T, | ^ use of generic parameter from outer function diff --git a/src/test/ui/issues/issue-5997-enum.stderr b/src/test/ui/issues/issue-5997-enum.stderr index 1c58b9c391104..3a79215d3ae9c 100644 --- a/src/test/ui/issues/issue-5997-enum.stderr +++ b/src/test/ui/issues/issue-5997-enum.stderr @@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-enum.rs:2:16 | LL | fn f() -> bool { - | - - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | enum E { V(Z) } - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5997-struct.stderr b/src/test/ui/issues/issue-5997-struct.stderr index 5b388d16d7553..d2e97f767719f 100644 --- a/src/test/ui/issues/issue-5997-struct.stderr +++ b/src/test/ui/issues/issue-5997-struct.stderr @@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-struct.rs:2:14 | LL | fn f() -> bool { - | - - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | struct S(T); - | ^ use of generic parameter from outer function + | -^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/nested-ty-params.stderr b/src/test/ui/nested-ty-params.stderr index f6741b5e5e82a..8f4746f5ec3bd 100644 --- a/src/test/ui/nested-ty-params.stderr +++ b/src/test/ui/nested-ty-params.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn hd(v: Vec ) -> U { | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `hd1` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error[E0401]: can't use generic parameters from outer function --> $DIR/nested-ty-params.rs:3:23 @@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn hd(v: Vec ) -> U { | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `hd1` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/bad-type-env-capture.stderr b/src/test/ui/resolve/bad-type-env-capture.stderr index 6f24c0d86997e..b6282c2d0703b 100644 --- a/src/test/ui/resolve/bad-type-env-capture.stderr +++ b/src/test/ui/resolve/bad-type-env-capture.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo() { | - type parameter from outer function LL | fn bar(b: T) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-3021-c.stderr b/src/test/ui/resolve/issue-3021-c.stderr index 8764ac8a8563c..5176efc3a6be7 100644 --- a/src/test/ui/resolve/issue-3021-c.stderr +++ b/src/test/ui/resolve/issue-3021-c.stderr @@ -3,22 +3,22 @@ error[E0401]: can't use generic parameters from outer function | LL | fn siphash() { | - type parameter from outer function -... +LL | +LL | trait U { + | - help: try using a local generic parameter instead: `` LL | fn g(&self, x: T) -> T; - | - ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `g` + | ^ use of generic parameter from outer function error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3021-c.rs:4:30 | LL | fn siphash() { | - type parameter from outer function -... +LL | +LL | trait U { + | - help: try using a local generic parameter instead: `` LL | fn g(&self, x: T) -> T; - | - ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `g` + | ^ use of generic parameter from outer function error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr index 10a703ee09351..0a6d1cc3bcd45 100644 --- a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr +++ b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr @@ -4,8 +4,8 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitA { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | enum Foo { + | - help: try using a local generic parameter instead: `A,` LL | Variance(A) | ^ use of generic parameter from outer function @@ -15,9 +15,10 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitB { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | struct Foo(A); - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:23:28 @@ -25,9 +26,10 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitC { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | struct Foo { a: A } - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:30:22 @@ -36,9 +38,9 @@ LL | trait TraitD { | - type parameter from outer function LL | fn outer(&self) { LL | fn foo(a: A) { } - | ------ ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `foo` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error: aborting due to 4 previous errors diff --git a/src/test/ui/structs/struct-record-suggestion.fixed b/src/test/ui/structs/struct-record-suggestion.fixed index 48144cd1ce2d1..49e38b196deb2 100644 --- a/src/test/ui/structs/struct-record-suggestion.fixed +++ b/src/test/ui/structs/struct-record-suggestion.fixed @@ -6,11 +6,29 @@ struct A { d: usize, } -fn main() { - let q = A { c: 5, .. Default::default() }; +fn a() { + let q = A { c: 5,..Default::default() }; //~^ ERROR mismatched types //~| ERROR missing fields //~| HELP separate the last named field with a comma - let r = A { c: 5, .. Default::default() }; + let r = A { c: 5, ..Default::default() }; assert_eq!(q, r); } + +#[derive(Debug, Default, Eq, PartialEq)] +struct B { + b: u32, +} + +fn b() { + let q = B { b: 1,..Default::default() }; + //~^ ERROR mismatched types + //~| HELP separate the last named field with a comma + let r = B { b: 1 }; + assert_eq!(q, r); +} + +fn main() { + a(); + b(); +} diff --git a/src/test/ui/structs/struct-record-suggestion.rs b/src/test/ui/structs/struct-record-suggestion.rs index 6d169d5c6dbfd..901f310c8bdb2 100644 --- a/src/test/ui/structs/struct-record-suggestion.rs +++ b/src/test/ui/structs/struct-record-suggestion.rs @@ -6,11 +6,29 @@ struct A { d: usize, } -fn main() { - let q = A { c: 5 .. Default::default() }; +fn a() { + let q = A { c: 5..Default::default() }; //~^ ERROR mismatched types //~| ERROR missing fields //~| HELP separate the last named field with a comma - let r = A { c: 5, .. Default::default() }; + let r = A { c: 5, ..Default::default() }; assert_eq!(q, r); } + +#[derive(Debug, Default, Eq, PartialEq)] +struct B { + b: u32, +} + +fn b() { + let q = B { b: 1..Default::default() }; + //~^ ERROR mismatched types + //~| HELP separate the last named field with a comma + let r = B { b: 1 }; + assert_eq!(q, r); +} + +fn main() { + a(); + b(); +} diff --git a/src/test/ui/structs/struct-record-suggestion.stderr b/src/test/ui/structs/struct-record-suggestion.stderr index e5bd03117b9fe..66e9f021ed68f 100644 --- a/src/test/ui/structs/struct-record-suggestion.stderr +++ b/src/test/ui/structs/struct-record-suggestion.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types --> $DIR/struct-record-suggestion.rs:10:20 | -LL | let q = A { c: 5 .. Default::default() }; - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range` +LL | let q = A { c: 5..Default::default() }; + | ^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range` | = note: expected type `u64` found struct `std::ops::Range<{integer}>` @@ -10,15 +10,28 @@ LL | let q = A { c: 5 .. Default::default() }; error[E0063]: missing fields `b` and `d` in initializer of `A` --> $DIR/struct-record-suggestion.rs:10:13 | -LL | let q = A { c: 5 .. Default::default() }; +LL | let q = A { c: 5..Default::default() }; | ^ missing `b` and `d` | help: to set the remaining fields from `Default::default()`, separate the last named field with a comma | -LL | let q = A { c: 5, .. Default::default() }; +LL | let q = A { c: 5,..Default::default() }; | + -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/struct-record-suggestion.rs:24:20 + | +LL | let q = B { b: 1..Default::default() }; + | ^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `std::ops::Range` + | + = note: expected type `u32` + found struct `std::ops::Range<{integer}>` +help: to set the remaining fields from `Default::default()`, separate the last named field with a comma + | +LL | let q = B { b: 1,..Default::default() }; + | + + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0063, E0308. For more information about an error, try `rustc --explain E0063`. diff --git a/src/test/ui/type/type-arg-out-of-scope.stderr b/src/test/ui/type/type-arg-out-of-scope.stderr index 0b6283fbc51e9..7f18b4510f4b2 100644 --- a/src/test/ui/type/type-arg-out-of-scope.stderr +++ b/src/test/ui/type/type-arg-out-of-scope.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error[E0401]: can't use generic parameters from outer function --> $DIR/type-arg-out-of-scope.rs:3:35 @@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 582782f245fcc..e32ef9933afe5 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -290,7 +290,7 @@ impl<'a> NormalizedPat<'a> { LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val), LitKind::Bool(val) => Self::LitBool(val), - LitKind::Float(..) | LitKind::Err(_) => Self::Wild, + LitKind::Float(..) | LitKind::Err => Self::Wild, }, _ => Self::Wild, }, diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index c0726868f77e2..429c64ac15641 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -276,7 +276,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match lit.value.node { LitKind::Bool(val) => kind!("Bool({val:?})"), LitKind::Char(c) => kind!("Char({c:?})"), - LitKind::Err(val) => kind!("Err({val})"), + LitKind::Err => kind!("Err"), LitKind::Byte(b) => kind!("Byte({b})"), LitKind::Int(i, suffix) => { let int_ty = match suffix { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 351a3f4aec8c8..e053708edd507 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -45,7 +45,7 @@ pub enum Constant { /// A reference Ref(Box), /// A literal with syntax error. - Err(Symbol), + Err, } impl PartialEq for Constant { @@ -118,9 +118,7 @@ impl Hash for Constant { Self::Ref(ref r) => { r.hash(state); }, - Self::Err(ref s) => { - s.hash(state); - }, + Self::Err => {}, } } } @@ -194,7 +192,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option>) -> Constant { _ => bug!(), }, LitKind::Bool(b) => Constant::Bool(b), - LitKind::Err(s) => Constant::Err(s), + LitKind::Err => Constant::Err, } }