diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b7da276fc7e1d..4233f7806248b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1542,10 +1542,10 @@ pub enum MacArgs { } impl MacArgs { - pub fn delim(&self) -> DelimToken { + pub fn delim(&self) -> Option { match self { - MacArgs::Delimited(_, delim, _) => delim.to_token(), - MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim, + MacArgs::Delimited(_, delim, _) => Some(delim.to_token()), + MacArgs::Empty | MacArgs::Eq(..) => None, } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3c9bb81bedb1c..39824095e8663 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -464,7 +464,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere Some(MacHeader::Path(&item.path)), false, None, - delim.to_token(), + Some(delim.to_token()), tokens, true, span, @@ -530,7 +530,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere None, false, None, - *delim, + Some(*delim), tts, convert_dollar_crate, dspan.entire(), @@ -556,12 +556,12 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere header: Option>, has_bang: bool, ident: Option, - delim: DelimToken, + delim: Option, tts: &TokenStream, convert_dollar_crate: bool, span: Span, ) { - if delim == DelimToken::Brace { + if delim == Some(DelimToken::Brace) { self.cbox(INDENT_UNIT); } match header { @@ -577,7 +577,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.print_ident(ident); } match delim { - DelimToken::Brace => { + Some(DelimToken::Brace) => { if header.is_some() || has_bang || ident.is_some() { self.nbsp(); } @@ -585,23 +585,25 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere if !tts.is_empty() { self.space(); } - } - _ => { - let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); - self.word(token_str) - } - } - self.ibox(0); - self.print_tts(tts, convert_dollar_crate); - self.end(); - match delim { - DelimToken::Brace => { + self.ibox(0); + self.print_tts(tts, convert_dollar_crate); + self.end(); let empty = tts.is_empty(); self.bclose(span, empty); } - _ => { + Some(delim) => { + let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); + self.word(token_str); + self.ibox(0); + self.print_tts(tts, convert_dollar_crate); + self.end(); let token_str = self.token_kind_to_string(&token::CloseDelim(delim)); - self.word(token_str) + self.word(token_str); + } + None => { + self.ibox(0); + self.print_tts(tts, convert_dollar_crate); + self.end(); } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 76caa3ceaafae..99e4ded62f1a7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -20,7 +20,6 @@ pub fn compute_mir_scopes<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, mir: &Body<'tcx>, - fn_dbg_scope: &'ll DIScope, debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, ) { // Find all scopes with variables defined in them. @@ -38,40 +37,41 @@ pub fn compute_mir_scopes<'ll, 'tcx>( // Nothing to emit, of course. None }; - + let mut instantiated = BitSet::new_empty(mir.source_scopes.len()); // Instantiate all scopes. for idx in 0..mir.source_scopes.len() { let scope = SourceScope::new(idx); - make_mir_scope(cx, instance, mir, fn_dbg_scope, &variables, debug_context, scope); + make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope); } + assert!(instantiated.count() == mir.source_scopes.len()); } fn make_mir_scope<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, mir: &Body<'tcx>, - fn_dbg_scope: &'ll DIScope, variables: &Option>, debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, + instantiated: &mut BitSet, scope: SourceScope, ) { - if debug_context.scopes[scope].dbg_scope.is_some() { + if instantiated.contains(scope) { return; } let scope_data = &mir.source_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { - make_mir_scope(cx, instance, mir, fn_dbg_scope, variables, debug_context, parent); + make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent); debug_context.scopes[parent] } else { // The root is the function itself. let loc = cx.lookup_debug_loc(mir.span.lo()); debug_context.scopes[scope] = DebugScope { - dbg_scope: Some(fn_dbg_scope), - inlined_at: None, file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_pos, + ..debug_context.scopes[scope] }; + instantiated.insert(scope); return; }; @@ -79,6 +79,7 @@ fn make_mir_scope<'ll, 'tcx>( // Do not create a DIScope if there are no variables defined in this // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. debug_context.scopes[scope] = parent_scope; + instantiated.insert(scope); return; } @@ -100,7 +101,7 @@ fn make_mir_scope<'ll, 'tcx>( None => unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(cx), - parent_scope.dbg_scope.unwrap(), + parent_scope.dbg_scope, file_metadata, loc.line, loc.col, @@ -116,9 +117,10 @@ fn make_mir_scope<'ll, 'tcx>( }); debug_context.scopes[scope] = DebugScope { - dbg_scope: Some(dbg_scope), + dbg_scope, inlined_at: inlined_at.or(parent_scope.inlined_at), file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_pos, }; + instantiated.insert(scope); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 4e6d3f88e6719..6a164557a4719 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -286,9 +286,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { } // Initialize fn debug context (including scopes). - // FIXME(eddyb) figure out a way to not need `Option` for `dbg_scope`. let empty_scope = DebugScope { - dbg_scope: None, + dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)), inlined_at: None, file_start_pos: BytePos(0), file_end_pos: BytePos(0), @@ -297,13 +296,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) }; // Fill in all the scopes, with the information from the MIR body. - compute_mir_scopes( - self, - instance, - mir, - self.dbg_scope_fn(instance, fn_abi, Some(llfn)), - &mut fn_debug_context, - ); + compute_mir_scopes(self, instance, mir, &mut fn_debug_context); Some(fn_debug_context) } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index bb53c722a244a..f2d1827c792db 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -39,8 +39,7 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { #[derive(Clone, Copy, Debug)] pub struct DebugScope { - // FIXME(eddyb) this should never be `None`, after initialization. - pub dbg_scope: Option, + pub dbg_scope: S, /// Call site location, if this scope was inlined from another function. pub inlined_at: Option, @@ -61,17 +60,12 @@ impl<'tcx, S: Copy, L: Copy> DebugScope { cx: &Cx, span: Span, ) -> S { - // FIXME(eddyb) this should never be `None`. - let dbg_scope = self - .dbg_scope - .unwrap_or_else(|| bug!("`dbg_scope` is only `None` during initialization")); - let pos = span.lo(); if pos < self.file_start_pos || pos >= self.file_end_pos { let sm = cx.sess().source_map(); - cx.extend_scope_to_file(dbg_scope, &sm.lookup_char_pos(pos).file) + cx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file) } else { - dbg_scope + self.dbg_scope } } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 47cdf39cd52ce..5dd743e8d0023 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -212,7 +212,12 @@ pub trait Emitter { fn emit_future_breakage_report(&mut self, _diags: Vec) {} /// Emit list of unused externs - fn emit_unused_externs(&mut self, _lint_level: &str, _unused_externs: &[&str]) {} + fn emit_unused_externs( + &mut self, + _lint_level: rustc_lint_defs::Level, + _unused_externs: &[&str], + ) { + } /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index d680e7fab7047..6ff52182d6b03 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -171,7 +171,8 @@ impl Emitter for JsonEmitter { } } - fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) { + fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) { + let lint_level = lint_level.as_str(); let data = UnusedExterns { lint_level, unused_extern_names: unused_externs }; let result = if self.pretty { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4e6ab0edf6666..a64133bb7f4f9 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -969,8 +969,19 @@ impl Handler { self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) } - pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) { - self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs) + pub fn emit_unused_externs( + &self, + lint_level: rustc_lint_defs::Level, + loud: bool, + unused_externs: &[&str], + ) { + let mut inner = self.inner.borrow_mut(); + + if loud && lint_level.is_error() { + inner.bump_err_count(); + } + + inner.emit_unused_externs(lint_level, unused_externs) } pub fn update_unstable_expectation_id( @@ -1141,7 +1152,7 @@ impl HandlerInner { self.emitter.emit_artifact_notification(path, artifact_type); } - fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) { + fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) { self.emitter.emit_unused_externs(lint_level, unused_externs); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 2cfd6968accf7..f3dcdbf93c5f1 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -260,16 +260,15 @@ fn generic_extension<'cx, 'tt>( // Merge the gated spans from parsing the matcher with the pre-existing ones. sess.gated_spans.merge(gated_spans_snapshot); - // Ignore the delimiters on the RHS. - let rhs = match &rhses[i] { - mbe::TokenTree::Delimited(_, delimited) => &delimited.tts, + let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] { + mbe::TokenTree::Delimited(span, delimited) => (&delimited, *span), _ => cx.span_bug(sp, "malformed macro rhs"), }; let arm_span = rhses[i].span(); - let rhs_spans = rhs.iter().map(|t| t.span()).collect::>(); + let rhs_spans = rhs.tts.iter().map(|t| t.span()).collect::>(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = match transcribe(cx, &named_matches, &rhs, transparency) { + let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) { Ok(tts) => tts, Err(mut err) => { err.emit(); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index d25f044234cf4..d5b1913e1440c 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -29,8 +29,8 @@ impl MutVisitor for Marker { enum Frame<'a> { Delimited { tts: &'a [mbe::TokenTree], - delim_token: token::DelimToken, idx: usize, + delim_token: token::DelimToken, span: DelimSpan, }, Sequence { @@ -42,8 +42,8 @@ enum Frame<'a> { impl<'a> Frame<'a> { /// Construct a new frame around the delimited set of tokens. - fn new(tts: &'a [mbe::TokenTree]) -> Frame<'a> { - Frame::Delimited { tts, delim_token: token::NoDelim, idx: 0, span: DelimSpan::dummy() } + fn new(src: &'a mbe::Delimited, span: DelimSpan) -> Frame<'a> { + Frame::Delimited { tts: &src.tts, idx: 0, delim_token: src.delim, span } } } @@ -85,17 +85,18 @@ impl<'a> Iterator for Frame<'a> { pub(super) fn transcribe<'a>( cx: &ExtCtxt<'a>, interp: &FxHashMap, - src: &[mbe::TokenTree], + src: &mbe::Delimited, + src_span: DelimSpan, transparency: Transparency, ) -> PResult<'a, TokenStream> { // Nothing for us to transcribe... - if src.is_empty() { + if src.tts.is_empty() { return Ok(TokenStream::default()); } // We descend into the RHS (`src`), expanding things as we go. This stack contains the things // we have yet to expand/are still expanding. We start the stack off with the whole RHS. - let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new(&src)]; + let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new(&src, src_span)]; // As we descend in the RHS, we will need to be able to match nested sequences of matchers. // `repeats` keeps track of where we are in matching at each level, with the last element being diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index f590172af4f9c..57b4f96dc100d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -214,6 +214,13 @@ impl Level { _ => None, } } + + pub fn is_error(self) -> bool { + match self { + Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn => false, + Level::Deny | Level::Forbid => true, + } + } } /// Specification of a single lint. diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e8cdae7fd25ce..3c545e6a0d240 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -195,10 +195,12 @@ impl CStore { } pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { + let json_unused_externs = tcx.sess.opts.json_unused_externs; + // We put the check for the option before the lint_level_at_node call // because the call mutates internal state and introducing it // leads to some ui tests failing. - if !tcx.sess.opts.json_unused_externs { + if !json_unused_externs.is_enabled() { return; } let level = tcx @@ -208,10 +210,11 @@ impl CStore { let unused_externs = self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::>(); let unused_externs = unused_externs.iter().map(String::as_str).collect::>(); - tcx.sess - .parse_sess - .span_diagnostic - .emit_unused_externs(level.as_str(), &unused_externs); + tcx.sess.parse_sess.span_diagnostic.emit_unused_externs( + level, + json_unused_externs.is_loud(), + &unused_externs, + ); } } } @@ -917,7 +920,7 @@ impl<'a> CrateLoader<'a> { } // Got a real unused --extern - if self.sess.opts.json_unused_externs { + if self.sess.opts.json_unused_externs.is_enabled() { self.cstore.unused_externs.push(name_interned); continue; } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 3b044b19259d0..8c8a2650fd657 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,8 +3,8 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::TyKind::*; use crate::ty::{ - ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy, - ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, + ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, + InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, }; use rustc_data_structures::fx::FxHashMap; @@ -74,10 +74,10 @@ impl<'tcx> Ty<'tcx> { } /// Whether the type can be safely suggested during error recovery. - pub fn is_suggestable(self) -> bool { - fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool { + pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { + fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool { match arg.unpack() { - GenericArgKind::Type(ty) => ty.is_suggestable(), + GenericArgKind::Type(ty) => ty.is_suggestable(tcx), GenericArgKind::Const(c) => const_is_suggestable(c.val()), _ => true, } @@ -99,8 +99,7 @@ impl<'tcx> Ty<'tcx> { // temporary, so I'll leave this as a fixme. match self.kind() { - Opaque(..) - | FnDef(..) + FnDef(..) | Closure(..) | Infer(..) | Generator(..) @@ -108,27 +107,38 @@ impl<'tcx> Ty<'tcx> { | Bound(_, _) | Placeholder(_) | Error(_) => false, + Opaque(did, substs) => { + let parent = tcx.parent(*did).expect("opaque types always have a parent"); + if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent) + && let Opaque(parent_did, _) = tcx.type_of(parent).kind() + && parent_did == did + { + substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) + } else { + false + } + } Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() { ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => { - substs.iter().all(generic_arg_is_suggestible) + substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) } ExistentialPredicate::Projection(ExistentialProjection { substs, term, .. }) => { let term_is_suggestable = match term { - Term::Ty(ty) => ty.is_suggestable(), + Term::Ty(ty) => ty.is_suggestable(tcx), Term::Const(c) => const_is_suggestable(c.val()), }; - term_is_suggestable && substs.iter().all(generic_arg_is_suggestible) + term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) } _ => true, }), Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => { - args.iter().all(generic_arg_is_suggestible) + args.iter().all(|a| generic_arg_is_suggestible(a, tcx)) } - Tuple(args) => args.iter().all(|ty| ty.is_suggestable()), - Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(), - Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()), + Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)), + Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx), + Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()), _ => true, } } diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 02749088c3139..575b01180df77 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -5,7 +5,7 @@ use rustc_ast::tokenstream::{AttrAnnotatedTokenTree, DelimSpan, LazyTokenStream, use rustc_ast::{self as ast}; use rustc_ast::{AstLike, AttrVec, Attribute}; use rustc_errors::PResult; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{sym, Span}; use std::convert::TryInto; use std::ops::Range; @@ -400,24 +400,26 @@ fn make_token_stream( ) -> AttrAnnotatedTokenStream { #[derive(Debug)] struct FrameData { - open: Span, - open_delim: DelimToken, + // This is `None` for the first frame, `Some` for all others. + open_delim_sp: Option<(DelimToken, Span)>, inner: Vec<(AttrAnnotatedTokenTree, Spacing)>, } - let mut stack = - vec![FrameData { open: DUMMY_SP, open_delim: DelimToken::NoDelim, inner: vec![] }]; + let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }]; let mut token_and_spacing = iter.next(); while let Some((token, spacing)) = token_and_spacing { match token { FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => { - stack.push(FrameData { open: span, open_delim: delim, inner: vec![] }); + stack.push(FrameData { open_delim_sp: Some((delim, span)), inner: vec![] }); } FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => { // HACK: If we encounter a mismatched `None` delimiter at the top // level, just ignore it. if matches!(delim, DelimToken::NoDelim) && (stack.len() == 1 - || !matches!(stack.last_mut().unwrap().open_delim, DelimToken::NoDelim)) + || !matches!( + stack.last_mut().unwrap().open_delim_sp.unwrap().0, + DelimToken::NoDelim + )) { token_and_spacing = iter.next(); continue; @@ -430,7 +432,7 @@ fn make_token_stream( // merge our current frame with the one above it. That is, transform // `[ { < first second } third ]` into `[ { first second } third ]` if !matches!(delim, DelimToken::NoDelim) - && matches!(frame_data.open_delim, DelimToken::NoDelim) + && matches!(frame_data.open_delim_sp.unwrap().0, DelimToken::NoDelim) { stack.last_mut().unwrap().inner.extend(frame_data.inner); // Process our closing delimiter again, this time at the previous @@ -439,12 +441,13 @@ fn make_token_stream( continue; } + let (open_delim, open_sp) = frame_data.open_delim_sp.unwrap(); assert_eq!( - frame_data.open_delim, delim, + open_delim, delim, "Mismatched open/close delims: open={:?} close={:?}", - frame_data.open, span + open_delim, span ); - let dspan = DelimSpan::from_pair(frame_data.open, span); + let dspan = DelimSpan::from_pair(open_sp, span); let stream = AttrAnnotatedTokenStream::new(frame_data.inner); let delimited = AttrAnnotatedTokenTree::Delimited(dspan, delim, stream); stack @@ -472,7 +475,7 @@ fn make_token_stream( // HACK: If we don't have a closing `None` delimiter for our last // frame, merge the frame with the top-level frame. That is, // turn `< first second` into `first second` - if stack.len() == 2 && stack[1].open_delim == DelimToken::NoDelim { + if stack.len() == 2 && stack[1].open_delim_sp.unwrap().0 == DelimToken::NoDelim { let temp_buf = stack.pop().unwrap(); stack.last_mut().unwrap().inner.extend(temp_buf.inner); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7efc0ca2da234..e4370809ebc24 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2043,7 +2043,8 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::async_closure, span); } - if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren + if self.token.kind == TokenKind::Semi + && matches!(self.token_cursor.frame.delim_sp, Some((DelimToken::Paren, _))) { // It is likely that the closure body is a block but where the // braces have been removed. We will recover and eat the next diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 1686c5873e183..dfe758d0cdf01 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -244,14 +244,13 @@ struct TokenCursor { #[derive(Clone)] struct TokenCursorFrame { - delim: token::DelimToken, - span: DelimSpan, + delim_sp: Option<(DelimToken, DelimSpan)>, tree_cursor: tokenstream::Cursor, } impl TokenCursorFrame { - fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self { - TokenCursorFrame { delim, span, tree_cursor: tts.into_trees() } + fn new(delim_sp: Option<(DelimToken, DelimSpan)>, tts: TokenStream) -> Self { + TokenCursorFrame { delim_sp, tree_cursor: tts.into_trees() } } } @@ -266,7 +265,7 @@ impl TokenCursor { loop { // FIXME: we currently don't return `NoDelim` open/close delims. To fix #67062 we will // need to, whereupon the `delim != DelimToken::NoDelim` conditions below can be - // removed, as well as the loop. + // removed. if let Some((tree, spacing)) = self.frame.tree_cursor.next_with_spacing_ref() { match tree { &TokenTree::Token(ref token) => match (desugar_doc_comments, token) { @@ -277,7 +276,7 @@ impl TokenCursor { }, &TokenTree::Delimited(sp, delim, ref tts) => { // Set `open_delim` to true here because we deal with it immediately. - let frame = TokenCursorFrame::new(sp, delim, tts.clone()); + let frame = TokenCursorFrame::new(Some((delim, sp)), tts.clone()); self.stack.push(mem::replace(&mut self.frame, frame)); if delim != DelimToken::NoDelim { return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone); @@ -286,12 +285,11 @@ impl TokenCursor { } }; } else if let Some(frame) = self.stack.pop() { - let delim = self.frame.delim; - let span = self.frame.span; - self.frame = frame; - if delim != DelimToken::NoDelim { + if let Some((delim, span)) = self.frame.delim_sp && delim != DelimToken::NoDelim { + self.frame = frame; return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone); } + self.frame = frame; // No close delimiter to return; continue on to the next iteration. } else { return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone); @@ -330,8 +328,7 @@ impl TokenCursor { self.stack.push(mem::replace( &mut self.frame, TokenCursorFrame::new( - delim_span, - token::NoDelim, + None, if attr_style == AttrStyle::Inner { [TokenTree::token(token::Pound, span), TokenTree::token(token::Not, span), body] .iter() @@ -431,10 +428,6 @@ impl<'a> Parser<'a> { desugar_doc_comments: bool, subparser_name: Option<&'static str>, ) -> Self { - // Note: because of the way `TokenCursor::inlined_next` is structured, the `span` and - // `delim` arguments here are never used. - let start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens); - let mut parser = Parser { sess, token: Token::dummy(), @@ -444,7 +437,7 @@ impl<'a> Parser<'a> { restrictions: Restrictions::empty(), expected_tokens: Vec::new(), token_cursor: TokenCursor { - frame: start_frame, + frame: TokenCursorFrame::new(None, tokens), stack: Vec::new(), num_next_calls: 0, desugar_doc_comments, @@ -1025,7 +1018,7 @@ impl<'a> Parser<'a> { } let frame = &self.token_cursor.frame; - if frame.delim != DelimToken::NoDelim { + if let Some((delim, span)) = frame.delim_sp && delim != DelimToken::NoDelim { let all_normal = (0..dist).all(|i| { let token = frame.tree_cursor.look_ahead(i); !matches!(token, Some(TokenTree::Delimited(_, DelimToken::NoDelim, _))) @@ -1038,7 +1031,7 @@ impl<'a> Parser<'a> { looker(&Token::new(token::OpenDelim(*delim), dspan.open)) } }, - None => looker(&Token::new(token::CloseDelim(frame.delim), frame.span.close)), + None => looker(&Token::new(token::CloseDelim(delim), span.close)), }; } } @@ -1198,8 +1191,7 @@ impl<'a> Parser<'a> { // Grab the tokens from this frame. let frame = &self.token_cursor.frame; let stream = frame.tree_cursor.stream.clone(); - let span = frame.span; - let delim = frame.delim; + let (delim, span) = frame.delim_sp.unwrap(); // Advance the token cursor through the entire delimited // sequence. After getting the `OpenDelim` we are *within* the diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 5b7ae5f7a7b82..14f1208b71f51 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -164,25 +164,29 @@ impl<'a> Parser<'a> { let delim = args.delim(); let hi = self.prev_token.span; - let style = - if delim == token::Brace { MacStmtStyle::Braces } else { MacStmtStyle::NoBraces }; + let style = match delim { + Some(token::Brace) => MacStmtStyle::Braces, + Some(_) => MacStmtStyle::NoBraces, + None => unreachable!(), + }; let mac = MacCall { path, args, prior_type_ascription: self.last_type_ascription }; - let kind = - if (delim == token::Brace && self.token != token::Dot && self.token != token::Question) - || self.token == token::Semi - || self.token == token::Eof - { - StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) - } else { - // Since none of the above applied, this is an expression statement macro. - let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); - let e = self.maybe_recover_from_bad_qpath(e, true)?; - let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; - StmtKind::Expr(e) - }; + let kind = if (style == MacStmtStyle::Braces + && self.token != token::Dot + && self.token != token::Question) + || self.token == token::Semi + || self.token == token::Eof + { + StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) + } else { + // Since none of the above applied, this is an expression statement macro. + let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); + let e = self.maybe_recover_from_bad_qpath(e, true)?; + let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + StmtKind::Expr(e) + }; Ok(self.mk_stmt(lo.to(hi), kind)) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 925f6bfd93d3c..5851ed43a0e71 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -757,7 +757,7 @@ impl Default for Options { real_rust_source_base_dir: None, edition: DEFAULT_EDITION, json_artifact_notifications: false, - json_unused_externs: false, + json_unused_externs: JsonUnusedExterns::No, json_future_incompat: false, pretty: None, working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()), @@ -1493,10 +1493,37 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { pub struct JsonConfig { pub json_rendered: HumanReadableErrorType, pub json_artifact_notifications: bool, - pub json_unused_externs: bool, + pub json_unused_externs: JsonUnusedExterns, pub json_future_incompat: bool, } +/// Report unused externs in event stream +#[derive(Copy, Clone)] +pub enum JsonUnusedExterns { + /// Do not + No, + /// Report, but do not exit with failure status for deny/forbid + Silent, + /// Report, and also exit with failure status for deny/forbid + Loud, +} + +impl JsonUnusedExterns { + pub fn is_enabled(&self) -> bool { + match self { + JsonUnusedExterns::No => false, + JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true, + } + } + + pub fn is_loud(&self) -> bool { + match self { + JsonUnusedExterns::No | JsonUnusedExterns::Silent => false, + JsonUnusedExterns::Loud => true, + } + } +} + /// Parse the `--json` flag. /// /// The first value returned is how to render JSON diagnostics, and the second @@ -1506,7 +1533,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { HumanReadableErrorType::Default; let mut json_color = ColorConfig::Never; let mut json_artifact_notifications = false; - let mut json_unused_externs = false; + let mut json_unused_externs = JsonUnusedExterns::No; let mut json_future_incompat = false; for option in matches.opt_strs("json") { // For now conservatively forbid `--color` with `--json` since `--json` @@ -1524,7 +1551,8 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { "diagnostic-short" => json_rendered = HumanReadableErrorType::Short, "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, "artifacts" => json_artifact_notifications = true, - "unused-externs" => json_unused_externs = true, + "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud, + "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent, "future-incompat" => json_future_incompat = true, s => early_error( ErrorOutputType::default(), @@ -2224,7 +2252,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { check_debug_option_stability(&debugging_opts, error_format, json_rendered); - if !debugging_opts.unstable_options && json_unused_externs { + if !debugging_opts.unstable_options && json_unused_externs.is_enabled() { early_error( error_format, "the `-Z unstable-options` flag must also be passed to enable \ diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 96f50e57ac4d0..14e918660dd39 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -221,7 +221,7 @@ top_level_options!( json_artifact_notifications: bool [TRACKED], /// `true` if we're emitting a JSON blob containing the unused externs - json_unused_externs: bool [UNTRACKED], + json_unused_externs: JsonUnusedExterns [UNTRACKED], /// `true` if we're emitting a JSON job containing a future-incompat report for lints json_future_incompat: bool [TRACKED], diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 5f5b81b892475..794e711b6c831 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_type = tcx.infer_ctxt().enter(|infcx| { infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id)) }); - if param_type.is_suggestable() { + if param_type.is_suggestable(tcx) { err.span_suggestion( tcx.def_span(src_def_id), "consider changing this type parameter to be a `const` generic", diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 1caf93e5fe055..3e36ffa7fe0d2 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2466,7 +2466,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, ty, opt_sugg: Some((span, Applicability::MachineApplicable)) - .filter(|_| ty.is_suggestable()), + .filter(|_| ty.is_suggestable(tcx)), }); ty diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 62518408b8b30..8db9da7fcb23a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -525,7 +525,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); // Only suggest changing the return type for methods that // haven't set a return type at all (and aren't `fn main()` or an impl). - match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { + match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) { (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { err.span_suggestion( span, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index be77bdb0bf5f0..0ccc2b6b182c4 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -41,7 +41,7 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt}; -use rustc_middle::ty::{ReprOptions, ToPredicate, TypeFoldable}; +use rustc_middle::ty::{ReprOptions, ToPredicate}; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -2004,28 +2004,29 @@ fn infer_return_ty_for_fn_sig<'tcx>( visitor.visit_ty(ty); let mut diag = bad_placeholder(tcx, visitor.0, "return type"); let ret_ty = fn_sig.skip_binder().output(); - if !ret_ty.references_error() { - if !ret_ty.is_closure() { - let ret_ty_str = match ret_ty.kind() { - // Suggest a function pointer return type instead of a unique function definition - // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid - // syntax) - ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(), - _ => ret_ty.to_string(), - }; + if ret_ty.is_suggestable(tcx) { + diag.span_suggestion( + ty.span, + "replace with the correct return type", + ret_ty.to_string(), + Applicability::MachineApplicable, + ); + } else if matches!(ret_ty.kind(), ty::FnDef(..)) { + let fn_sig = ret_ty.fn_sig(tcx); + if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) { diag.span_suggestion( ty.span, "replace with the correct return type", - ret_ty_str, - Applicability::MaybeIncorrect, + fn_sig.to_string(), + Applicability::MachineApplicable, ); - } else { - // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds - // to prevent the user from getting a papercut while trying to use the unique closure - // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`). - diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); - diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html"); } + } else if ret_ty.is_closure() { + // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds + // to prevent the user from getting a papercut while trying to use the unique closure + // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`). + diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); + diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html"); } diag.emit(); diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 10ef6662115c1..7d66973bed6f5 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -25,7 +25,7 @@ use crate::char; use crate::collections::TryReserveError; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::iter::FromIterator; +use crate::iter::{FromIterator, FusedIterator}; use crate::mem; use crate::ops; use crate::rc::Rc; @@ -899,6 +899,9 @@ impl<'a> Iterator for EncodeWide<'a> { } } +#[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] +impl FusedIterator for EncodeWide<'_> {} + impl Hash for CodePoint { #[inline] fn hash(&self, state: &mut H) { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index cee3dcb416f80..1ff2c8191e562 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -10,7 +10,9 @@ use rustc_session::config::{ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType, }; use rustc_session::config::{get_cmd_lint_options, nightly_options}; -use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; +use rustc_session::config::{ + CodegenOptions, DebuggingOptions, ErrorOutputType, Externs, JsonUnusedExterns, +}; use rustc_session::getopts; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -147,7 +149,7 @@ crate struct Options { /// documentation. crate run_check: bool, /// Whether doctests should emit unused externs - crate json_unused_externs: bool, + crate json_unused_externs: JsonUnusedExterns, /// Whether to skip capturing stdout and stderr of tests. crate nocapture: bool, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 45ac16e75aa37..82e367427ef6f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -168,7 +168,7 @@ crate fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { // Collect and warn about unused externs, but only if we've gotten // reports for each doctest - if json_unused_externs { + if json_unused_externs.is_enabled() { let unused_extern_reports: Vec<_> = std::mem::take(&mut unused_extern_reports.lock().unwrap()); if unused_extern_reports.len() == compiling_test_count { @@ -337,7 +337,7 @@ fn run_test( if lang_string.test_harness { compiler.arg("--test"); } - if rustdoc_options.json_unused_externs && !lang_string.compile_fail { + if rustdoc_options.json_unused_externs.is_enabled() && !lang_string.compile_fail { compiler.arg("--error-format=json"); compiler.arg("--json").arg("unused-externs"); compiler.arg("-Z").arg("unstable-options"); diff --git a/src/test/ui/unused-crate-deps/deny-attr.rs b/src/test/ui/unused-crate-deps/deny-attr.rs new file mode 100644 index 0000000000000..e9ab18ff63f39 --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-attr.rs @@ -0,0 +1,9 @@ +// Check for unused crate dep, no path + +// edition:2018 +// aux-crate:bar=bar.rs + +#![deny(unused_crate_dependencies)] +//~^ ERROR external crate `bar` unused in + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/deny-attr.stderr b/src/test/ui/unused-crate-deps/deny-attr.stderr new file mode 100644 index 0000000000000..93694f6827f9c --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-attr.stderr @@ -0,0 +1,14 @@ +error: external crate `bar` unused in `deny_attr`: remove the dependency or add `use bar as _;` + --> $DIR/deny-attr.rs:6:1 + | +LL | #![deny(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/deny-attr.rs:6:9 + | +LL | #![deny(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs new file mode 100644 index 0000000000000..fd9a61d6caa25 --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs @@ -0,0 +1,8 @@ +// Check for unused crate dep, json event, deny but we're not reporting that in exit status + +// edition:2018 +// check-pass +// compile-flags: -Dunused-crate-dependencies -Zunstable-options --json unused-externs-silent --error-format=json +// aux-crate:bar=bar.rs + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr new file mode 100644 index 0000000000000..595619f3a8a4e --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr @@ -0,0 +1 @@ +{"lint_level":"deny","unused_extern_names":["bar"]} diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json.rs b/src/test/ui/unused-crate-deps/deny-cmdline-json.rs new file mode 100644 index 0000000000000..2b369dee5a0db --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline-json.rs @@ -0,0 +1,7 @@ +// Check for unused crate dep, json event, deny, expect compile failure + +// edition:2018 +// compile-flags: -Dunused-crate-dependencies -Zunstable-options --json unused-externs --error-format=json +// aux-crate:bar=bar.rs + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json.stderr b/src/test/ui/unused-crate-deps/deny-cmdline-json.stderr new file mode 100644 index 0000000000000..595619f3a8a4e --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline-json.stderr @@ -0,0 +1 @@ +{"lint_level":"deny","unused_extern_names":["bar"]} diff --git a/src/test/ui/unused-crate-deps/deny-cmdline.rs b/src/test/ui/unused-crate-deps/deny-cmdline.rs new file mode 100644 index 0000000000000..69e28b3319a22 --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline.rs @@ -0,0 +1,8 @@ +// Check for unused crate dep, deny, expect failure + +// edition:2018 +// compile-flags: -Dunused-crate-dependencies +// aux-crate:bar=bar.rs + +fn main() {} +//~^ ERROR external crate `bar` unused in diff --git a/src/test/ui/unused-crate-deps/deny-cmdline.stderr b/src/test/ui/unused-crate-deps/deny-cmdline.stderr new file mode 100644 index 0000000000000..0951dc670fe9e --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline.stderr @@ -0,0 +1,10 @@ +error: external crate `bar` unused in `deny_cmdline`: remove the dependency or add `use bar as _;` + --> $DIR/deny-cmdline.rs:7:1 + | +LL | fn main() {} + | ^ + | + = note: requested on the command line with `-D unused-crate-dependencies` + +error: aborting due to previous error + diff --git a/src/test/ui/unused-crate-deps/warn-cmdline-json.rs b/src/test/ui/unused-crate-deps/warn-cmdline-json.rs new file mode 100644 index 0000000000000..4826c0062d0e5 --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-cmdline-json.rs @@ -0,0 +1,8 @@ +// Check for unused crate dep, warn, json event, expect pass + +// edition:2018 +// check-pass +// compile-flags: -Wunused-crate-dependencies -Zunstable-options --json unused-externs --error-format=json +// aux-crate:bar=bar.rs + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/warn-cmdline-json.stderr b/src/test/ui/unused-crate-deps/warn-cmdline-json.stderr new file mode 100644 index 0000000000000..98dbd763927e6 --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-cmdline-json.stderr @@ -0,0 +1 @@ +{"lint_level":"warn","unused_extern_names":["bar"]} diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index a5ff779a4abfb..10726b9842080 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -23,6 +23,14 @@ struct ArtifactNotification { artifact: PathBuf, } +#[derive(Deserialize)] +struct UnusedExternNotification { + #[allow(dead_code)] + lint_level: String, + #[allow(dead_code)] + unused_extern_names: Vec, +} + #[derive(Deserialize, Clone)] struct DiagnosticSpan { file_name: String, @@ -113,6 +121,9 @@ pub fn extract_rendered(output: &str) -> String { } else if serde_json::from_str::(line).is_ok() { // Ignore the notification. None + } else if serde_json::from_str::(line).is_ok() { + // Ignore the notification. + None } else { print!( "failed to decode compiler output as json: line: {}\noutput: {}", diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 4f333cd27cefe..cd724373f4d16 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1325,7 +1325,7 @@ pub(crate) fn can_be_overflowed_expr( } ast::ExprKind::MacCall(ref mac) => { match ( - rustc_ast::ast::MacDelimiter::from_token(mac.args.delim()), + rustc_ast::ast::MacDelimiter::from_token(mac.args.delim().unwrap()), context.config.overflow_delimited_expr(), ) { (Some(ast::MacDelimiter::Bracket), true) diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 664f152e8be1d..92606902c5789 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -562,7 +562,7 @@ fn delim_token_to_str( ("{ ", " }") } } - DelimToken::NoDelim => ("", ""), + DelimToken::NoDelim => unreachable!(), }; if use_multiple_lines { let indent_str = shape.indent.to_string_with_newline(context.config);