diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index d522c285e3ebe..d0e8b86b71d3b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1021,7 +1021,7 @@ impl Stmt { #[derive(Clone, Encodable, Decodable, Debug)] pub enum StmtKind { /// A local (let) binding. - Local(P), + Let(P), /// An item definition. Item(P), /// Expr without trailing semi-colon. diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 4dc9c30a2c807..a0486227f2afb 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -182,7 +182,7 @@ impl HasTokens for Option { impl HasTokens for StmtKind { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { - StmtKind::Local(local) => local.tokens.as_ref(), + StmtKind::Let(local) => local.tokens.as_ref(), StmtKind::Item(item) => item.tokens(), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(), StmtKind::Empty => return None, @@ -191,7 +191,7 @@ impl HasTokens for StmtKind { } fn tokens_mut(&mut self) -> Option<&mut Option> { match self { - StmtKind::Local(local) => Some(&mut local.tokens), + StmtKind::Let(local) => Some(&mut local.tokens), StmtKind::Item(item) => item.tokens_mut(), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(), StmtKind::Empty => return None, @@ -355,7 +355,7 @@ impl HasAttrs for StmtKind { fn attrs(&self) -> &[Attribute] { match self { - StmtKind::Local(local) => &local.attrs, + StmtKind::Let(local) => &local.attrs, StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(), StmtKind::Item(item) => item.attrs(), StmtKind::Empty => &[], @@ -365,7 +365,7 @@ impl HasAttrs for StmtKind { fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { match self { - StmtKind::Local(local) => f(&mut local.attrs), + StmtKind::Let(local) => f(&mut local.attrs), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), StmtKind::Item(item) => item.visit_attrs(f), StmtKind::Empty => {} diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 9ec92c9d4edfe..83468c5f10122 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1567,7 +1567,7 @@ pub fn noop_flat_map_stmt_kind( vis: &mut T, ) -> SmallVec<[StmtKind; 1]> { match kind { - StmtKind::Local(mut local) => smallvec![StmtKind::Local({ + StmtKind::Let(mut local) => smallvec![StmtKind::Let({ vis.visit_local(&mut local); local })], diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7296e29301f35..d75ff4565e6f0 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -787,7 +787,7 @@ pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::R pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result { match &statement.kind { - StmtKind::Local(local) => try_visit!(visitor.visit_local(local)), + StmtKind::Let(local) => try_visit!(visitor.visit_local(local)), StmtKind::Item(item) => try_visit!(visitor.visit_item(item)), StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)), StmtKind::Empty => {} diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 865a56b2c1f15..11a66fe87c9a6 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -32,11 +32,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut expr = None; while let [s, tail @ ..] = ast_stmts { match &s.kind { - StmtKind::Local(local) => { + StmtKind::Let(local) => { let hir_id = self.lower_node_id(s.id); let local = self.lower_local(local); self.alias_attrs(hir_id, local.hir_id); - let kind = hir::StmtKind::Local(local); + let kind = hir::StmtKind::Let(local); let span = self.lower_span(s.span); stmts.push(hir::Stmt { hir_id, kind, span }); } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 94e1e06a95453..e8ff64a7fd2c3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2356,7 +2356,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: self.lower_span(span), ty: None, }; - self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) + self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local))) } fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index e5d7b8489033a..c50878e32a460 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1212,7 +1212,7 @@ impl<'a> State<'a> { fn print_stmt(&mut self, st: &ast::Stmt) { self.maybe_print_comment(st.span.lo()); match &st.kind { - ast::StmtKind::Local(loc) => { + ast::StmtKind::Let(loc) => { self.print_outer_attributes(&loc.attrs); self.space_if_not_bol(); self.ibox(INDENT_UNIT); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 0776f455efd9c..5af70937f622c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -616,7 +616,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // FIXME: We make sure that this is a normal top-level binding, // but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern - if let hir::StmtKind::Local(hir::Local { span, ty, init: None, pat, .. }) = + if let hir::StmtKind::Let(hir::Local { span, ty, init: None, pat, .. }) = &ex.kind && let hir::PatKind::Binding(..) = pat.kind && span.contains(self.decl_span) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index ebc9f1d109ee7..ee2e3d20fe56e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -558,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { hir::intravisit::walk_stmt(self, stmt); let expr = match stmt.kind { hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr, - hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr, + hir::StmtKind::Let(hir::Local { init: Some(expr), .. }) => expr, _ => { return; } @@ -1305,7 +1305,7 @@ struct BindingFinder { impl<'tcx> Visitor<'tcx> for BindingFinder { type Result = ControlFlow; fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result { - if let hir::StmtKind::Local(local) = s.kind + if let hir::StmtKind::Let(local) = s.kind && local.pat.span == self.span { ControlFlow::Break(local.hir_id) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 147939d3a529a..e5f5146fac8fb 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -203,57 +203,63 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { val: &'ll Value, dst: PlaceRef<'tcx, &'ll Value>, ) { - if self.is_ignore() { - return; - } - if self.is_sized_indirect() { - OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) - } else if self.is_unsized_indirect() { - bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); - } else if let PassMode::Cast { cast, pad_i32: _ } = &self.mode { - // FIXME(eddyb): Figure out when the simpler Store is safe, clang - // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. - let can_store_through_cast_ptr = false; - if can_store_through_cast_ptr { - bx.store(val, dst.llval, self.layout.align.abi); - } else { - // The actual return type is a struct, but the ABI - // adaptation code has cast it into some scalar type. The - // code that follows is the only reliable way I have - // found to do a transform like i64 -> {i32,i32}. - // Basically we dump the data onto the stack then memcpy it. - // - // Other approaches I tried: - // - Casting rust ret pointer to the foreign type and using Store - // is (a) unsafe if size of foreign type > size of rust type and - // (b) runs afoul of strict aliasing rules, yielding invalid - // assembly under -O (specifically, the store gets removed). - // - Truncating foreign type to correct integral type and then - // bitcasting to the struct type yields invalid cast errors. - - // We instead thus allocate some scratch space... - let scratch_size = cast.size(bx); - let scratch_align = cast.align(bx); - let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align); - bx.lifetime_start(llscratch, scratch_size); - - // ... where we first store the value... - bx.store(val, llscratch, scratch_align); - - // ... and then memcpy it to the intended destination. - bx.memcpy( - dst.llval, - self.layout.align.abi, - llscratch, - scratch_align, - bx.const_usize(self.layout.size.bytes()), - MemFlags::empty(), - ); + match &self.mode { + PassMode::Ignore => {} + // Sized indirect arguments + PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => { + let align = attrs.pointee_align.unwrap_or(self.layout.align.abi); + OperandValue::Ref(val, None, align).store(bx, dst); + } + // Unsized indirect qrguments + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { + bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); + } + PassMode::Cast { cast, pad_i32: _ } => { + // FIXME(eddyb): Figure out when the simpler Store is safe, clang + // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. + let can_store_through_cast_ptr = false; + if can_store_through_cast_ptr { + bx.store(val, dst.llval, self.layout.align.abi); + } else { + // The actual return type is a struct, but the ABI + // adaptation code has cast it into some scalar type. The + // code that follows is the only reliable way I have + // found to do a transform like i64 -> {i32,i32}. + // Basically we dump the data onto the stack then memcpy it. + // + // Other approaches I tried: + // - Casting rust ret pointer to the foreign type and using Store + // is (a) unsafe if size of foreign type > size of rust type and + // (b) runs afoul of strict aliasing rules, yielding invalid + // assembly under -O (specifically, the store gets removed). + // - Truncating foreign type to correct integral type and then + // bitcasting to the struct type yields invalid cast errors. + + // We instead thus allocate some scratch space... + let scratch_size = cast.size(bx); + let scratch_align = cast.align(bx); + let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align); + bx.lifetime_start(llscratch, scratch_size); + + // ... where we first store the value... + bx.store(val, llscratch, scratch_align); + + // ... and then memcpy it to the intended destination. + bx.memcpy( + dst.llval, + self.layout.align.abi, + llscratch, + scratch_align, + bx.const_usize(self.layout.size.bytes()), + MemFlags::empty(), + ); - bx.lifetime_end(llscratch, scratch_size); + bx.lifetime_end(llscratch, scratch_size); + } + } + _ => { + OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst); } - } else { - OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst); } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 017843c7e7d15..2af28146a51ea 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -164,6 +164,15 @@ impl CounterMappingRegion { end_line, end_col, ), + MappingKind::Branch { true_term, false_term } => Self::branch_region( + Counter::from_term(true_term), + Counter::from_term(false_term), + local_file_id, + start_line, + start_col, + end_line, + end_col, + ), } } @@ -188,9 +197,6 @@ impl CounterMappingRegion { } } - // This function might be used in the future; the LLVM API is still evolving, as is coverage - // support. - #[allow(dead_code)] pub(crate) fn branch_region( counter: Counter, false_counter: Counter, diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 733a77d24c2a4..133084b7c12ae 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -88,7 +88,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { match coverage.kind { // Marker statements have no effect during codegen, // so return early and don't create `func_coverage`. - CoverageKind::SpanMarker => return, + CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => return, // Match exhaustively to ensure that newly-added kinds are classified correctly. CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. } => {} } @@ -108,7 +108,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { let Coverage { kind } = coverage; match *kind { - CoverageKind::SpanMarker => unreachable!( + CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!( "unexpected marker statement {kind:?} should have caused an early return" ), CoverageKind::CounterIncrement { id } => { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e70cc9b621616..1406a7d9b5c29 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1081,6 +1081,21 @@ fn link_natively<'a>( } } + if sess.target.is_like_aix { + let stripcmd = "/usr/bin/strip"; + match strip { + Strip::Debuginfo => { + // FIXME: AIX's strip utility only offers option to strip line number information. + strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-l")) + } + Strip::Symbols => { + // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata. + strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-r")) + } + Strip::None => {} + } + } + Ok(()) } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index b4e054417f31c..bb23e21b2a230 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1640,16 +1640,7 @@ impl<'a> Linker for AixLinker<'a> { fn ehcont_guard(&mut self) {} - fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { - match strip { - Strip::None => {} - // FIXME: -s strips the symbol table, line number information - // and relocation information. - Strip::Debuginfo | Strip::Symbols => { - self.cmd.arg("-s"); - } - } - } + fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {} fn no_crt_objects(&mut self) {} diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index cd6afd2dbbf0e..387a5366b209b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -377,29 +377,45 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } - if arg.is_sized_indirect() { - // Don't copy an indirect argument to an alloca, the caller - // already put it in a temporary alloca and gave it up. - // FIXME: lifetimes - let llarg = bx.get_param(llarg_idx); - llarg_idx += 1; - LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout)) - } else if arg.is_unsized_indirect() { - // As the storage for the indirect argument lives during - // the whole function call, we just copy the fat pointer. - let llarg = bx.get_param(llarg_idx); - llarg_idx += 1; - let llextra = bx.get_param(llarg_idx); - llarg_idx += 1; - let indirect_operand = OperandValue::Pair(llarg, llextra); - - let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout); - indirect_operand.store(bx, tmp); - LocalRef::UnsizedPlace(tmp) - } else { - let tmp = PlaceRef::alloca(bx, arg.layout); - bx.store_fn_arg(arg, &mut llarg_idx, tmp); - LocalRef::Place(tmp) + match arg.mode { + // Sized indirect arguments + PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => { + // Don't copy an indirect argument to an alloca, the caller already put it + // in a temporary alloca and gave it up. + // FIXME: lifetimes + if let Some(pointee_align) = attrs.pointee_align + && pointee_align < arg.layout.align.abi + { + // ...unless the argument is underaligned, then we need to copy it to + // a higher-aligned alloca. + let tmp = PlaceRef::alloca(bx, arg.layout); + bx.store_fn_arg(arg, &mut llarg_idx, tmp); + LocalRef::Place(tmp) + } else { + let llarg = bx.get_param(llarg_idx); + llarg_idx += 1; + LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout)) + } + } + // Unsized indirect qrguments + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { + // As the storage for the indirect argument lives during + // the whole function call, we just copy the fat pointer. + let llarg = bx.get_param(llarg_idx); + llarg_idx += 1; + let llextra = bx.get_param(llarg_idx); + llarg_idx += 1; + let indirect_operand = OperandValue::Pair(llarg, llextra); + + let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout); + indirect_operand.store(bx, tmp); + LocalRef::UnsizedPlace(tmp) + } + _ => { + let tmp = PlaceRef::alloca(bx, arg.layout); + bx.store_fn_arg(arg, &mut llarg_idx, tmp); + LocalRef::Place(tmp) + } } }) .collect::>(); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index c448835413571..938f9f0beaacd 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -28,7 +28,7 @@ use rustc_errors::{ markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, }; use rustc_feature::find_gated_cfg; -use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; +use rustc_interface::util::{self, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; @@ -37,6 +37,7 @@ use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; +use rustc_session::output::collect_crate_types; use rustc_session::{config, filesearch, EarlyDiagCtxt, Session}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::FileLoader; diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 0c3e7fb75b059..5d345e788e94e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -189,7 +189,8 @@ where ); } -pub trait SubdiagMessageOp = Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage; +pub trait SubdiagMessageOp = + Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage; /// Trait implemented by lint types. This should not be implemented manually. Instead, use /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 989b7b485c992..e71047f94fa9a 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -218,7 +218,7 @@ impl<'a> ExtCtxt<'a> { } pub fn stmt_local(&self, local: P, span: Span) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Let(local), span } } pub fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 3544a8f0a8d92..cac1e8f80e323 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1389,7 +1389,7 @@ impl InvocationCollectorNode for ast::Stmt { StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)), StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)), StmtKind::Expr(..) => unreachable!(), - StmtKind::Local(..) | StmtKind::Empty => false, + StmtKind::Let(..) | StmtKind::Empty => false, } } fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8ce6c3b0900ef..bb468b2e05673 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1209,7 +1209,7 @@ pub struct Stmt<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum StmtKind<'hir> { /// A local (`let`) binding. - Local(&'hir Local<'hir>), + Let(&'hir Local<'hir>), /// An item binding. Item(ItemId), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 32b4bf38fa96a..fbbad38d17f10 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -627,7 +627,7 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) -> pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result { try_visit!(visitor.visit_id(statement.hir_id)); match statement.kind { - StmtKind::Local(ref local) => visitor.visit_local(local), + StmtKind::Let(ref local) => visitor.visit_local(local), StmtKind::Item(item) => visitor.visit_nested_item(item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index b9dc5cbc4d206..f0c15a070b48a 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -27,7 +27,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { /// Check for shared or mutable references of `static mut` inside statement pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { - if let hir::StmtKind::Local(loc) = stmt.kind + if let hir::StmtKind::Let(loc) = stmt.kind && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind && matches!(ba.0, rustc_ast::ByRef::Yes) && let Some(init) = loc.init diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 2a4dd6b0e0ef3..3c26729eff8af 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -123,7 +123,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h for (i, statement) in blk.stmts.iter().enumerate() { match statement.kind { - hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => { + hir::StmtKind::Let(hir::Local { els: Some(els), .. }) => { // Let-else has a special lexical structure for variables. // First we take a checkpoint of the current scope context here. let mut prev_cx = visitor.cx; @@ -146,7 +146,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h // From now on, we continue normally. visitor.cx = prev_cx; } - hir::StmtKind::Local(..) => { + hir::StmtKind::Let(..) => { // Each declaration introduces a subscope for bindings // introduced by the declaration; this subscope covers a // suffix of the block. Each subscope in a block has the diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1ace7cd201f96..e070db9423df1 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -864,7 +864,7 @@ impl<'a> State<'a> { fn print_stmt(&mut self, st: &hir::Stmt<'_>) { self.maybe_print_comment(st.span.lo()); match st.kind { - hir::StmtKind::Local(loc) => { + hir::StmtKind::Let(loc) => { self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc)); } hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)), @@ -2307,7 +2307,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool { /// seen the semicolon, and thus don't need another. fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool { match *stmt { - hir::StmtKind::Local(_) => true, + hir::StmtKind::Let(_) => true, hir::StmtKind::Item(_) => false, hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e), hir::StmtKind::Semi(..) => false, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index ba0383d19b92a..43e9554459439 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -371,11 +371,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { match stmt.kind { - hir::StmtKind::Local(hir::Local { pat, init: Some(expr), els, .. }) => { + hir::StmtKind::Let(hir::Local { pat, init: Some(expr), els, .. }) => { self.walk_local(expr, pat, *els, |_| {}) } - hir::StmtKind::Local(_) => {} + hir::StmtKind::Let(_) => {} hir::StmtKind::Item(_) => { // We don't visit nested items in this visitor, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 2747700f3c136..1fa1da93018af 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1593,7 +1593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't do all the complex logic below for `DeclItem`. match stmt.kind { hir::StmtKind::Item(..) => return, - hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} + hir::StmtKind::Let(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} } self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); @@ -1602,7 +1602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let old_diverges = self.diverges.replace(Diverges::Maybe); match stmt.kind { - hir::StmtKind::Local(l) => { + hir::StmtKind::Let(l) => { self.check_decl_local(l); } // Ignore for now. @@ -1765,7 +1765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { [ hir::Stmt { kind: - hir::StmtKind::Local(hir::Local { + hir::StmtKind::Let(hir::Local { source: hir::LocalSource::AssignDesugar(_), .. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5a1c7b0561185..3f6f4cccba796 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1599,7 +1599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_local_statement(&self, id: hir::HirId) -> bool { let node = self.tcx.hir_node(id); - matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. })) + matches!(node, Node::Stmt(Stmt { kind: StmtKind::Let(..), .. })) } /// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4c413e4d1c6a5..c5bbcc56f86a5 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2221,7 +2221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'v> Visitor<'v> for LetVisitor { type Result = ControlFlow>>; fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result { - if let hir::StmtKind::Local(&hir::Local { pat, init, .. }) = ex.kind + if let hir::StmtKind::Let(&hir::Local { pat, init, .. }) = ex.kind && let Binding(_, _, ident, ..) = pat.kind && ident.name == self.ident_name { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 211109b59417a..be14f5bf0d8b5 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -217,7 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bug!(); }; for stmt in block.stmts { - let hir::StmtKind::Local(hir::Local { + let hir::StmtKind::Let(hir::Local { init: Some(init), source: hir::LocalSource::AsyncFn, pat, diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index dd9c16d006a96..1462037c8c8e7 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -110,8 +110,9 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::{base_n, flock}; use rustc_errors::ErrorGuaranteed; use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy}; +use rustc_session::config::CrateType; +use rustc_session::output::{collect_crate_types, find_crate_name}; use rustc_session::{Session, StableCrateId}; -use rustc_span::Symbol; use std::fs as std_fs; use std::io::{self, ErrorKind}; @@ -205,11 +206,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu /// The garbage collection will take care of it. /// /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph -pub(crate) fn prepare_session_directory( - sess: &Session, - crate_name: Symbol, - stable_crate_id: StableCrateId, -) -> Result<(), ErrorGuaranteed> { +pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuaranteed> { if sess.opts.incremental.is_none() { return Ok(()); } @@ -219,7 +216,7 @@ pub(crate) fn prepare_session_directory( debug!("prepare_session_directory"); // {incr-comp-dir}/{crate-name-and-disambiguator} - let crate_dir = crate_path(sess, crate_name, stable_crate_id); + let crate_dir = crate_path(sess); debug!("crate-dir: {}", crate_dir.display()); create_dir(sess, &crate_dir, "crate")?; @@ -604,9 +601,18 @@ fn string_to_timestamp(s: &str) -> Result { Ok(UNIX_EPOCH + duration) } -fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf { +fn crate_path(sess: &Session) -> PathBuf { let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); + let crate_name = find_crate_name(sess, &[]); + let crate_types = collect_crate_types(sess, &[]); + let stable_crate_id = StableCrateId::new( + crate_name, + crate_types.contains(&CrateType::Executable), + sess.opts.cg.metadata.clone(), + sess.cfg_version, + ); + let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE); let crate_name = format!("{crate_name}-{stable_crate_id}"); diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 96bfe766c20f5..357f2ae92d4c3 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -8,8 +8,8 @@ use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::Decodable; use rustc_session::config::IncrementalStateAssertion; -use rustc_session::{Session, StableCrateId}; -use rustc_span::{ErrorGuaranteed, Symbol}; +use rustc_session::Session; +use rustc_span::ErrorGuaranteed; use std::path::{Path, PathBuf}; use super::data::*; @@ -190,13 +190,9 @@ pub fn load_query_result_cache(sess: &Session) -> Option> { /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a /// new graph to an incremental session directory. -pub fn setup_dep_graph( - sess: &Session, - crate_name: Symbol, - stable_crate_id: StableCrateId, -) -> Result { +pub fn setup_dep_graph(sess: &Session) -> Result { // `load_dep_graph` can only be called after `prepare_session_directory`. - prepare_session_directory(sess, crate_name, stable_crate_id)?; + prepare_session_directory(sess)?; let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess)); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index edd7f733ec96b..ef4b88575fced 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2139,7 +2139,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // the same span as the error and the type is specified. if let hir::Stmt { kind: - hir::StmtKind::Local(hir::Local { + hir::StmtKind::Let(hir::Local { init: Some(hir::Expr { span: init_span, .. }), ty: Some(array_ty), .. diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 8cdf39b173987..9081fbaa2dc2b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -585,7 +585,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result { - if let hir::StmtKind::Local(hir::Local { + if let hir::StmtKind::Let(hir::Local { span, pat: hir::Pat { .. }, ty: None, @@ -824,7 +824,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let hir = self.tcx.hir(); for stmt in blk.stmts.iter().rev() { - let hir::StmtKind::Local(local) = &stmt.kind else { + let hir::StmtKind::Let(local) = &stmt.kind else { continue; }; local.pat.walk(&mut find_compatible_candidates); diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index bd9fad8b04296..47dfbc1d7fbf1 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -48,6 +48,3 @@ interface_rustc_error_unexpected_annotation = interface_temps_dir_error = failed to find or create the directory specified by `--temps-dir` - -interface_unsupported_crate_type_for_target = - dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index a9ab2720d89a5..29294003b8f29 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -1,7 +1,5 @@ use rustc_macros::Diagnostic; -use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; -use rustc_target::spec::TargetTriple; use std::io; use std::path::Path; @@ -90,13 +88,6 @@ pub struct FailedWritingFile<'a> { #[diag(interface_proc_macro_crate_panic_abort)] pub struct ProcMacroCratePanicAbort; -#[derive(Diagnostic)] -#[diag(interface_unsupported_crate_type_for_target)] -pub struct UnsupportedCrateTypeForTarget<'a> { - pub crate_type: CrateType, - pub target_triple: &'a TargetTriple, -} - #[derive(Diagnostic)] #[diag(interface_multiple_output_types_adaption)] pub struct MultipleOutputTypesAdaption; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index c22188226961e..ee677a092e2f1 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{GlobalCtxt, TyCtxt}; use rustc_serialize::opaque::FileEncodeResult; use rustc_session::config::{self, CrateType, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; -use rustc_session::output::find_crate_name; +use rustc_session::output::{collect_crate_types, find_crate_name}; use rustc_session::Session; use rustc_span::symbol::sym; use std::any::Any; @@ -128,7 +128,7 @@ impl<'tcx> Queries<'tcx> { // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. let crate_name = find_crate_name(sess, &pre_configured_attrs); - let crate_types = util::collect_crate_types(sess, &pre_configured_attrs); + let crate_types = collect_crate_types(sess, &pre_configured_attrs); let stable_crate_id = StableCrateId::new( crate_name, crate_types.contains(&CrateType::Executable), @@ -136,7 +136,7 @@ impl<'tcx> Queries<'tcx> { sess.cfg_version, ); let outputs = util::build_output_filenames(&pre_configured_attrs, sess); - let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?; + let dep_graph = setup_dep_graph(sess)?; let cstore = FreezeLock::new(Box::new(CStore::new( self.compiler.codegen_backend.metadata_loader(), diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 829b00aabc126..7d48f90db3625 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -7,14 +7,15 @@ use rustc_data_structures::sync; use rustc_metadata::{load_symbol_from_dylib, DylibError}; use rustc_parse::validate_attr; use rustc_session as session; -use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes}; +use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes}; use rustc_session::filesearch::sysroot_candidates; use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer}; -use rustc_session::{filesearch, output, Session}; +use rustc_session::{filesearch, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; use rustc_target::spec::Target; +use session::output::{categorize_crate_type, CRATE_TYPES}; use session::EarlyDiagCtxt; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; @@ -399,67 +400,6 @@ pub(crate) fn check_attr_crate_type( } } -const CRATE_TYPES: &[(Symbol, CrateType)] = &[ - (sym::rlib, CrateType::Rlib), - (sym::dylib, CrateType::Dylib), - (sym::cdylib, CrateType::Cdylib), - (sym::lib, config::default_lib_output()), - (sym::staticlib, CrateType::Staticlib), - (sym::proc_dash_macro, CrateType::ProcMacro), - (sym::bin, CrateType::Executable), -]; - -fn categorize_crate_type(s: Symbol) -> Option { - Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1) -} - -pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { - // If we're generating a test executable, then ignore all other output - // styles at all other locations - if session.opts.test { - return vec![CrateType::Executable]; - } - - // Only check command line flags if present. If no types are specified by - // command line, then reuse the empty `base` Vec to hold the types that - // will be found in crate attributes. - // JUSTIFICATION: before wrapper fn is available - #[allow(rustc::bad_opt_access)] - let mut base = session.opts.crate_types.clone(); - if base.is_empty() { - let attr_types = attrs.iter().filter_map(|a| { - if a.has_name(sym::crate_type) - && let Some(s) = a.value_str() - { - categorize_crate_type(s) - } else { - None - } - }); - base.extend(attr_types); - if base.is_empty() { - base.push(output::default_output_for_target(session)); - } else { - base.sort(); - base.dedup(); - } - } - - base.retain(|crate_type| { - if output::invalid_output_for_target(session, *crate_type) { - session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { - crate_type: *crate_type, - target_triple: &session.opts.target_triple, - }); - false - } else { - true - } - }); - - base -} - fn multiple_output_types_to_stdout( output_types: &OutputTypes, single_output_file_is_stdout: bool, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 595dc08b081ed..d1343e3b4bae8 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -989,7 +989,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & impl EarlyLintPass for UnusedDocComment { fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) { let kind = match stmt.kind { - ast::StmtKind::Local(..) => "statements", + ast::StmtKind::Let(..) => "statements", // Disabled pending discussion in #78306 ast::StmtKind::Item(..) => return, // expressions will be reported by `check_expr`. diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index f84d1c6c2d0aa..3e10879e2411a 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -914,7 +914,7 @@ trait UnusedDelimLint { fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { match s.kind { - StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { + StmtKind::Let(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { if let Some((init, els)) = local.kind.init_else_opt() { let ctx = match els { None => UnusedDelimsCtx::AssignedValue, @@ -1189,7 +1189,7 @@ impl EarlyLintPass for UnusedParens { } fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { - if let StmtKind::Local(ref local) = s.kind { + if let StmtKind::Let(ref local) = s.kind { self.check_unused_parens_pat(cx, &local.pat, true, false, (true, false)); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 4acdd8fef5270..6506aa3343108 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -557,6 +557,7 @@ declare_lint! { /// fn main() { /// use foo::bar; /// foo::bar(); + /// bar(); /// } /// ``` /// diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index a64fa74762c04..cc940f2e74b8d 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -653,7 +653,7 @@ impl<'hir> Map<'hir> { | Node::ForeignItem(_) | Node::TraitItem(_) | Node::ImplItem(_) - | Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break, + | Node::Stmt(Stmt { kind: StmtKind::Let(_), .. }) => break, Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => { return Some(expr); } diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 8588ae2033613..b984df3646e61 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -6,6 +6,7 @@ use crate::mir; use crate::query::TyCtxtAt; use crate::ty::{Ty, TyCtxt}; +use rustc_span::def_id::LocalDefId; use rustc_span::DUMMY_SP; macro_rules! declare_hooks { @@ -70,4 +71,10 @@ declare_hooks! { /// Getting a &core::panic::Location referring to a span. hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue<'tcx>; + + /// Returns `true` if this def is a function-like thing that is eligible for + /// coverage instrumentation under `-Cinstrument-coverage`. + /// + /// (Eligible functions might nevertheless be skipped for other reasons.) + hook is_eligible_for_coverage(key: LocalDefId) -> bool; } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 18e198eb9fcab..645a417c32250 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -2,10 +2,19 @@ use rustc_index::IndexVec; use rustc_macros::HashStable; -use rustc_span::Symbol; +use rustc_span::{Span, Symbol}; use std::fmt::{self, Debug, Formatter}; +rustc_index::newtype_index! { + /// Used by [`CoverageKind::BlockMarker`] to mark blocks during THIR-to-MIR + /// lowering, so that those blocks can be identified later. + #[derive(HashStable)] + #[encodable] + #[debug_format = "BlockMarkerId({})"] + pub struct BlockMarkerId {} +} + rustc_index::newtype_index! { /// ID of a coverage counter. Values ascend from 0. /// @@ -83,6 +92,12 @@ pub enum CoverageKind { /// codegen. SpanMarker, + /// Marks its enclosing basic block with an ID that can be referred to by + /// side data in [`BranchInfo`]. + /// + /// Has no effect during codegen. + BlockMarker { id: BlockMarkerId }, + /// Marks the point in MIR control flow represented by a coverage counter. /// /// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR. @@ -107,6 +122,7 @@ impl Debug for CoverageKind { use CoverageKind::*; match self { SpanMarker => write!(fmt, "SpanMarker"), + BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()), CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()), ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()), } @@ -163,14 +179,18 @@ pub struct Expression { pub enum MappingKind { /// Associates a normal region of code with a counter/expression/zero. Code(CovTerm), + /// Associates a branch region with separate counters for true and false. + Branch { true_term: CovTerm, false_term: CovTerm }, } impl MappingKind { /// Iterator over all coverage terms in this mapping kind. pub fn terms(&self) -> impl Iterator { - let one = |a| std::iter::once(a); + let one = |a| std::iter::once(a).chain(None); + let two = |a, b| std::iter::once(a).chain(Some(b)); match *self { Self::Code(term) => one(term), + Self::Branch { true_term, false_term } => two(true_term, false_term), } } @@ -179,6 +199,9 @@ impl MappingKind { pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self { match *self { Self::Code(term) => Self::Code(map_fn(term)), + Self::Branch { true_term, false_term } => { + Self::Branch { true_term: map_fn(true_term), false_term: map_fn(false_term) } + } } } } @@ -202,3 +225,22 @@ pub struct FunctionCoverageInfo { pub expressions: IndexVec, pub mappings: Vec, } + +/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR. +#[derive(Clone, Debug)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +pub struct BranchInfo { + /// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was + /// injected into the MIR body. This makes it possible to allocate per-ID + /// data structures without having to scan the entire body first. + pub num_block_markers: usize, + pub branch_spans: Vec, +} + +#[derive(Clone, Debug)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +pub struct BranchSpan { + pub span: Span, + pub true_marker: BlockMarkerId, + pub false_marker: BlockMarkerId, +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index b71c614dc4fe9..d57ffc0f8b5c5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -403,6 +403,12 @@ pub struct Body<'tcx> { pub tainted_by_errors: Option, + /// Branch coverage information collected during MIR building, to be used by + /// the `InstrumentCoverage` pass. + /// + /// Only present if branch coverage is enabled and this function is eligible. + pub coverage_branch_info: Option>, + /// Per-function coverage information added by the `InstrumentCoverage` /// pass, to be used in conjunction with the coverage statements injected /// into this body's blocks. @@ -450,6 +456,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors, + coverage_branch_info: None, function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); @@ -479,6 +486,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors: None, + coverage_branch_info: None, function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8ae65f3832fd7..94751c4476157 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -461,6 +461,9 @@ pub fn write_mir_intro<'tcx>( // Add an empty line before the first block is printed. writeln!(w)?; + if let Some(branch_info) = &body.coverage_branch_info { + write_coverage_branch_info(branch_info, w)?; + } if let Some(function_coverage_info) = &body.function_coverage_info { write_function_coverage_info(function_coverage_info, w)?; } @@ -468,6 +471,25 @@ pub fn write_mir_intro<'tcx>( Ok(()) } +fn write_coverage_branch_info( + branch_info: &coverage::BranchInfo, + w: &mut dyn io::Write, +) -> io::Result<()> { + let coverage::BranchInfo { branch_spans, .. } = branch_info; + + for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans { + writeln!( + w, + "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", + )?; + } + if !branch_spans.is_empty() { + writeln!(w)?; + } + + Ok(()) +} + fn write_function_coverage_info( function_coverage_info: &coverage::FunctionCoverageInfo, w: &mut dyn io::Write, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index c8fb11673cf89..4b015640f916e 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -405,6 +405,7 @@ TrivialTypeTraversalImpls! { ::rustc_hir::HirId, ::rustc_hir::MatchSource, ::rustc_target::asm::InlineAsmRegOrRegClass, + crate::mir::coverage::BlockMarkerId, crate::mir::coverage::CounterId, crate::mir::coverage::ExpressionId, crate::mir::Local, diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs new file mode 100644 index 0000000000000..0b8ec234dda7a --- /dev/null +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -0,0 +1,148 @@ +use std::assert_matches::assert_matches; +use std::collections::hash_map::Entry; + +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind}; +use rustc_middle::mir::{self, BasicBlock, UnOp}; +use rustc_middle::thir::{ExprId, ExprKind, Thir}; +use rustc_middle::ty::TyCtxt; +use rustc_span::def_id::LocalDefId; + +use crate::build::Builder; + +pub(crate) struct BranchInfoBuilder { + /// Maps condition expressions to their enclosing `!`, for better instrumentation. + nots: FxHashMap, + + num_block_markers: usize, + branch_spans: Vec, +} + +#[derive(Clone, Copy)] +struct NotInfo { + /// When visiting the associated expression as a branch condition, treat this + /// enclosing `!` as the branch condition instead. + enclosing_not: ExprId, + /// True if the associated expression is nested within an odd number of `!` + /// expressions relative to `enclosing_not` (inclusive of `enclosing_not`). + is_flipped: bool, +} + +impl BranchInfoBuilder { + /// Creates a new branch info builder, but only if branch coverage instrumentation + /// is enabled and `def_id` represents a function that is eligible for coverage. + pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) { + Some(Self { nots: FxHashMap::default(), num_block_markers: 0, branch_spans: vec![] }) + } else { + None + } + } + + /// Unary `!` expressions inside an `if` condition are lowered by lowering + /// their argument instead, and then reversing the then/else arms of that `if`. + /// + /// That's awkward for branch coverage instrumentation, so to work around that + /// we pre-emptively visit any affected `!` expressions, and record extra + /// information that [`Builder::visit_coverage_branch_condition`] can use to + /// synthesize branch instrumentation for the enclosing `!`. + pub(crate) fn visit_unary_not(&mut self, thir: &Thir<'_>, unary_not: ExprId) { + assert_matches!(thir[unary_not].kind, ExprKind::Unary { op: UnOp::Not, .. }); + + self.visit_with_not_info( + thir, + unary_not, + // Set `is_flipped: false` for the `!` itself, so that its enclosed + // expression will have `is_flipped: true`. + NotInfo { enclosing_not: unary_not, is_flipped: false }, + ); + } + + fn visit_with_not_info(&mut self, thir: &Thir<'_>, expr_id: ExprId, not_info: NotInfo) { + match self.nots.entry(expr_id) { + // This expression has already been marked by an enclosing `!`. + Entry::Occupied(_) => return, + Entry::Vacant(entry) => entry.insert(not_info), + }; + + match thir[expr_id].kind { + ExprKind::Unary { op: UnOp::Not, arg } => { + // Invert the `is_flipped` flag for the contents of this `!`. + let not_info = NotInfo { is_flipped: !not_info.is_flipped, ..not_info }; + self.visit_with_not_info(thir, arg, not_info); + } + ExprKind::Scope { value, .. } => self.visit_with_not_info(thir, value, not_info), + ExprKind::Use { source } => self.visit_with_not_info(thir, source, not_info), + // All other expressions (including `&&` and `||`) don't need any + // special handling of their contents, so stop visiting. + _ => {} + } + } + + fn next_block_marker_id(&mut self) -> BlockMarkerId { + let id = BlockMarkerId::from_usize(self.num_block_markers); + self.num_block_markers += 1; + id + } + + pub(crate) fn into_done(self) -> Option> { + let Self { nots: _, num_block_markers, branch_spans } = self; + + if num_block_markers == 0 { + assert!(branch_spans.is_empty()); + return None; + } + + Some(Box::new(mir::coverage::BranchInfo { num_block_markers, branch_spans })) + } +} + +impl Builder<'_, '_> { + /// If branch coverage is enabled, inject marker statements into `then_block` + /// and `else_block`, and record their IDs in the table of branch spans. + pub(crate) fn visit_coverage_branch_condition( + &mut self, + mut expr_id: ExprId, + mut then_block: BasicBlock, + mut else_block: BasicBlock, + ) { + // Bail out if branch coverage is not enabled for this function. + let Some(branch_info) = self.coverage_branch_info.as_ref() else { return }; + + // If this condition expression is nested within one or more `!` expressions, + // replace it with the enclosing `!` collected by `visit_unary_not`. + if let Some(&NotInfo { enclosing_not, is_flipped }) = branch_info.nots.get(&expr_id) { + expr_id = enclosing_not; + if is_flipped { + std::mem::swap(&mut then_block, &mut else_block); + } + } + let source_info = self.source_info(self.thir[expr_id].span); + + // Now that we have `source_info`, we can upgrade to a &mut reference. + let branch_info = self.coverage_branch_info.as_mut().expect("upgrading & to &mut"); + + let mut inject_branch_marker = |block: BasicBlock| { + let id = branch_info.next_block_marker_id(); + + let marker_statement = mir::Statement { + source_info, + kind: mir::StatementKind::Coverage(Box::new(mir::Coverage { + kind: CoverageKind::BlockMarker { id }, + })), + }; + self.cfg.push(block, marker_statement); + + id + }; + + let true_marker = inject_branch_marker(then_block); + let false_marker = inject_branch_marker(else_block); + + branch_info.branch_spans.push(BranchSpan { + span: source_info.span, + true_marker, + false_marker, + }); + } +} diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index c2bff9084c67e..288b787798b49 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -60,6 +60,7 @@ pub(super) fn build_custom_mir<'tcx>( tainted_by_errors: None, injection_phase: None, pass_count: 0, + coverage_branch_info: None, function_coverage_info: None, }; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4d5ed65c8416c..e7808ff880b57 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -105,6 +105,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { success_block.unit() } ExprKind::Unary { op: UnOp::Not, arg } => { + // Improve branch coverage instrumentation by noting conditions + // nested within one or more `!` expressions. + // (Skipped if branch coverage is not enabled.) + if let Some(branch_info) = this.coverage_branch_info.as_mut() { + branch_info.visit_unary_not(this.thir, expr_id); + } + let local_scope = this.local_scope(); let (success_block, failure_block) = this.in_if_then_scope(local_scope, expr_span, |this| { @@ -149,6 +156,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let else_block = this.cfg.start_new_block(); let term = TerminatorKind::if_(operand, then_block, else_block); + // Record branch coverage info for this condition. + // (Does nothing if branch coverage is not enabled.) + this.visit_coverage_branch_condition(expr_id, then_block, else_block); + let source_info = this.source_info(expr_span); this.cfg.terminate(block, source_info, term); this.break_for_else(else_block, source_info); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 45954bdb114f2..2fe5d3fb5e0df 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -234,6 +234,10 @@ struct Builder<'a, 'tcx> { // the root (most of them do) and saves us from retracing many sub-paths // many times, and rechecking many nodes. lint_level_roots_cache: GrowableBitSet, + + /// Collects additional coverage information during MIR building. + /// Only present if branch coverage is enabled and this function is eligible. + coverage_branch_info: Option, } type CaptureMap<'tcx> = SortedIndexMultiMap>; @@ -807,6 +811,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unit_temp: None, var_debug_info: vec![], lint_level_roots_cache: GrowableBitSet::new_empty(), + coverage_branch_info: coverageinfo::BranchInfoBuilder::new_if_enabled(tcx, def), }; assert_eq!(builder.cfg.start_new_block(), START_BLOCK); @@ -826,7 +831,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - Body::new( + let mut body = Body::new( MirSource::item(self.def_id.to_def_id()), self.cfg.basic_blocks, self.source_scopes, @@ -837,7 +842,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.fn_span, self.coroutine, None, - ) + ); + body.coverage_branch_info = self.coverage_branch_info.and_then(|b| b.into_done()); + body } fn insert_upvar_arg(&mut self) { @@ -1111,6 +1118,7 @@ pub(crate) fn parse_float_into_scalar( mod block; mod cfg; +mod coverageinfo; mod custom; mod expr; mod matches; diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 1e93e126b706e..d4a347975dbae 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -63,7 +63,7 @@ impl<'tcx> Cx<'tcx> { // ignore for purposes of the MIR None } - hir::StmtKind::Local(local) => { + hir::StmtKind::Let(local) => { let remainder_scope = region::Scope { id: block_id, data: region::ScopeData::Remainder(region::FirstStatementIndex::new( diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 4c5be0a3f4bed..b2407c545071b 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -14,7 +14,6 @@ use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans}; use crate::MirPass; use rustc_middle::hir; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{ self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator, @@ -44,7 +43,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { let def_id = mir_source.def_id().expect_local(); - if !is_eligible_for_coverage(tcx, def_id) { + if !tcx.is_eligible_for_coverage(def_id) { trace!("InstrumentCoverage skipped for {def_id:?} (not eligible)"); return; } @@ -140,6 +139,10 @@ fn create_mappings<'tcx>( .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| { let kind = match bcb_mapping_kind { BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)), + BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch { + true_term: term_for_bcb(true_bcb), + false_term: term_for_bcb(false_bcb), + }, }; let code_region = make_code_region(source_map, file_name, span, body_span)?; Some(Mapping { kind, code_region }) @@ -349,37 +352,6 @@ fn check_code_region(code_region: CodeRegion) -> Option { } } -fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - // Only instrument functions, methods, and closures (not constants since they are evaluated - // at compile time by Miri). - // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const - // expressions get coverage spans, we will probably have to "carve out" space for const - // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might - // be tricky if const expressions have no corresponding statements in the enclosing MIR. - // Closures are carved out by their initial `Assign` statement.) - if !tcx.def_kind(def_id).is_fn_like() { - trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)"); - return false; - } - - // Don't instrument functions with `#[automatically_derived]` on their - // enclosing impl block, on the assumption that most users won't care about - // coverage for derived impls. - if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id()) - && tcx.is_automatically_derived(impl_of) - { - trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)"); - return false; - } - - if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { - trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)"); - return false; - } - - true -} - /// Function information extracted from HIR by the coverage instrumentor. #[derive(Debug)] struct ExtractedHirInfo { diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index dfc7c3a713bc2..1de7b6f66a7bc 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,14 +1,49 @@ -use super::*; - use rustc_data_structures::captures::Captures; -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{Body, CoverageIdsInfo}; -use rustc_middle::query::Providers; -use rustc_middle::ty::{self}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::coverage::{CounterId, CoverageKind}; +use rustc_middle::mir::{Body, Coverage, CoverageIdsInfo, Statement, StatementKind}; +use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::util::Providers; +use rustc_span::def_id::LocalDefId; -/// A `query` provider for retrieving coverage information injected into MIR. +/// Registers query/hook implementations related to coverage. pub(crate) fn provide(providers: &mut Providers) { - providers.coverage_ids_info = |tcx, def_id| coverage_ids_info(tcx, def_id); + providers.hooks.is_eligible_for_coverage = + |TyCtxtAt { tcx, .. }, def_id| is_eligible_for_coverage(tcx, def_id); + providers.queries.coverage_ids_info = coverage_ids_info; +} + +/// Hook implementation for [`TyCtxt::is_eligible_for_coverage`]. +fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + // Only instrument functions, methods, and closures (not constants since they are evaluated + // at compile time by Miri). + // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const + // expressions get coverage spans, we will probably have to "carve out" space for const + // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might + // be tricky if const expressions have no corresponding statements in the enclosing MIR. + // Closures are carved out by their initial `Assign` statement.) + if !tcx.def_kind(def_id).is_fn_like() { + trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)"); + return false; + } + + // Don't instrument functions with `#[automatically_derived]` on their + // enclosing impl block, on the assumption that most users won't care about + // coverage for derived impls. + if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id()) + && tcx.is_automatically_derived(impl_of) + { + trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)"); + return false; + } + + if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)"); + return false; + } + + true } /// Query implementation for `coverage_ids_info`. diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 4260a6f0c6f79..672de1fbe60fd 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -13,6 +13,8 @@ mod from_mir; pub(super) enum BcbMappingKind { /// Associates an ordinary executable code span with its corresponding BCB. Code(BasicCoverageBlock), + /// Associates a branch span with BCBs for its true and false arms. + Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock }, } #[derive(Debug)] @@ -66,6 +68,12 @@ pub(super) fn generate_coverage_spans( // Each span produced by the generator represents an ordinary code region. BcbMapping { kind: BcbMappingKind::Code(bcb), span } })); + + mappings.extend(from_mir::extract_branch_mappings( + mir_body, + hir_info.body_span, + basic_coverage_blocks, + )); } if mappings.is_empty() { @@ -80,6 +88,10 @@ pub(super) fn generate_coverage_spans( for &BcbMapping { kind, span: _ } in &mappings { match kind { BcbMappingKind::Code(bcb) => insert(bcb), + BcbMappingKind::Branch { true_bcb, false_bcb } => { + insert(true_bcb); + insert(false_bcb); + } } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 099a354f45dd1..86097bdcd9537 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,7 +1,9 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; +use rustc_index::IndexVec; +use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind}; use rustc_middle::mir::{ - self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, + self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; @@ -9,6 +11,7 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; +use crate::coverage::spans::{BcbMapping, BcbMappingKind}; use crate::coverage::ExtractedHirInfo; /// Traverses the MIR body to produce an initial collection of coverage-relevant @@ -179,8 +182,6 @@ fn is_closure_like(statement: &Statement<'_>) -> bool { /// If the MIR `Statement` has a span contributive to computing coverage spans, /// return it; otherwise return `None`. fn filtered_statement_span(statement: &Statement<'_>) -> Option { - use mir::coverage::CoverageKind; - match statement.kind { // These statements have spans that are often outside the scope of the executed source code // for their parent `BasicBlock`. @@ -225,6 +226,11 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option { Some(statement.source_info.span) } + StatementKind::Coverage(box mir::Coverage { + // Block markers are used for branch coverage, so ignore them here. + kind: CoverageKind::BlockMarker {..} + }) => None, + StatementKind::Coverage(box mir::Coverage { // These coverage statements should not exist prior to coverage instrumentation. kind: CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. } @@ -358,3 +364,51 @@ impl SpanFromMir { Self { span, visible_macro, bcb, is_hole } } } + +pub(super) fn extract_branch_mappings( + mir_body: &mir::Body<'_>, + body_span: Span, + basic_coverage_blocks: &CoverageGraph, +) -> Vec { + let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { + return vec![]; + }; + + let mut block_markers = IndexVec::>::from_elem_n( + None, + branch_info.num_block_markers, + ); + + // Fill out the mapping from block marker IDs to their enclosing blocks. + for (bb, data) in mir_body.basic_blocks.iter_enumerated() { + for statement in &data.statements { + if let StatementKind::Coverage(coverage) = &statement.kind + && let CoverageKind::BlockMarker { id } = coverage.kind + { + block_markers[id] = Some(bb); + } + } + } + + branch_info + .branch_spans + .iter() + .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| { + // For now, ignore any branch span that was introduced by + // expansion. This makes things like assert macros less noisy. + if !raw_span.ctxt().outer_expn_data().is_root() { + return None; + } + let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?; + + let bcb_from_marker = |marker: BlockMarkerId| { + Some(basic_coverage_blocks.bcb_from_bb(block_markers[marker]?)?) + }; + + let true_bcb = bcb_from_marker(true_marker)?; + let false_bcb = bcb_from_marker(false_marker)?; + + Some(BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span }) + }) + .collect::>() +} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 0491de7826590..4551380152217 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -37,8 +37,9 @@ use rustc_middle::mir::{ LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, }; -use rustc_middle::query::Providers; +use rustc_middle::query; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_middle::util::Providers; use rustc_span::{source_map::Spanned, sym, DUMMY_SP}; use rustc_trait_selection::traits; @@ -124,7 +125,7 @@ pub fn provide(providers: &mut Providers) { ffi_unwind_calls::provide(providers); shim::provide(providers); cross_crate_inline::provide(providers); - *providers = Providers { + providers.queries = query::Providers { mir_keys, mir_const, mir_const_qualif, @@ -139,7 +140,7 @@ pub fn provide(providers: &mut Providers) { mir_inliner_callees: inline::cycle::mir_inliner_callees, promoted_mir, deduced_param_attrs: deduce_param_attrs::deduced_param_attrs, - ..*providers + ..providers.queries }; } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 73f5829adec64..fc907760531f7 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -254,7 +254,7 @@ impl<'a> Parser<'a> { let local = this.parse_local(attrs)?; // FIXME - maybe capture semicolon in recovery? Ok(( - this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), + this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), TrailingToken::None, )) })?; @@ -278,7 +278,7 @@ impl<'a> Parser<'a> { } else { TrailingToken::None }; - Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), trailing)) + Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing)) }) } @@ -764,7 +764,7 @@ impl<'a> Parser<'a> { } } StmtKind::Expr(_) | StmtKind::MacCall(_) => {} - StmtKind::Local(local) if let Err(mut e) = self.expect_semi() => { + StmtKind::Let(local) if let Err(mut e) = self.expect_semi() => { // We might be at the `,` in `let x = foo;`. Try to recover. match &mut local.kind { LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => { @@ -820,7 +820,7 @@ impl<'a> Parser<'a> { } eat_semi = false; } - StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => { + StmtKind::Empty | StmtKind::Item(_) | StmtKind::Let(_) | StmtKind::Semi(_) => { eat_semi = false } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 91ab5b30dea3d..eb2399f7a64f4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2444,7 +2444,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { // When checking statements ignore expressions, they will be checked later. - if let hir::StmtKind::Local(l) = stmt.kind { + if let hir::StmtKind::Let(l) = stmt.kind { self.check_attributes(l.hir_id, stmt.span, Target::Statement, None); } intravisit::walk_stmt(self, stmt) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index be6ba585d2004..d742ffc69e450 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -277,7 +277,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { record_variants!( (self, s, s.kind, Id::Node(s.hir_id), hir, Stmt, StmtKind), - [Local, Item, Expr, Semi] + [Let, Item, Expr, Semi] ); hir_visit::walk_stmt(self, s) } @@ -539,7 +539,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_stmt(&mut self, s: &'v ast::Stmt) { record_variants!( (self, s, s.kind, Id::None, ast, Stmt, StmtKind), - [Local, Item, Expr, Semi, Empty, MacCall] + [Let, Item, Expr, Semi, Empty, MacCall] ); ast_visit::walk_stmt(self, s) } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index e5033e1f51f23..f0c3f7a385d60 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -771,7 +771,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_stmt(&mut self, stmt: &hir::Stmt<'_>, succ: LiveNode) -> LiveNode { match stmt.kind { - hir::StmtKind::Local(local) => { + hir::StmtKind::Let(local) => { // Note: we mark the variable as defined regardless of whether // there is an initializer. Initially I had thought to only mark // the live variable as defined if it was initialized, and then we diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 27c9c1306e6ac..bd34b0597e255 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -280,7 +280,7 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { match stmt.kind { StmtKind::Item(..) => {} - StmtKind::Local(..) => { + StmtKind::Let(..) => { self.items.push((ItemKind::NonAsm, stmt.span)); } StmtKind::Expr(expr) | StmtKind::Semi(expr) => { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index bf1ea2e270932..f6004fed8284e 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -23,18 +23,19 @@ // - `check_unused` finally emits the diagnostics based on the data generated // in the last step -use crate::imports::ImportKind; +use crate::imports::{Import, ImportKind}; use crate::module_to_string; use crate::Resolver; -use crate::NameBindingKind; +use crate::{LexicalScopeBinding, NameBindingKind}; use rustc_ast as ast; use rustc_ast::visit::{self, Visitor}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; use rustc_hir::def::{DefKind, Res}; -use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS}; +use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES}; +use rustc_session::lint::builtin::{UNUSED_IMPORTS, UNUSED_QUALIFICATIONS}; use rustc_session::lint::BuiltinLintDiag; use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, DUMMY_SP}; @@ -514,8 +515,59 @@ impl Resolver<'_, '_> { } } + let mut redundant_imports = UnordSet::default(); for import in check_redundant_imports { - self.check_for_redundant_imports(import); + if self.check_for_redundant_imports(import) + && let Some(id) = import.id() + { + redundant_imports.insert(id); + } + } + + // The lint fixes for unused_import and unnecessary_qualification may conflict. + // Deleting both unused imports and unnecessary segments of an item may result + // in the item not being found. + for unn_qua in &self.potentially_unnecessary_qualifications { + if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding + && let NameBindingKind::Import { import, .. } = name_binding.kind + && (is_unused_import(import, &unused_imports) + || is_redundant_import(import, &redundant_imports)) + { + continue; + } + + self.lint_buffer.buffer_lint_with_diagnostic( + UNUSED_QUALIFICATIONS, + unn_qua.node_id, + unn_qua.path_span, + "unnecessary qualification", + BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span }, + ); + } + + fn is_redundant_import( + import: Import<'_>, + redundant_imports: &UnordSet, + ) -> bool { + if let Some(id) = import.id() + && redundant_imports.contains(&id) + { + return true; + } + false + } + + fn is_unused_import( + import: Import<'_>, + unused_imports: &FxIndexMap, + ) -> bool { + if let Some(unused_import) = unused_imports.get(&import.root_id) + && let Some(id) = import.id() + && unused_import.unused.contains(&id) + { + return true; + } + false } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index ea08041f2aadd..9bf3e9ccabdf1 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1306,7 +1306,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None } - pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) { + pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) -> bool { // This function is only called for single imports. let ImportKind::Single { source, target, ref source_bindings, ref target_bindings, id, .. @@ -1317,12 +1317,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Skip if the import is of the form `use source as target` and source != target. if source != target { - return; + return false; } // Skip if the import was produced by a macro. if import.parent_scope.expansion != LocalExpnId::ROOT { - return; + return false; } // Skip if we are inside a named module (in contrast to an anonymous @@ -1332,7 +1332,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if import.used.get() == Some(Used::Other) || self.effective_visibilities.is_exported(self.local_def_id(id)) { - return; + return false; } let mut is_redundant = true; @@ -1375,7 +1375,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { format!("the item `{source}` is imported redundantly"), BuiltinLintDiag::RedundantImport(redundant_spans, source), ); + return true; } + + false } fn resolve_glob_import(&mut self, import: Import<'a>) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a996188db0229..c9b5c659f0f47 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -580,6 +580,15 @@ impl MaybeExported<'_> { } } +/// Used for recording UnnecessaryQualification. +#[derive(Debug)] +pub(crate) struct UnnecessaryQualification<'a> { + pub binding: LexicalScopeBinding<'a>, + pub node_id: NodeId, + pub path_span: Span, + pub removal_span: Span, +} + #[derive(Default)] struct DiagMetadata<'ast> { /// The current trait's associated items' ident, used for diagnostic suggestions. @@ -4654,20 +4663,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let ns = if i + 1 == path.len() { ns } else { TypeNS }; let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?; let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?; - - (res == binding.res()).then_some(seg) + (res == binding.res()).then_some((seg, binding)) }); - if let Some(unqualified) = unqualified { - self.r.lint_buffer.buffer_lint_with_diagnostic( - lint::builtin::UNUSED_QUALIFICATIONS, - finalize.node_id, - finalize.path_span, - "unnecessary qualification", - lint::BuiltinLintDiag::UnusedQualifications { - removal_span: path[0].ident.span.until(unqualified.ident.span), - }, - ); + if let Some((seg, binding)) = unqualified { + self.r.potentially_unnecessary_qualifications.push(UnnecessaryQualification { + binding, + node_id: finalize.node_id, + path_span: finalize.path_span, + removal_span: path[0].ident.span.until(seg.ident.span), + }); } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ccb67ea78cfdb..dfc2d029d4cfd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -68,7 +68,7 @@ use std::fmt; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportData, ImportKind, NameResolution}; -use late::{HasGenericParams, PathSource, PatternSource}; +use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::effective_visibilities::EffectiveVisibilitiesVisitor; @@ -372,7 +372,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment { /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that /// items are visible in their whole block, while `Res`es only from the place they are defined /// forward. -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] enum LexicalScopeBinding<'a> { Item(NameBinding<'a>), Res(Res), @@ -1105,6 +1105,8 @@ pub struct Resolver<'a, 'tcx> { potentially_unused_imports: Vec>, + potentially_unnecessary_qualifications: Vec>, + /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility @@ -1464,6 +1466,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { local_macro_def_scopes: FxHashMap::default(), name_already_seen: FxHashMap::default(), potentially_unused_imports: Vec::new(), + potentially_unnecessary_qualifications: Default::default(), struct_constructors: Default::default(), unused_macros: Default::default(), unused_macro_rules: Default::default(), diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index af8c962a2ed6a..42c681e496174 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -111,4 +111,7 @@ session_unleashed_feature_help_unnamed = skipping check that does not even have session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` +session_unsupported_crate_type_for_target = + dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` + session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 5c52ee66128c9..b7ee2c9802541 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -146,7 +146,7 @@ pub enum InstrumentCoverage { /// Individual flag values controlled by `-Z coverage-options`. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct CoverageOptions { - /// Add branch coverage instrumentation (placeholder flag; not yet implemented). + /// Add branch coverage instrumentation. pub branch: bool, } diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 5f04915a9e755..d523da1ad7e38 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -10,7 +10,7 @@ use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; -use crate::parse::ParseSess; +use crate::{config::CrateType, parse::ParseSess}; pub struct FeatureGateError { pub span: MultiSpan, @@ -345,6 +345,13 @@ pub(crate) struct BinaryFloatLiteralNotSupported { pub span: Span, } +#[derive(Diagnostic)] +#[diag(session_unsupported_crate_type_for_target)] +pub struct UnsupportedCrateTypeForTarget<'a> { + pub crate_type: CrateType, + pub target_triple: &'a TargetTriple, +} + pub fn report_lit_error( psess: &ParseSess, err: LitError, diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 74d26237f2463..35cd3cbab66ce 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,7 +1,7 @@ //! Related to out filenames of compilation (e.g. binaries). -use crate::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; +use crate::config::{self, CrateType, Input, OutFileName, OutputFilenames, OutputType}; use crate::errors::{ - CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, + self, CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, InvalidCharacterInCrateName, InvalidCrateNameHelp, }; use crate::Session; @@ -200,3 +200,64 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool false } + +pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[ + (sym::rlib, CrateType::Rlib), + (sym::dylib, CrateType::Dylib), + (sym::cdylib, CrateType::Cdylib), + (sym::lib, config::default_lib_output()), + (sym::staticlib, CrateType::Staticlib), + (sym::proc_dash_macro, CrateType::ProcMacro), + (sym::bin, CrateType::Executable), +]; + +pub fn categorize_crate_type(s: Symbol) -> Option { + Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1) +} + +pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { + // If we're generating a test executable, then ignore all other output + // styles at all other locations + if session.opts.test { + return vec![CrateType::Executable]; + } + + // Only check command line flags if present. If no types are specified by + // command line, then reuse the empty `base` Vec to hold the types that + // will be found in crate attributes. + // JUSTIFICATION: before wrapper fn is available + #[allow(rustc::bad_opt_access)] + let mut base = session.opts.crate_types.clone(); + if base.is_empty() { + let attr_types = attrs.iter().filter_map(|a| { + if a.has_name(sym::crate_type) + && let Some(s) = a.value_str() + { + categorize_crate_type(s) + } else { + None + } + }); + base.extend(attr_types); + if base.is_empty() { + base.push(default_output_for_target(session)); + } else { + base.sort(); + base.dedup(); + } + } + + base.retain(|crate_type| { + if invalid_output_for_target(session, *crate_type) { + session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { + crate_type: *crate_type, + target_triple: &session.opts.target_triple, + }); + false + } else { + true + } + }); + + base +} diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index cb587e28a6c99..486afc5f8f30a 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -633,10 +633,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> { /// If the resulting alignment differs from the type's alignment, /// the argument will be copied to an alloca with sufficient alignment, /// either in the caller (if the type's alignment is lower than the byval alignment) - /// or in the callee† (if the type's alignment is higher than the byval alignment), + /// or in the callee (if the type's alignment is higher than the byval alignment), /// to ensure that Rust code never sees an underaligned pointer. - /// - /// † This is currently broken, see . pub fn make_indirect_byval(&mut self, byval_align: Option) { assert!(!self.layout.is_unsized(), "used byval ABI for unsized layout"); self.make_indirect(); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1241227a5af39..2924a18654444 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -763,7 +763,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?); match self.tcx.parent_hir_node(hir_id) { - hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. }) => { + hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(local), .. }) => { get_name(err, &local.pat.kind) } // Different to previous arm because one is `&hir::Local` and the other diff --git a/library/core/src/time.rs b/library/core/src/time.rs index b533f53993870..78494b866b108 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -856,6 +856,48 @@ impl Duration { (self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32) } + /// Returns the number of milliseconds contained by this `Duration` as `f64`. + /// + /// The returned value does include the fractional (nanosecond) part of the duration. + /// + /// # Examples + /// ``` + /// #![feature(duration_millis_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 345_678_000); + /// assert_eq!(dur.as_millis_f64(), 2345.678); + /// ``` + #[unstable(feature = "duration_millis_float", issue = "122451")] + #[must_use] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + pub const fn as_millis_f64(&self) -> f64 { + (self.secs as f64) * (MILLIS_PER_SEC as f64) + + (self.nanos.0 as f64) / (NANOS_PER_MILLI as f64) + } + + /// Returns the number of milliseconds contained by this `Duration` as `f32`. + /// + /// The returned value does include the fractional (nanosecond) part of the duration. + /// + /// # Examples + /// ``` + /// #![feature(duration_millis_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 345_678_000); + /// assert_eq!(dur.as_millis_f32(), 2345.678); + /// ``` + #[unstable(feature = "duration_millis_float", issue = "122451")] + #[must_use] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + pub const fn as_millis_f32(&self) -> f32 { + (self.secs as f32) * (MILLIS_PER_SEC as f32) + + (self.nanos.0 as f32) / (NANOS_PER_MILLI as f32) + } + /// Creates a new `Duration` from the specified number of seconds represented /// as `f64`. /// diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml index 3371dfa124253..937149f8e86d6 100644 --- a/library/profiler_builtins/Cargo.toml +++ b/library/profiler_builtins/Cargo.toml @@ -13,4 +13,4 @@ core = { path = "../core" } compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [build-dependencies] -cc = "1.0.69" +cc = "1.0.90" diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index e45457b2e42b4..72ea54bd77203 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -39,6 +39,13 @@ pub trait CommandExt: Sealed { /// Sets the child process's user ID. This translates to a /// `setuid` call in the child process. Failure in the `setuid` /// call will cause the spawn to fail. + /// + /// # Notes + /// + /// This will also trigger a call to `setgroups(0, NULL)` in the child + /// process if no groups have been specified. + /// This removes supplementary groups that might have given the child + /// unwanted permissions. #[stable(feature = "rust1", since = "1.0.0")] fn uid(&mut self, id: UserId) -> &mut process::Command; diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 97cbd1929d329..f017d39d804aa 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -330,14 +330,22 @@ impl Command { if let Some(u) = self.get_uid() { // When dropping privileges from root, the `setgroups` call // will remove any extraneous groups. We only drop groups - // if the current uid is 0 and we weren't given an explicit + // if we have CAP_SETGID and we weren't given an explicit // set of groups. If we don't call this, then even though our // uid has dropped, we may still have groups that enable us to // do super-user things. //FIXME: Redox kernel does not support setgroups yet #[cfg(not(target_os = "redox"))] - if libc::getuid() == 0 && self.get_groups().is_none() { - cvt(libc::setgroups(0, crate::ptr::null()))?; + if self.get_groups().is_none() { + let res = cvt(libc::setgroups(0, crate::ptr::null())); + if let Err(e) = res { + // Here we ignore the case of not having CAP_SETGID. + // An alternative would be to require CAP_SETGID (in + // addition to CAP_SETUID) for setting the UID. + if e.raw_os_error() != Some(libc::EPERM) { + return Err(e.into()); + } + } } cvt(libc::setuid(u as uid_t))?; } diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md index 7780f2102ba6b..185a3ba5dbd41 100644 --- a/src/doc/rustc/src/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -352,7 +352,7 @@ This unstable option provides finer control over some aspects of coverage instrumentation. Pass one or more of the following values, separated by commas. - `branch` or `no-branch` - - Placeholder for potential branch coverage support in the future. + - Enables or disables branch coverage instrumentation. ## Other references diff --git a/src/doc/unstable-book/src/compiler-flags/coverage-options.md b/src/doc/unstable-book/src/compiler-flags/coverage-options.md index 105dce6151178..450573cc6c746 100644 --- a/src/doc/unstable-book/src/compiler-flags/coverage-options.md +++ b/src/doc/unstable-book/src/compiler-flags/coverage-options.md @@ -5,4 +5,4 @@ This option controls details of the coverage instrumentation performed by Multiple options can be passed, separated by commas. Valid options are: -- `branch` or `no-branch`: Placeholder for future branch coverage support. +- `branch` or `no-branch`: Enables or disables branch coverage instrumentation. diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 9b36cc00444f3..91ae19acbf7f6 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -52,7 +52,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ .as_ref() .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), |stmt| match &stmt.kind { - StmtKind::Local(_) => true, + StmtKind::Let(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), StmtKind::Item(_) => false, }, diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 247048bbc49da..acdcb54be2719 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -349,7 +349,7 @@ impl BlockEq { /// If the statement is a local, checks if the bound names match the expected list of names. fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { - if let StmtKind::Local(l) = s.kind { + if let StmtKind::Let(l) = s.kind { let mut i = 0usize; let mut res = true; l.pat.each_binding_or_first(&mut |_, _, _, name| { @@ -389,7 +389,7 @@ fn eq_stmts( eq: &mut HirEqInterExpr<'_, '_, '_>, moved_bindings: &mut Vec<(HirId, Symbol)>, ) -> bool { - (if let StmtKind::Local(l) = stmt.kind { + (if let StmtKind::Let(l) = stmt.kind { let old_count = moved_bindings.len(); l.pat.each_binding_or_first(&mut |_, id, _, name| { moved_bindings.push((id, name.name)); @@ -432,7 +432,7 @@ fn scan_block_for_eq<'tcx>( .iter() .enumerate() .find(|&(i, stmt)| { - if let StmtKind::Local(l) = stmt.kind + if let StmtKind::Let(l) = stmt.kind && needs_ordered_drop(cx, cx.typeck_results().node_type(l.hir_id)) { local_needs_ordered_drop = true; @@ -509,7 +509,7 @@ fn scan_block_for_eq<'tcx>( // Clear out all locals seen at the end so far. None of them can be moved. let stmts = &blocks[0].stmts; for stmt in &stmts[stmts.len() - init..=stmts.len() - offset] { - if let StmtKind::Local(l) = stmt.kind { + if let StmtKind::Let(l) = stmt.kind { l.pat.each_binding_or_first(&mut |_, id, _, _| { // FIXME(rust/#120456) - is `swap_remove` correct? eq.locals.swap_remove(&id); diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 8789efcc99444..98a6d9370c344 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find all binding statements like `let mut _ = T::default()` where `T::default()` is the // `default` method of the `Default` trait, and store statement index in current block being // checked and the name of the bound variable - let (local, variant, binding_name, binding_type, span) = if let StmtKind::Local(local) = stmt.kind + let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind // only take `let ...` statements && let Some(expr) = local.init && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 59d2df0295fb4..1d6c4ce72e18b 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { match stmt.kind { // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric` - StmtKind::Local(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())), + StmtKind::Let(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())), _ => self.ty_bounds.push(ExplicitTyBound(false)), } diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index de6073c272360..ebda2ad83870d 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -423,7 +423,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { } }, StmtKind::Expr(e) => self.visit_expr(e), - StmtKind::Local(l) => { + StmtKind::Let(l) => { self.visit_pat(l.pat); if let Some(e) = l.init { self.allow_insert_closure &= !self.in_tail_pos; diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index de048fef5f224..2e9bec6a7b083 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) -> &'tcx ExprKind<'hir> { if let ExprKind::Block(block, _label @ None) = kind && let Block { - stmts: [Stmt { kind: StmtKind::Local(local), .. }], + stmts: [Stmt { kind: StmtKind::Let(local), .. }], expr: Some(expr_end_of_block), rules: BlockCheckMode::DefaultBlock, .. diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 270162ae7717f..f084d89ccc282 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { let mut it = block.stmts.iter().peekable(); while let Some(stmt) = it.next() { if let Some(expr) = it.peek() - && let hir::StmtKind::Local(local) = stmt.kind + && let hir::StmtKind::Let(local) = stmt.kind && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind && let hir::StmtKind::Expr(if_) = expr.kind && let hir::ExprKind::If( diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index 18f799e875a07..a7c1d1bd6cd36 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -410,7 +410,7 @@ fn get_assignments<'a, 'tcx>( stmts .iter() .filter_map(move |stmt| match stmt.kind { - StmtKind::Local(..) | StmtKind::Item(..) => None, + StmtKind::Let(..) | StmtKind::Item(..) => None, StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e), }) .chain(*expr) diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs index ca584a454d035..b00a082bb8cf9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs @@ -72,7 +72,7 @@ fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr } fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) { - if let StmtKind::Local(local) = stmt.kind + if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && is_vec_pop_unwrap(cx, init, is_empty_recv) { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 65d922f03df3a..6cc79440f39a0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -137,7 +137,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t match stmt.kind { StmtKind::Semi(e) | StmtKind::Expr(e) => Some((e, None)), // add the let...else expression (if present) - StmtKind::Local(local) => local.init.map(|init| (init, local.els)), + StmtKind::Let(local) => local.init.map(|init| (init, local.els)), StmtKind::Item(..) => None, } } diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs index 735d704a43cee..93774b8976824 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs @@ -11,7 +11,7 @@ use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { ([stmt, stmts @ ..], expr) => { - if let StmtKind::Local(&Local { + if let StmtKind::Let(&Local { init: Some(e), els: None, .. diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index fdf8fa4e2771f..03e4d668dd8fb 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -53,7 +53,7 @@ impl<'tcx> QuestionMark { return; } - if let StmtKind::Local(local) = stmt.kind + if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && local.els.is_none() && local.ty.is_none() diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 3b82c50a84e62..c9eab7109ebcd 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -138,7 +138,7 @@ fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option< // If block only contains statements, // reduce `{ X; }` to `X` or `X;` match inner_stmt.kind { - hir::StmtKind::Local(local) => Some(local.span), + hir::StmtKind::Let(local) => Some(local.span), hir::StmtKind::Expr(e) => Some(e.span), hir::StmtKind::Semi(..) => Some(inner_stmt.span), hir::StmtKind::Item(..) => None, diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 55050ae693e76..78540353005d3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -424,7 +424,7 @@ fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v> match stmt.kind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)), StmtKind::Item(..) => None, - StmtKind::Local(Local { init, pat, .. }) => { + StmtKind::Let(Local { init, pat, .. }) => { if let PatKind::Binding(_, hir_id, ..) = pat.kind { init.map(|init_expr| (init_expr, Some(hir_id))) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 0e7ad8fc996e5..55cd1a38ec96c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -198,7 +198,7 @@ fn indirect_usage<'tcx>( binding: HirId, ctxt: SyntaxContext, ) -> Option> { - if let StmtKind::Local(&Local { + if let StmtKind::Let(&Local { pat: Pat { kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None), .. diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs index 7b0cf48ac43be..cdfaa690d5f4b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs @@ -27,7 +27,7 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &E fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option { for stmt in statements { - if let StmtKind::Local(local) = stmt.kind + if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind && let hir::def::Res::Local(local_hir_id) = path.res diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index b9784a58596c1..4094d7ded7d82 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !in_external_macro(cx.tcx.sess, stmt.span) - && let StmtKind::Local(local) = stmt.kind + && let StmtKind::Let(local) = stmt.kind && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index a1f7dc7b38c40..12c7c18afde6c 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(local) => { + StmtKind::Let(local) => { if let Local { init: Some(e), .. } = local { DivergenceVisitor { cx }.visit_expr(e); } @@ -291,7 +291,7 @@ fn check_stmt<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, stmt: &'tcx Stmt<'_>) -> St StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr), // If the declaration is of a local variable, check its initializer // expression if it has one. Otherwise, keep going. - StmtKind::Local(local) => local + StmtKind::Let(local) => local .init .as_ref() .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)), diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 3e63c0a1d36e7..4cda4b171e31b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -86,7 +86,7 @@ fn contains_let(cond: &Expr<'_>) -> bool { } fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { - let StmtKind::Local(local) = stmt.kind else { + let StmtKind::Let(local) = stmt.kind else { return false; }; !local.pat.walk_short(|pat| { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index cac34c8ce06e9..43810ec0ec743 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -174,7 +174,7 @@ impl NoEffect { ); return true; } - } else if let StmtKind::Local(local) = stmt.kind { + } else if let StmtKind::Let(local) = stmt.kind { if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) && !matches!(local.source, LocalSource::AsyncFn) && let Some(init) = local.init diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 60ced9c12082d..fbca4329342a9 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -82,7 +82,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]); impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Local(local) = stmt.kind { + if let StmtKind::Let(local) = stmt.kind { if in_external_macro(cx.sess(), local.pat.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index cf7f730140ceb..831c291ed7cc5 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -109,7 +109,7 @@ fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir } fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Local(Local { + if let StmtKind::Let(Local { pat, init: Some(init_expr), els: Some(els), diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 650324d4249eb..d0b37cd92e002 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { return; } - if let StmtKind::Local(local) = stmt.kind + if let StmtKind::Let(local) = stmt.kind && let Local { pat, init: Some(init), .. } = local diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index f61527cc0a9fe..c2673bc409fa8 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { } for w in block.stmts.windows(2) { - if let hir::StmtKind::Local(local) = w[0].kind + if let hir::StmtKind::Let(local) = w[0].kind && let Option::Some(t) = local.init && let hir::ExprKind::Closure { .. } = t.kind && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 2af466d3f51e3..196975274674e 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { // we need both a let-binding stmt and an expr if let Some(retexpr) = block.expr && let Some(stmt) = block.stmts.iter().last() - && let StmtKind::Local(local) = &stmt.kind + && let StmtKind::Let(local) = &stmt.kind && local.ty.is_none() && cx.tcx.hir().attrs(local.hir_id).is_empty() && let Some(initexpr) = &local.init diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index 6c99ccda7ea73..f8726aa173a9b 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -236,7 +236,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx fn manage_has_expensive_expr_after_last_attr(&mut self) { let has_expensive_stmt = match self.ap.curr_stmt.kind { hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false, - hir::StmtKind::Local(local) + hir::StmtKind::Let(local) if let Some(expr) = local.init && let hir::ExprKind::Path(_) = expr.kind => { @@ -290,7 +290,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o }; let mut ac = AttrChecker::new(self.cx, self.seen_types, self.type_cache); if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) { - if let hir::StmtKind::Local(local) = self.ap.curr_stmt.kind + if let hir::StmtKind::Let(local) = self.ap.curr_stmt.kind && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind && !self.ap.apas.contains_key(&hir_id) && { @@ -326,7 +326,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o return; }; match self.ap.curr_stmt.kind { - hir::StmtKind::Local(local) => { + hir::StmtKind::Let(local) => { if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { apa.last_bind_ident = ident; } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 4837f2858a669..ff8e8fe702176 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` // or `Vec::new()` - if let StmtKind::Local(local) = stmt.kind + if let StmtKind::Let(local) = stmt.kind && let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind && let Some(init) = local.init && let Some(size_expr) = Self::as_vec_initializer(cx, init) diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index daa6fe8715ca8..be590aede158d 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -148,7 +148,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { } for [s1, s2, s3] in block.stmts.array_windows::<3>() { - if let StmtKind::Local(tmp) = s1.kind + if let StmtKind::Let(tmp) = s1.kind // let t = foo(); && let Some(tmp_init) = tmp.init && let PatKind::Binding(.., ident, None) = tmp.pat.kind @@ -243,7 +243,7 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< if let ExprKind::Assign(lhs, rhs, _) = expr.kind { return Some((ExprOrIdent::Expr(lhs), rhs)); } - } else if let StmtKind::Local(expr) = stmt.kind { + } else if let StmtKind::Let(expr) = stmt.kind { if let Some(rhs) = expr.init { if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind { return Some((ExprOrIdent::Ident(ident_l), rhs)); diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 559d7ace40edc..0efa65b28e230 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -158,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) { - let (hir::StmtKind::Local(&hir::Local { init: Some(expr), .. }) + let (hir::StmtKind::Let(&hir::Local { init: Some(expr), .. }) | hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr)) = stmt.kind else { @@ -358,7 +358,7 @@ fn block_parents_have_safety_comment( }, Node::Stmt(hir::Stmt { kind: - hir::StmtKind::Local(hir::Local { span, hir_id, .. }) + hir::StmtKind::Let(hir::Local { span, hir_id, .. }) | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. }) | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }), .. diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index fc8519d562835..9ffcfcc0f50cb 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -153,7 +153,7 @@ impl<'tcx> VecLocation<'tcx> { /// or `self` expression for `Vec::reserve()`. fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option> { match stmt.kind { - StmtKind::Local(local) => { + StmtKind::Let(local) => { if let Some(init_expr) = local.init && let PatKind::Binding(_, hir_id, _, None) = local.pat.kind && let Some(init_kind) = get_vec_init_kind(cx, init_expr) diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 6b3ea7700b735..eb64dd633f606 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { /// we need to check them at `check_expr` or `check_block` as they are not stmts /// but we can't check them at `check_expr` because we need the broader context /// because we should do this only for the final expression of the block, and not for - /// `StmtKind::Local` which binds values => the io amount is used. + /// `StmtKind::Let` which binds values => the io amount is used. /// /// To check for unused io amount in stmts, we only consider `StmtKind::Semi`. - /// `StmtKind::Local` is not considered because it binds values => the io amount is used. + /// `StmtKind::Let` is not considered because it binds values => the io amount is used. /// `StmtKind::Expr` is not considered because requires unit type => the io amount is used. /// `StmtKind::Item` is not considered because it's not an expression. /// diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index ba72b3450b933..f1d0c22b1aec1 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { for (idx, stmt) in block.stmts.iter().enumerate() { if !stmt.span.from_expansion() - && let StmtKind::Local(local) = stmt.kind + && let StmtKind::Let(local) = stmt.kind && let PatKind::Binding(_, binding, ident, _) = local.pat.kind && let Some(init) = local.init && !init.span.from_expansion() @@ -197,7 +197,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { }, Node::Stmt(stmt) => { match stmt.kind { - StmtKind::Local(_) | StmtKind::Item(_) => self.found_peek_call = true, + StmtKind::Let(_) | StmtKind::Item(_) => self.found_peek_call = true, StmtKind::Expr(_) | StmtKind::Semi(_) => {}, } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index a0a6382046d02..187bfda129cd7 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -724,7 +724,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } match stmt.value.kind { - StmtKind::Local(local) => { + StmtKind::Let(local) => { bind!(self, local); kind!("Local({local})"); self.option(field!(local.init), "init", |init| { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 3b3939da7b6bc..3874c1169e48c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -267,7 +267,7 @@ pub fn eq_block(l: &Block, r: &Block) -> bool { pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { use StmtKind::*; match (&l.kind, &r.kind) { - (Local(l), Local(r)) => { + (Let(l), Let(r)) => { eq_pat(&l.pat, &r.pat) && both(&l.ty, &r.ty, |l, r| eq_ty(l, r)) && eq_local_kind(&l.kind, &r.kind) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f7f5f7ca35ff0..106d1d0d77f01 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -108,7 +108,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { impl HirEqInterExpr<'_, '_, '_> { pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool { match (&left.kind, &right.kind) { - (&StmtKind::Local(l), &StmtKind::Local(r)) => { + (&StmtKind::Let(l), &StmtKind::Let(r)) => { // This additional check ensures that the type of the locals are equivalent even if the init // expression or type have some inferred parts. if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results { @@ -1030,7 +1030,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&b.kind).hash(&mut self.s); match &b.kind { - StmtKind::Local(local) => { + StmtKind::Let(local) => { self.hash_pat(local.pat); if let Some(init) = local.init { self.hash_expr(init); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 708037a465558..dc0725730322b 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2161,7 +2161,7 @@ pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { Node::Stmt(Stmt { kind: StmtKind::Expr(_) | StmtKind::Semi(_) - | StmtKind::Local(Local { + | StmtKind::Let(Local { pat: Pat { kind: PatKind::Wild, .. diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 4d83547d664e2..83f59837d442c 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -26,7 +26,7 @@ pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] { pub(crate) fn get_span_without_attrs(stmt: &ast::Stmt) -> Span { match stmt.kind { - ast::StmtKind::Local(ref local) => local.span, + ast::StmtKind::Let(ref local) => local.span, ast::StmtKind::Item(ref item) => item.span, ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => expr.span, ast::StmtKind::MacCall(ref mac_stmt) => mac_stmt.mac.span(), diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index 5960b14449948..4aaf7fdb27fb0 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -61,7 +61,7 @@ implement_spanned!(ast::Local); impl Spanned for ast::Stmt { fn span(&self) -> Span { match self.kind { - ast::StmtKind::Local(ref local) => mk_sp(local.span().lo(), self.span.hi()), + ast::StmtKind::Let(ref local) => mk_sp(local.span().lo(), self.span.hi()), ast::StmtKind::Item(ref item) => mk_sp(item.span().lo(), self.span.hi()), ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => { mk_sp(expr.span().lo(), self.span.hi()) diff --git a/src/tools/rustfmt/src/stmt.rs b/src/tools/rustfmt/src/stmt.rs index e3fe4ebca11f1..73a9cce416c18 100644 --- a/src/tools/rustfmt/src/stmt.rs +++ b/src/tools/rustfmt/src/stmt.rs @@ -115,7 +115,7 @@ fn format_stmt( skip_out_of_file_lines_range!(context, stmt.span()); let result = match stmt.kind { - ast::StmtKind::Local(ref local) => local.rewrite(context, shape), + ast::StmtKind::Let(ref local) => local.rewrite(context, shape), ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => { let suffix = if semicolon_for_stmt(context, stmt, is_last_expr) { ";" diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 47f772b485daf..6209b37004bf1 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -150,7 +150,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.visit_item(item); self.last_pos = stmt.span().hi(); } - ast::StmtKind::Local(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => { + ast::StmtKind::Let(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => { let attrs = get_attrs_from_stmt(stmt.as_ast_node()); if contains_skip(attrs) { self.push_skipped_with_span( diff --git a/tests/codegen/align-byval-alignment-mismatch.rs b/tests/codegen/align-byval-alignment-mismatch.rs new file mode 100644 index 0000000000000..306e3ce1358af --- /dev/null +++ b/tests/codegen/align-byval-alignment-mismatch.rs @@ -0,0 +1,126 @@ +// ignore-tidy-linelength +//@ revisions:i686-linux x86_64-linux + +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//@[i686-linux] needs-llvm-components: x86 +//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 + +// Tests that we correctly copy arguments into allocas when the alignment of the byval argument +// is different from the alignment of the Rust type. + +// For the following test cases: +// All of the `*_decreases_alignment` functions should codegen to a direct call, since the +// alignment is already sufficient. +// All off the `*_increases_alignment` functions should copy the argument to an alloca +// on i686-unknown-linux-gnu, since the alignment needs to be increased, and should codegen +// to a direct call on x86_64-unknown-linux-gnu, where byval alignment matches Rust alignment. + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![allow(non_camel_case_types)] + +#[lang = "sized"] +trait Sized {} +#[lang = "freeze"] +trait Freeze {} +#[lang = "copy"] +trait Copy {} + +// This type has align 1 in Rust, but as a byval argument on i686-linux, it will have align 4. +#[repr(C)] +#[repr(packed)] +struct Align1 { + x: u128, + y: u128, + z: u128, +} + +// This type has align 16 in Rust, but as a byval argument on i686-linux, it will have align 4. +#[repr(C)] +#[repr(align(16))] +struct Align16 { + x: u128, + y: u128, + z: u128, +} + +extern "C" { + fn extern_c_align1(x: Align1); + fn extern_c_align16(x: Align16); +} + +// CHECK-LABEL: @rust_to_c_increases_alignment +#[no_mangle] +pub unsafe fn rust_to_c_increases_alignment(x: Align1) { + // i686-linux: start: + // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca %Align1, align 4 + // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 4 {{.*}}[[ALLOCA]], ptr {{.*}}align 1 {{.*}}%x + // i686-linux-NEXT: call void @extern_c_align1({{.+}} [[ALLOCA]]) + + // x86_64-linux: start: + // x86_64-linux-NEXT: call void @extern_c_align1 + extern_c_align1(x); +} + +// CHECK-LABEL: @rust_to_c_decreases_alignment +#[no_mangle] +pub unsafe fn rust_to_c_decreases_alignment(x: Align16) { + // CHECK: start: + // CHECK-NEXT: call void @extern_c_align16 + extern_c_align16(x); +} + +extern "Rust" { + fn extern_rust_align1(x: Align1); + fn extern_rust_align16(x: Align16); +} + +// CHECK-LABEL: @c_to_rust_decreases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_decreases_alignment(x: Align1) { + // CHECK: start: + // CHECK-NEXT: call void @extern_rust_align1 + extern_rust_align1(x); +} + +// CHECK-LABEL: @c_to_rust_increases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_increases_alignment(x: Align16) { + // i686-linux: start: + // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca %Align16, align 16 + // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0 + // i686-linux-NEXT: call void @extern_rust_align16({{.+}} [[ALLOCA]]) + + // x86_64-linux: start: + // x86_64-linux-NEXT: call void @extern_rust_align16 + extern_rust_align16(x); +} + +extern "Rust" { + fn extern_rust_ref_align1(x: &Align1); + fn extern_rust_ref_align16(x: &Align16); +} + +// CHECK-LABEL: @c_to_rust_ref_decreases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_ref_decreases_alignment(x: Align1) { + // CHECK: start: + // CHECK-NEXT: call void @extern_rust_ref_align1 + extern_rust_ref_align1(&x); +} + +// CHECK-LABEL: @c_to_rust_ref_increases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_ref_increases_alignment(x: Align16) { + // i686-linux: start: + // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca %Align16, align 16 + // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0 + // i686-linux-NEXT: call void @extern_rust_ref_align16({{.+}} [[ALLOCA]]) + + // x86_64-linux: start: + // x86_64-linux-NEXT: call void @extern_rust_ref_align16 + extern_rust_ref_align16(&x); +} diff --git a/tests/coverage/branch_generics.cov-map b/tests/coverage/branch_generics.cov-map new file mode 100644 index 0000000000000..719e97efad455 --- /dev/null +++ b/tests/coverage/branch_generics.cov-map @@ -0,0 +1,54 @@ +Function name: branch_generics::print_size::<()> +Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: branch_generics::print_size:: +Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: branch_generics::print_size:: +Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + diff --git a/tests/coverage/branch_generics.coverage b/tests/coverage/branch_generics.coverage new file mode 100644 index 0000000000000..e7cec151ce62c --- /dev/null +++ b/tests/coverage/branch_generics.coverage @@ -0,0 +1,62 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| 3|fn print_size() { + LL| 3| if std::mem::size_of::() > 4 { + ------------------ + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:8): [True: 1, False: 0] + ------------------ + LL| 1| println!("size > 4"); + LL| 2| } else { + LL| 2| println!("size <= 4"); + LL| 2| } + LL| 3|} + ------------------ + | branch_generics::print_size::<()>: + | LL| 1|fn print_size() { + | LL| 1| if std::mem::size_of::() > 4 { + | ------------------ + | | Branch (LL:8): [True: 0, False: 1] + | ------------------ + | LL| 0| println!("size > 4"); + | LL| 1| } else { + | LL| 1| println!("size <= 4"); + | LL| 1| } + | LL| 1|} + ------------------ + | branch_generics::print_size::: + | LL| 1|fn print_size() { + | LL| 1| if std::mem::size_of::() > 4 { + | ------------------ + | | Branch (LL:8): [True: 0, False: 1] + | ------------------ + | LL| 0| println!("size > 4"); + | LL| 1| } else { + | LL| 1| println!("size <= 4"); + | LL| 1| } + | LL| 1|} + ------------------ + | branch_generics::print_size::: + | LL| 1|fn print_size() { + | LL| 1| if std::mem::size_of::() > 4 { + | ------------------ + | | Branch (LL:8): [True: 1, False: 0] + | ------------------ + | LL| 1| println!("size > 4"); + | LL| 1| } else { + | LL| 0| println!("size <= 4"); + | LL| 0| } + | LL| 1|} + ------------------ + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | print_size::<()>(); + LL| | print_size::(); + LL| | print_size::(); + LL| |} + diff --git a/tests/coverage/branch_generics.rs b/tests/coverage/branch_generics.rs new file mode 100644 index 0000000000000..d870ace7006b3 --- /dev/null +++ b/tests/coverage/branch_generics.rs @@ -0,0 +1,19 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch +//@ llvm-cov-flags: --show-branches=count + +fn print_size() { + if std::mem::size_of::() > 4 { + println!("size > 4"); + } else { + println!("size <= 4"); + } +} + +#[coverage(off)] +fn main() { + print_size::<()>(); + print_size::(); + print_size::(); +} diff --git a/tests/coverage/branch_guard.cov-map b/tests/coverage/branch_guard.cov-map new file mode 100644 index 0000000000000..0b3622f6347a8 --- /dev/null +++ b/tests/coverage/branch_guard.cov-map @@ -0,0 +1,32 @@ +Function name: branch_guard::branch_match_guard +Raw bytes (85): 0x[01, 01, 06, 19, 0d, 05, 09, 0f, 15, 13, 11, 17, 0d, 05, 09, 0d, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 17, 03, 0e, 02, 0a, 0b, 04, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 6 +- expression 0 operands: lhs = Counter(6), rhs = Counter(3) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) +- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4) +- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) +- expression 5 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(7)) at (prev + 3, 11) to (start + 0, 12) +- Code(Counter(5)) at (prev + 1, 20) to (start + 2, 10) +- Code(Counter(3)) at (prev + 3, 14) to (start + 0, 15) +- Code(Counter(6)) at (prev + 0, 20) to (start + 0, 25) +- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30) + true = c3 + false = (c6 - c3) +- Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10) +- Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15) +- Code(Counter(7)) at (prev + 0, 20) to (start + 0, 25) +- Branch { true: Counter(4), false: Counter(2) } at (prev + 0, 20) to (start + 0, 30) + true = c4 + false = c2 +- Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10) +- Code(Expression(5, Add)) at (prev + 3, 14) to (start + 2, 10) + = (c1 + c2) +- Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2) + = ((((c1 + c2) + c3) + c4) + c5) + diff --git a/tests/coverage/branch_guard.coverage b/tests/coverage/branch_guard.coverage new file mode 100644 index 0000000000000..f89b965b5d0f7 --- /dev/null +++ b/tests/coverage/branch_guard.coverage @@ -0,0 +1,45 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |macro_rules! no_merge { + LL| | () => { + LL| | for _ in 0..1 {} + LL| | }; + LL| |} + LL| | + LL| 4|fn branch_match_guard(x: Option) { + LL| 4| no_merge!(); + LL| | + LL| 1| match x { + LL| 1| Some(0) => { + LL| 1| println!("zero"); + LL| 1| } + LL| 3| Some(x) if x % 2 == 0 => { + ^2 + ------------------ + | Branch (LL:20): [True: 2, False: 1] + ------------------ + LL| 2| println!("is nonzero and even"); + LL| 2| } + LL| 1| Some(x) if x % 3 == 0 => { + ------------------ + | Branch (LL:20): [True: 1, False: 0] + ------------------ + LL| 1| println!("is nonzero and odd, but divisible by 3"); + LL| 1| } + LL| 0| _ => { + LL| 0| println!("something else"); + LL| 0| } + LL| | } + LL| 4|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | branch_match_guard(Some(0)); + LL| | branch_match_guard(Some(2)); + LL| | branch_match_guard(Some(6)); + LL| | branch_match_guard(Some(3)); + LL| |} + diff --git a/tests/coverage/branch_guard.rs b/tests/coverage/branch_guard.rs new file mode 100644 index 0000000000000..fa049e6206dc5 --- /dev/null +++ b/tests/coverage/branch_guard.rs @@ -0,0 +1,37 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch +//@ llvm-cov-flags: --show-branches=count + +macro_rules! no_merge { + () => { + for _ in 0..1 {} + }; +} + +fn branch_match_guard(x: Option) { + no_merge!(); + + match x { + Some(0) => { + println!("zero"); + } + Some(x) if x % 2 == 0 => { + println!("is nonzero and even"); + } + Some(x) if x % 3 == 0 => { + println!("is nonzero and odd, but divisible by 3"); + } + _ => { + println!("something else"); + } + } +} + +#[coverage(off)] +fn main() { + branch_match_guard(Some(0)); + branch_match_guard(Some(2)); + branch_match_guard(Some(6)); + branch_match_guard(Some(3)); +} diff --git a/tests/coverage/branch_if.cov-map b/tests/coverage/branch_if.cov-map new file mode 100644 index 0000000000000..0dbfd92541b03 --- /dev/null +++ b/tests/coverage/branch_if.cov-map @@ -0,0 +1,188 @@ +Function name: branch_if::branch_and +Raw bytes (56): 0x[01, 01, 04, 05, 09, 0d, 02, 11, 0f, 0d, 02, 08, 01, 2b, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 00, 0d, 00, 0e, 20, 11, 0d, 00, 0d, 00, 0e, 11, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Counter(3), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Counter(4), rhs = Expression(3, Add) +- expression 3 operands: lhs = Counter(3), rhs = Expression(0, Sub) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 43, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9) +- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) + true = c2 + false = (c1 - c2) +- Code(Counter(2)) at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(4), false: Counter(3) } at (prev + 0, 13) to (start + 0, 14) + true = c4 + false = c3 +- Code(Counter(4)) at (prev + 0, 15) to (start + 2, 6) +- Code(Expression(3, Add)) at (prev + 2, 12) to (start + 2, 6) + = (c3 + (c1 - c2)) +- Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c4 + (c3 + (c1 - c2))) + +Function name: branch_if::branch_not +Raw bytes (224): 0x[01, 01, 29, 05, 09, 09, 02, a3, 01, 0d, 09, 02, a3, 01, 0d, 09, 02, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 15, 8e, 01, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, a3, 01, 01, 08, 00, 0a, 20, 9e, 01, 0d, 00, 08, 00, 0a, 9e, 01, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 9b, 01, 01, 08, 00, 0b, 20, 11, 96, 01, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 96, 01, 02, 06, 00, 07, 93, 01, 01, 08, 00, 0c, 20, 8e, 01, 15, 00, 08, 00, 0c, 8e, 01, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 8b, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 41 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 4 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 6 operands: lhs = Counter(3), rhs = Expression(39, Sub) +- expression 7 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 9 operands: lhs = Expression(38, Add), rhs = Counter(4) +- expression 10 operands: lhs = Counter(3), rhs = Expression(39, Sub) +- expression 11 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 13 operands: lhs = Expression(38, Add), rhs = Counter(4) +- expression 14 operands: lhs = Counter(3), rhs = Expression(39, Sub) +- expression 15 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 17 operands: lhs = Counter(4), rhs = Expression(37, Sub) +- expression 18 operands: lhs = Expression(38, Add), rhs = Counter(4) +- expression 19 operands: lhs = Counter(3), rhs = Expression(39, Sub) +- expression 20 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 22 operands: lhs = Expression(36, Add), rhs = Counter(5) +- expression 23 operands: lhs = Counter(4), rhs = Expression(37, Sub) +- expression 24 operands: lhs = Expression(38, Add), rhs = Counter(4) +- expression 25 operands: lhs = Counter(3), rhs = Expression(39, Sub) +- expression 26 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 27 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 28 operands: lhs = Expression(36, Add), rhs = Counter(5) +- expression 29 operands: lhs = Counter(4), rhs = Expression(37, Sub) +- expression 30 operands: lhs = Expression(38, Add), rhs = Counter(4) +- expression 31 operands: lhs = Counter(3), rhs = Expression(39, Sub) +- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 33 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 34 operands: lhs = Counter(5), rhs = Expression(35, Sub) +- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(5) +- expression 36 operands: lhs = Counter(4), rhs = Expression(37, Sub) +- expression 37 operands: lhs = Expression(38, Add), rhs = Counter(4) +- expression 38 operands: lhs = Counter(3), rhs = Expression(39, Sub) +- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(3) +- expression 40 operands: lhs = Counter(2), rhs = Expression(0, Sub) +Number of file 0 mappings: 18 +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9) +- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) + true = c2 + false = (c1 - c2) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 0, 7) + = (c1 - c2) +- Code(Expression(40, Add)) at (prev + 1, 8) to (start + 0, 10) + = (c2 + (c1 - c2)) +- Branch { true: Expression(39, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10) + true = ((c2 + (c1 - c2)) - c3) + false = c3 +- Code(Expression(39, Sub)) at (prev + 0, 11) to (start + 2, 6) + = ((c2 + (c1 - c2)) - c3) +- Code(Counter(3)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(38, Add)) at (prev + 1, 8) to (start + 0, 11) + = (c3 + ((c2 + (c1 - c2)) - c3)) +- Branch { true: Counter(4), false: Expression(37, Sub) } at (prev + 0, 8) to (start + 0, 11) + true = c4 + false = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4) +- Code(Counter(4)) at (prev + 0, 12) to (start + 2, 6) +- Code(Expression(37, Sub)) at (prev + 2, 6) to (start + 0, 7) + = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4) +- Code(Expression(36, Add)) at (prev + 1, 8) to (start + 0, 12) + = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) +- Branch { true: Expression(35, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12) + true = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5) + false = c5 +- Code(Expression(35, Sub)) at (prev + 0, 13) to (start + 2, 6) + = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5) +- Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(34, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c5 + ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5)) + +Function name: branch_if::branch_not_as +Raw bytes (124): 0x[01, 01, 16, 05, 09, 09, 02, 57, 0d, 09, 02, 57, 0d, 09, 02, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 11, 4a, 4f, 11, 0d, 52, 57, 0d, 09, 02, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 57, 01, 08, 00, 15, 20, 0d, 52, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 52, 02, 06, 00, 07, 4f, 01, 08, 00, 16, 20, 4a, 11, 00, 08, 00, 16, 4a, 00, 17, 02, 06, 11, 02, 06, 00, 07, 47, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 22 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Expression(21, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 4 operands: lhs = Expression(21, Add), rhs = Counter(3) +- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 6 operands: lhs = Counter(3), rhs = Expression(20, Sub) +- expression 7 operands: lhs = Expression(21, Add), rhs = Counter(3) +- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 9 operands: lhs = Expression(19, Add), rhs = Counter(4) +- expression 10 operands: lhs = Counter(3), rhs = Expression(20, Sub) +- expression 11 operands: lhs = Expression(21, Add), rhs = Counter(3) +- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 13 operands: lhs = Expression(19, Add), rhs = Counter(4) +- expression 14 operands: lhs = Counter(3), rhs = Expression(20, Sub) +- expression 15 operands: lhs = Expression(21, Add), rhs = Counter(3) +- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub) +- expression 17 operands: lhs = Counter(4), rhs = Expression(18, Sub) +- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(4) +- expression 19 operands: lhs = Counter(3), rhs = Expression(20, Sub) +- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(3) +- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 29, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 20) +- Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 0, 8) to (start + 0, 20) + true = (c1 - c2) + false = c2 +- Code(Expression(0, Sub)) at (prev + 0, 21) to (start + 2, 6) + = (c1 - c2) +- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(21, Add)) at (prev + 1, 8) to (start + 0, 21) + = (c2 + (c1 - c2)) +- Branch { true: Counter(3), false: Expression(20, Sub) } at (prev + 0, 8) to (start + 0, 21) + true = c3 + false = ((c2 + (c1 - c2)) - c3) +- Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6) +- Code(Expression(20, Sub)) at (prev + 2, 6) to (start + 0, 7) + = ((c2 + (c1 - c2)) - c3) +- Code(Expression(19, Add)) at (prev + 1, 8) to (start + 0, 22) + = (c3 + ((c2 + (c1 - c2)) - c3)) +- Branch { true: Expression(18, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22) + true = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4) + false = c4 +- Code(Expression(18, Sub)) at (prev + 0, 23) to (start + 2, 6) + = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4) +- Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(17, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) + +Function name: branch_if::branch_or +Raw bytes (56): 0x[01, 01, 04, 05, 09, 09, 0d, 0f, 11, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0f, 00, 0f, 02, 06, 11, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(4) +- expression 3 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 53, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9) +- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) + true = c2 + false = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 14) + = (c1 - c2) +- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 13) to (start + 0, 14) + true = c3 + false = c4 +- Code(Expression(3, Add)) at (prev + 0, 15) to (start + 2, 6) + = (c2 + c3) +- Code(Counter(4)) at (prev + 2, 12) to (start + 2, 6) +- Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) + = ((c2 + c3) + c4) + diff --git a/tests/coverage/branch_if.coverage b/tests/coverage/branch_if.coverage new file mode 100644 index 0000000000000..2a9a408b16aff --- /dev/null +++ b/tests/coverage/branch_if.coverage @@ -0,0 +1,115 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |macro_rules! no_merge { + LL| | () => { + LL| | for _ in 0..1 {} + LL| | }; + LL| |} + LL| | + LL| 3|fn branch_not(a: bool) { + LL| 3| no_merge!(); + LL| | + LL| 3| if a { + ------------------ + | Branch (LL:8): [True: 2, False: 1] + ------------------ + LL| 2| say("a") + LL| 1| } + LL| 3| if !a { + ------------------ + | Branch (LL:8): [True: 1, False: 2] + ------------------ + LL| 1| say("not a"); + LL| 2| } + LL| 3| if !!a { + ------------------ + | Branch (LL:8): [True: 2, False: 1] + ------------------ + LL| 2| say("not not a"); + LL| 2| } + ^1 + LL| 3| if !!!a { + ------------------ + | Branch (LL:8): [True: 1, False: 2] + ------------------ + LL| 1| say("not not not a"); + LL| 2| } + LL| 3|} + LL| | + LL| 3|fn branch_not_as(a: bool) { + LL| 3| no_merge!(); + LL| | + LL| 3| if !(a as bool) { + ------------------ + | Branch (LL:8): [True: 1, False: 2] + ------------------ + LL| 1| say("not (a as bool)"); + LL| 2| } + LL| 3| if !!(a as bool) { + ------------------ + | Branch (LL:8): [True: 2, False: 1] + ------------------ + LL| 2| say("not not (a as bool)"); + LL| 2| } + ^1 + LL| 3| if !!!(a as bool) { + ------------------ + | Branch (LL:8): [True: 1, False: 2] + ------------------ + LL| 1| say("not not (a as bool)"); + LL| 2| } + LL| 3|} + LL| | + LL| 15|fn branch_and(a: bool, b: bool) { + LL| 15| no_merge!(); + LL| | + LL| 15| if a && b { + ^12 + ------------------ + | Branch (LL:8): [True: 12, False: 3] + | Branch (LL:13): [True: 8, False: 4] + ------------------ + LL| 8| say("both"); + LL| 8| } else { + LL| 7| say("not both"); + LL| 7| } + LL| 15|} + LL| | + LL| 15|fn branch_or(a: bool, b: bool) { + LL| 15| no_merge!(); + LL| | + LL| 15| if a || b { + ^3 + ------------------ + | Branch (LL:8): [True: 12, False: 3] + | Branch (LL:13): [True: 2, False: 1] + ------------------ + LL| 14| say("either"); + LL| 14| } else { + LL| 1| say("neither"); + LL| 1| } + LL| 15|} + LL| | + LL| |#[coverage(off)] + LL| |fn say(message: &str) { + LL| | core::hint::black_box(message); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | for a in [false, true, true] { + LL| | branch_not(a); + LL| | branch_not_as(a); + LL| | } + LL| | + LL| | for a in [false, true, true, true, true] { + LL| | for b in [false, true, true] { + LL| | branch_and(a, b); + LL| | branch_or(a, b); + LL| | } + LL| | } + LL| |} + diff --git a/tests/coverage/branch_if.rs b/tests/coverage/branch_if.rs new file mode 100644 index 0000000000000..151eede75bbc7 --- /dev/null +++ b/tests/coverage/branch_if.rs @@ -0,0 +1,81 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch +//@ llvm-cov-flags: --show-branches=count + +macro_rules! no_merge { + () => { + for _ in 0..1 {} + }; +} + +fn branch_not(a: bool) { + no_merge!(); + + if a { + say("a") + } + if !a { + say("not a"); + } + if !!a { + say("not not a"); + } + if !!!a { + say("not not not a"); + } +} + +fn branch_not_as(a: bool) { + no_merge!(); + + if !(a as bool) { + say("not (a as bool)"); + } + if !!(a as bool) { + say("not not (a as bool)"); + } + if !!!(a as bool) { + say("not not (a as bool)"); + } +} + +fn branch_and(a: bool, b: bool) { + no_merge!(); + + if a && b { + say("both"); + } else { + say("not both"); + } +} + +fn branch_or(a: bool, b: bool) { + no_merge!(); + + if a || b { + say("either"); + } else { + say("neither"); + } +} + +#[coverage(off)] +fn say(message: &str) { + core::hint::black_box(message); +} + +#[coverage(off)] +fn main() { + for a in [false, true, true] { + branch_not(a); + branch_not_as(a); + } + + for a in [false, true, true, true, true] { + for b in [false, true, true] { + branch_and(a, b); + branch_or(a, b); + } + } +} diff --git a/tests/coverage/branch_while.cov-map b/tests/coverage/branch_while.cov-map new file mode 100644 index 0000000000000..d5f54f1abea20 --- /dev/null +++ b/tests/coverage/branch_while.cov-map @@ -0,0 +1,98 @@ +Function name: branch_while::while_cond +Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 0c, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 10, 20, 09, 0a, 00, 0b, 00, 10, 09, 00, 11, 02, 06, 0a, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 3 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18) +- Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 16) + = (c1 + c2) +- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 16) + true = c2 + false = ((c1 + c2) - c2) +- Code(Counter(2)) at (prev + 0, 17) to (start + 2, 6) +- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2) + = ((c1 + c2) - c2) + +Function name: branch_while::while_cond_not +Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 15, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 14, 20, 09, 0a, 00, 0b, 00, 14, 09, 00, 15, 02, 06, 0a, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 3 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 21, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18) +- Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 20) + = (c1 + c2) +- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 20) + true = c2 + false = ((c1 + c2) - c2) +- Code(Counter(2)) at (prev + 0, 21) to (start + 2, 6) +- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2) + = ((c1 + c2) - c2) + +Function name: branch_while::while_op_and +Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 11, 0d, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 11, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 0f, 04, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(4), rhs = Counter(3) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 18) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 16) + = (c1 + c2) +- Branch { true: Expression(2, Sub), false: Counter(3) } at (prev + 0, 11) to (start + 0, 16) + true = ((c1 + c2) - c3) + false = c3 +- Code(Expression(2, Sub)) at (prev + 0, 20) to (start + 0, 25) + = ((c1 + c2) - c3) +- Branch { true: Counter(2), false: Counter(4) } at (prev + 0, 20) to (start + 0, 25) + true = c2 + false = c4 +- Code(Counter(2)) at (prev + 0, 26) to (start + 3, 6) +- Code(Expression(3, Add)) at (prev + 4, 1) to (start + 0, 2) + = (c4 + c3) + +Function name: branch_while::while_op_or +Raw bytes (66): 0x[01, 01, 09, 05, 1b, 09, 0d, 03, 09, 03, 09, 22, 0d, 03, 09, 09, 0d, 22, 0d, 03, 09, 08, 01, 29, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 09, 22, 00, 0b, 00, 10, 22, 00, 14, 00, 19, 20, 0d, 1e, 00, 14, 00, 19, 1b, 00, 1a, 03, 06, 1e, 04, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 9 +- expression 0 operands: lhs = Counter(1), rhs = Expression(6, Add) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 4 operands: lhs = Expression(8, Sub), rhs = Counter(3) +- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 6 operands: lhs = Counter(2), rhs = Counter(3) +- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(3) +- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(2) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 18) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 16) + = (c1 + (c2 + c3)) +- Branch { true: Counter(2), false: Expression(8, Sub) } at (prev + 0, 11) to (start + 0, 16) + true = c2 + false = ((c1 + (c2 + c3)) - c2) +- Code(Expression(8, Sub)) at (prev + 0, 20) to (start + 0, 25) + = ((c1 + (c2 + c3)) - c2) +- Branch { true: Counter(3), false: Expression(7, Sub) } at (prev + 0, 20) to (start + 0, 25) + true = c3 + false = (((c1 + (c2 + c3)) - c2) - c3) +- Code(Expression(6, Add)) at (prev + 0, 26) to (start + 3, 6) + = (c2 + c3) +- Code(Expression(7, Sub)) at (prev + 4, 1) to (start + 0, 2) + = (((c1 + (c2 + c3)) - c2) - c3) + diff --git a/tests/coverage/branch_while.coverage b/tests/coverage/branch_while.coverage new file mode 100644 index 0000000000000..8d9a6c3bc68b7 --- /dev/null +++ b/tests/coverage/branch_while.coverage @@ -0,0 +1,74 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |macro_rules! no_merge { + LL| | () => { + LL| | for _ in 0..1 {} + LL| | }; + LL| |} + LL| | + LL| 1|fn while_cond() { + LL| 1| no_merge!(); + LL| | + LL| 1| let mut a = 8; + LL| 9| while a > 0 { + ------------------ + | Branch (LL:11): [True: 8, False: 1] + ------------------ + LL| 8| a -= 1; + LL| 8| } + LL| 1|} + LL| | + LL| 1|fn while_cond_not() { + LL| 1| no_merge!(); + LL| | + LL| 1| let mut a = 8; + LL| 9| while !(a == 0) { + ------------------ + | Branch (LL:11): [True: 8, False: 1] + ------------------ + LL| 8| a -= 1; + LL| 8| } + LL| 1|} + LL| | + LL| 1|fn while_op_and() { + LL| 1| no_merge!(); + LL| | + LL| 1| let mut a = 8; + LL| 1| let mut b = 4; + LL| 5| while a > 0 && b > 0 { + ------------------ + | Branch (LL:11): [True: 5, False: 0] + | Branch (LL:20): [True: 4, False: 1] + ------------------ + LL| 4| a -= 1; + LL| 4| b -= 1; + LL| 4| } + LL| 1|} + LL| | + LL| 1|fn while_op_or() { + LL| 1| no_merge!(); + LL| | + LL| 1| let mut a = 4; + LL| 1| let mut b = 8; + LL| 9| while a > 0 || b > 0 { + ^5 + ------------------ + | Branch (LL:11): [True: 4, False: 5] + | Branch (LL:20): [True: 4, False: 1] + ------------------ + LL| 8| a -= 1; + LL| 8| b -= 1; + LL| 8| } + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | while_cond(); + LL| | while_cond_not(); + LL| | while_op_and(); + LL| | while_op_or(); + LL| |} + diff --git a/tests/coverage/branch_while.rs b/tests/coverage/branch_while.rs new file mode 100644 index 0000000000000..507815fbecbeb --- /dev/null +++ b/tests/coverage/branch_while.rs @@ -0,0 +1,58 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch +//@ llvm-cov-flags: --show-branches=count + +macro_rules! no_merge { + () => { + for _ in 0..1 {} + }; +} + +fn while_cond() { + no_merge!(); + + let mut a = 8; + while a > 0 { + a -= 1; + } +} + +fn while_cond_not() { + no_merge!(); + + let mut a = 8; + while !(a == 0) { + a -= 1; + } +} + +fn while_op_and() { + no_merge!(); + + let mut a = 8; + let mut b = 4; + while a > 0 && b > 0 { + a -= 1; + b -= 1; + } +} + +fn while_op_or() { + no_merge!(); + + let mut a = 4; + let mut b = 8; + while a > 0 || b > 0 { + a -= 1; + b -= 1; + } +} + +#[coverage(off)] +fn main() { + while_cond(); + while_cond_not(); + while_op_and(); + while_op_or(); +} diff --git a/tests/ui/lint/lint-qualification.fixed b/tests/ui/lint/lint-qualification.fixed index 2b1f8b591752a..6fe6ba2792fe6 100644 --- a/tests/ui/lint/lint-qualification.fixed +++ b/tests/ui/lint/lint-qualification.fixed @@ -1,5 +1,6 @@ //@ run-rustfix #![deny(unused_qualifications)] +#![deny(unused_imports)] #![allow(deprecated, dead_code)] mod foo { @@ -21,8 +22,10 @@ fn main() { //~^ ERROR: unnecessary qualification //~| ERROR: unnecessary qualification - use std::fmt; - let _: fmt::Result = Ok(()); //~ ERROR: unnecessary qualification + + //~^ ERROR: unused import: `std::fmt` + let _: std::fmt::Result = Ok(()); + // don't report unnecessary qualification because fix(#122373) for issue #121331 let _ = ::default(); // issue #121999 //~^ ERROR: unnecessary qualification diff --git a/tests/ui/lint/lint-qualification.rs b/tests/ui/lint/lint-qualification.rs index 002fdbf7724a7..19d339b006c9a 100644 --- a/tests/ui/lint/lint-qualification.rs +++ b/tests/ui/lint/lint-qualification.rs @@ -1,5 +1,6 @@ //@ run-rustfix #![deny(unused_qualifications)] +#![deny(unused_imports)] #![allow(deprecated, dead_code)] mod foo { @@ -22,7 +23,9 @@ fn main() { //~| ERROR: unnecessary qualification use std::fmt; - let _: std::fmt::Result = Ok(()); //~ ERROR: unnecessary qualification + //~^ ERROR: unused import: `std::fmt` + let _: std::fmt::Result = Ok(()); + // don't report unnecessary qualification because fix(#122373) for issue #121331 let _ = ::default(); // issue #121999 //~^ ERROR: unnecessary qualification diff --git a/tests/ui/lint/lint-qualification.stderr b/tests/ui/lint/lint-qualification.stderr index 8dddcf23f7575..9e5c9b2df13f1 100644 --- a/tests/ui/lint/lint-qualification.stderr +++ b/tests/ui/lint/lint-qualification.stderr @@ -1,5 +1,5 @@ error: unnecessary qualification - --> $DIR/lint-qualification.rs:11:5 + --> $DIR/lint-qualification.rs:12:5 | LL | foo::bar(); | ^^^^^^^^ @@ -16,7 +16,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:12:5 + --> $DIR/lint-qualification.rs:13:5 | LL | crate::foo::bar(); | ^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:17:13 + --> $DIR/lint-qualification.rs:18:13 | LL | let _ = std::string::String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let _ = String::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:18:13 + --> $DIR/lint-qualification.rs:19:13 | LL | let _ = ::std::env::current_dir(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + let _ = std::env::current_dir(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:12 + --> $DIR/lint-qualification.rs:21:12 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL + let _: Vec = std::vec::Vec::::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:36 + --> $DIR/lint-qualification.rs:21:36 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,20 +75,20 @@ LL - let _: std::vec::Vec = std::vec::Vec::::new(); LL + let _: std::vec::Vec = Vec::::new(); | -error: unnecessary qualification - --> $DIR/lint-qualification.rs:25:12 - | -LL | let _: std::fmt::Result = Ok(()); - | ^^^^^^^^^^^^^^^^ +error: unused import: `std::fmt` + --> $DIR/lint-qualification.rs:25:9 | -help: remove the unnecessary path segments +LL | use std::fmt; + | ^^^^^^^^ | -LL - let _: std::fmt::Result = Ok(()); -LL + let _: fmt::Result = Ok(()); +note: the lint level is defined here + --> $DIR/lint-qualification.rs:3:9 | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ error: unnecessary qualification - --> $DIR/lint-qualification.rs:27:13 + --> $DIR/lint-qualification.rs:30:13 | LL | let _ = ::default(); // issue #121999 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed new file mode 100644 index 0000000000000..d554bbfcc98c9 --- /dev/null +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed @@ -0,0 +1,50 @@ +//@ run-rustfix +//@ edition:2021 +#![deny(unused_qualifications)] +#![deny(unused_imports)] +#![feature(coroutines, coroutine_trait)] + +use std::ops::{ + Coroutine, + CoroutineState::{self}, + //~^ ERROR unused import: `*` +}; +use std::pin::Pin; + +#[allow(dead_code)] +fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Coroutine<(), Yield = ()> + Unpin, +{ + loop { + match Pin::new(&mut t).resume(()) { + CoroutineState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), + CoroutineState::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } + } + } +} + + +mod foo { + pub fn bar() {} +} + +pub fn main() { + + use foo::bar; + bar(); + //~^ ERROR unnecessary qualification + bar(); + + // The item `use std::string::String` is imported redundantly. + // Suppress `unused_imports` reporting, otherwise the fixed file will report an error + #[allow(unused_imports)] + use std::string::String; + let s = String::new(); + let y = std::string::String::new(); + // unnecessary qualification + println!("{} {}", s, y); + +} diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs new file mode 100644 index 0000000000000..4d79f5ab74530 --- /dev/null +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs @@ -0,0 +1,50 @@ +//@ run-rustfix +//@ edition:2021 +#![deny(unused_qualifications)] +#![deny(unused_imports)] +#![feature(coroutines, coroutine_trait)] + +use std::ops::{ + Coroutine, + CoroutineState::{self, *}, + //~^ ERROR unused import: `*` +}; +use std::pin::Pin; + +#[allow(dead_code)] +fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Coroutine<(), Yield = ()> + Unpin, +{ + loop { + match Pin::new(&mut t).resume(()) { + CoroutineState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), + CoroutineState::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } + } + } +} + + +mod foo { + pub fn bar() {} +} + +pub fn main() { + + use foo::bar; + foo::bar(); + //~^ ERROR unnecessary qualification + bar(); + + // The item `use std::string::String` is imported redundantly. + // Suppress `unused_imports` reporting, otherwise the fixed file will report an error + #[allow(unused_imports)] + use std::string::String; + let s = String::new(); + let y = std::string::String::new(); + // unnecessary qualification + println!("{} {}", s, y); + +} diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr new file mode 100644 index 0000000000000..52ed13ea150d7 --- /dev/null +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr @@ -0,0 +1,31 @@ +error: unused import: `*` + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:9:28 + | +LL | CoroutineState::{self, *}, + | ^ + | +note: the lint level is defined here + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:4:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: unnecessary qualification + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:37:5 + | +LL | foo::bar(); + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:3:9 + | +LL | #![deny(unused_qualifications)] + | ^^^^^^^^^^^^^^^^^^^^^ +help: remove the unnecessary path segments + | +LL - foo::bar(); +LL + bar(); + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed index 8a67b20eec11d..d95faef8ac44b 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed @@ -18,6 +18,16 @@ impl Index for A { } } +// This is used to make `use std::ops::Index;` not unused_import. +// details in fix(#122373) for issue #121331 +pub struct C; +impl Index for C { + type Output = (); + fn index(&self, _: str) -> &Self::Output { + &() + } +} + mod inner { pub trait Trait {} } @@ -29,4 +39,5 @@ use inner::Trait; impl Trait for () {} //~^ ERROR unnecessary qualification +impl Trait for A {} fn main() {} diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs index 528edb331cf55..0eee8f71ad4e1 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs @@ -18,6 +18,16 @@ impl ops::Index for A { } } +// This is used to make `use std::ops::Index;` not unused_import. +// details in fix(#122373) for issue #121331 +pub struct C; +impl Index for C { + type Output = (); + fn index(&self, _: str) -> &Self::Output { + &() + } +} + mod inner { pub trait Trait {} } @@ -29,4 +39,5 @@ use inner::Trait; impl inner::Trait for () {} //~^ ERROR unnecessary qualification +impl Trait for A {} fn main() {} diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr index bcda721071235..e105b754b7195 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr @@ -16,7 +16,7 @@ LL + impl Index for A { | error: unnecessary qualification - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:29:6 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:39:6 | LL | impl inner::Trait for () {} | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/resolve/unused-qualifications-suggestion.fixed b/tests/ui/resolve/unused-qualifications-suggestion.fixed index 6935f611b361f..22e0daea46764 100644 --- a/tests/ui/resolve/unused-qualifications-suggestion.fixed +++ b/tests/ui/resolve/unused-qualifications-suggestion.fixed @@ -16,8 +16,10 @@ fn main() { use foo::bar; bar(); //~^ ERROR unnecessary qualification + bar(); use baz::qux::quux; quux(); //~^ ERROR unnecessary qualification + quux(); } diff --git a/tests/ui/resolve/unused-qualifications-suggestion.rs b/tests/ui/resolve/unused-qualifications-suggestion.rs index b3fe04ff0ea4b..89516c1344a9e 100644 --- a/tests/ui/resolve/unused-qualifications-suggestion.rs +++ b/tests/ui/resolve/unused-qualifications-suggestion.rs @@ -16,8 +16,10 @@ fn main() { use foo::bar; foo::bar(); //~^ ERROR unnecessary qualification + bar(); use baz::qux::quux; baz::qux::quux(); //~^ ERROR unnecessary qualification + quux(); } diff --git a/tests/ui/resolve/unused-qualifications-suggestion.stderr b/tests/ui/resolve/unused-qualifications-suggestion.stderr index e3dac37fc6e22..5b71ba9e2223c 100644 --- a/tests/ui/resolve/unused-qualifications-suggestion.stderr +++ b/tests/ui/resolve/unused-qualifications-suggestion.stderr @@ -16,7 +16,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/unused-qualifications-suggestion.rs:21:5 + --> $DIR/unused-qualifications-suggestion.rs:22:5 | LL | baz::qux::quux(); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index 579a5d5180ef6..dc24833c267c7 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -17,7 +17,7 @@ ast-stats-1 - Fn 96 ( 1.4%) 1 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 ast-stats-1 FieldDef 160 ( 2.4%) 2 80 ast-stats-1 Stmt 160 ( 2.4%) 5 32 -ast-stats-1 - Local 32 ( 0.5%) 1 +ast-stats-1 - Let 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 ast-stats-1 - Expr 96 ( 1.4%) 3 ast-stats-1 Param 160 ( 2.4%) 4 40 @@ -75,7 +75,7 @@ ast-stats-2 - DocComment 32 ( 0.4%) 1 ast-stats-2 - Normal 96 ( 1.3%) 3 ast-stats-2 FieldDef 160 ( 2.2%) 2 80 ast-stats-2 Stmt 160 ( 2.2%) 5 32 -ast-stats-2 - Local 32 ( 0.4%) 1 +ast-stats-2 - Let 32 ( 0.4%) 1 ast-stats-2 - Semi 32 ( 0.4%) 1 ast-stats-2 - Expr 96 ( 1.3%) 3 ast-stats-2 Param 160 ( 2.2%) 4 40 @@ -131,7 +131,7 @@ hir-stats ImplItemRef 72 ( 0.8%) 2 36 hir-stats Arm 80 ( 0.9%) 2 40 hir-stats FieldDef 96 ( 1.1%) 2 48 hir-stats Stmt 96 ( 1.1%) 3 32 -hir-stats - Local 32 ( 0.4%) 1 +hir-stats - Let 32 ( 0.4%) 1 hir-stats - Semi 32 ( 0.4%) 1 hir-stats - Expr 32 ( 0.4%) 1 hir-stats FnDecl 120 ( 1.3%) 3 40