From 784dd22aac3f58eebc73ff54ae0ea43682392e68 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Sat, 25 Jul 2020 15:15:12 -0500 Subject: [PATCH 01/10] add `unsigned_abs` to signed integers --- library/core/src/num/mod.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 048c9c5ddaaee..eb50dc28b9f11 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1601,6 +1601,29 @@ $EndFeature, " } } + doc_comment! { + concat!("Computes the absolute value of `self` without any wrapping +or panicking. + + +# Examples + +Basic usage: + +``` +", $Feature, "#![feature(unsigned_abs)] +assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-128i8).unsigned_abs(), 128u8);", +$EndFeature, " +```"), + #[unstable(feature = "unsigned_abs", issue = "74913")] + #[inline] + pub const fn unsigned_abs(self) -> $UnsignedT { + self.wrapping_abs() as $UnsignedT + } + } + doc_comment! { concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, wrapping around at the boundary of the type. From 35d6a2ef2ba71d5ea120c2879825968babcf9a89 Mon Sep 17 00:00:00 2001 From: Lukas Wirth <lukastw97@gmail.com> Date: Sun, 2 Aug 2020 16:30:09 +0200 Subject: [PATCH 02/10] Lint path statements to use drop for drop types --- src/librustc_lint/unused.rs | 20 ++++++++++++++++++-- src/test/ui/warn-path-statement.rs | 13 ++++++++++++- src/test/ui/warn-path-statement.stderr | 16 ++++++++++++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 8d8fb8c3c6098..ee4361ce16b62 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -275,10 +275,26 @@ declare_lint_pass!(PathStatements => [PATH_STATEMENTS]); impl<'tcx> LateLintPass<'tcx> for PathStatements { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { - if let hir::StmtKind::Semi(ref expr) = s.kind { + if let hir::StmtKind::Semi(expr) = s.kind { if let hir::ExprKind::Path(_) = expr.kind { cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| { - lint.build("path statement with no effect").emit() + let ty = cx.typeck_results().expr_ty(expr); + if ty.needs_drop(cx.tcx, cx.param_env) { + let mut lint = lint.build("path statement drops value"); + if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { + lint.span_suggestion( + s.span, + "use `drop` to clarify the intent", + format!("drop({});", snippet), + Applicability::MachineApplicable, + ); + } else { + lint.span_help(s.span, "use `drop` to clarify the intent"); + } + lint.emit() + } else { + lint.build("path statement with no effect").emit() + } }); } } diff --git a/src/test/ui/warn-path-statement.rs b/src/test/ui/warn-path-statement.rs index e8525f8b892d6..2435be623f310 100644 --- a/src/test/ui/warn-path-statement.rs +++ b/src/test/ui/warn-path-statement.rs @@ -1,6 +1,17 @@ // compile-flags: -D path-statements -fn main() { +struct Droppy; + +impl Drop for Droppy { + fn drop(&mut self) {} +} +fn main() { let x = 10; x; //~ ERROR path statement with no effect + + let y = Droppy; + y; //~ ERROR path statement drops value + + let z = (Droppy,); + z; //~ ERROR path statement drops value } diff --git a/src/test/ui/warn-path-statement.stderr b/src/test/ui/warn-path-statement.stderr index 30afb99e5f02c..248d2ef299be3 100644 --- a/src/test/ui/warn-path-statement.stderr +++ b/src/test/ui/warn-path-statement.stderr @@ -1,10 +1,22 @@ error: path statement with no effect - --> $DIR/warn-path-statement.rs:5:5 + --> $DIR/warn-path-statement.rs:10:5 | LL | x; | ^^ | = note: requested on the command line with `-D path-statements` -error: aborting due to previous error +error: path statement drops value + --> $DIR/warn-path-statement.rs:13:5 + | +LL | y; + | ^^ help: use `drop` to clarify the intent: `drop(y);` + +error: path statement drops value + --> $DIR/warn-path-statement.rs:16:5 + | +LL | z; + | ^^ help: use `drop` to clarify the intent: `drop(z);` + +error: aborting due to 3 previous errors From 532e7f49fc6719528d37f69373aec821b09cd478 Mon Sep 17 00:00:00 2001 From: Stein Somers <git@steinsomers.be> Date: Tue, 28 Jul 2020 14:25:30 +0200 Subject: [PATCH 03/10] Separate off a leafy insert function instead of lying, and split split similarly --- library/alloc/src/collections/btree/node.rs | 86 ++++++++++----------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index b767d9ebed723..c401a47432eb4 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -819,13 +819,13 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar } } -impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::Edge> { + /// Helps implementations of `insert_fit` for a particular `NodeType`, + /// by taking care of leaf data. /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. - /// - /// The returned pointer points to the inserted value. - fn insert_fit(&mut self, key: K, val: V) -> *mut V { + fn leafy_insert_fit(&mut self, key: K, val: V) { // Necessary for correctness, but in a private module debug_assert!(self.node.len() < CAPACITY); @@ -834,11 +834,23 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge slice_insert(self.node.vals_mut(), self.idx, val); (*self.node.as_leaf_mut()).len += 1; - - self.node.vals_mut().get_unchecked_mut(self.idx) } } +} +impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> { + /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// this edge. This method assumes that there is enough space in the node for the new + /// pair to fit. + /// + /// The returned pointer points to the inserted value. + fn insert_fit(&mut self, key: K, val: V) -> *mut V { + self.leafy_insert_fit(key, val); + unsafe { self.node.vals_mut().get_unchecked_mut(self.idx) } + } +} + +impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room. /// @@ -880,14 +892,6 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: } } - /// Unsafely asserts to the compiler some static information about whether the underlying - /// node of this handle is a `Leaf` or an `Internal`. - unsafe fn cast_unchecked<NewType>( - &mut self, - ) -> Handle<NodeRef<marker::Mut<'_>, K, V, NewType>, marker::Edge> { - unsafe { Handle::new_edge(self.node.cast_unchecked(), self.idx) } - } - /// Inserts a new key/value pair and an edge that will go to the right of that new pair /// between this edge and the key/value pair to the right of this edge. This method assumes /// that there is enough space in the node for the new pair to fit. @@ -897,8 +901,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: debug_assert!(edge.height == self.node.height - 1); unsafe { - // This cast is a lie, but it allows us to reuse the key/value insertion logic. - self.cast_unchecked::<marker::Leaf>().insert_fit(key, val); + self.leafy_insert_fit(key, val); slice_insert( slice::from_raw_parts_mut( @@ -994,18 +997,11 @@ impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker } } -impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> { - /// Splits the underlying node into three parts: - /// - /// - The node is truncated to only contain the key/value pairs to the right of - /// this handle. - /// - The key and value pointed to by this handle and extracted. - /// - All the key/value pairs to the right of this handle are put into a newly - /// allocated node. - pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) { +impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> { + /// Helps implementations of `split` for a particular `NodeType`, + /// by taking care of leaf data. + fn leafy_split(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V, usize) { unsafe { - let mut new_node = Box::new(LeafNode::new()); - let k = ptr::read(self.node.keys().get_unchecked(self.idx)); let v = ptr::read(self.node.vals().get_unchecked(self.idx)); @@ -1024,6 +1020,24 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> (*self.node.as_leaf_mut()).len = self.idx as u16; new_node.len = new_len as u16; + (k, v, new_len) + } + } +} + +impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> { + /// Splits the underlying node into three parts: + /// + /// - The node is truncated to only contain the key/value pairs to the right of + /// this handle. + /// - The key and value pointed to by this handle and extracted. + /// - All the key/value pairs to the right of this handle are put into a newly + /// allocated node. + pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) { + unsafe { + let mut new_node = Box::new(LeafNode::new()); + + let (k, v, _) = self.leafy_split(&mut new_node); (self.node, k, v, Root { node: BoxedNode::from_leaf(new_node), height: 0 }) } @@ -1055,31 +1069,15 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: unsafe { let mut new_node = Box::new(InternalNode::new()); - let k = ptr::read(self.node.keys().get_unchecked(self.idx)); - let v = ptr::read(self.node.vals().get_unchecked(self.idx)); - + let (k, v, new_len) = self.leafy_split(&mut new_node.data); let height = self.node.height; - let new_len = self.node.len() - self.idx - 1; - ptr::copy_nonoverlapping( - self.node.keys().as_ptr().add(self.idx + 1), - new_node.data.keys.as_mut_ptr() as *mut K, - new_len, - ); - ptr::copy_nonoverlapping( - self.node.vals().as_ptr().add(self.idx + 1), - new_node.data.vals.as_mut_ptr() as *mut V, - new_len, - ); ptr::copy_nonoverlapping( self.node.as_internal().edges.as_ptr().add(self.idx + 1), new_node.edges.as_mut_ptr(), new_len + 1, ); - (*self.node.as_leaf_mut()).len = self.idx as u16; - new_node.data.len = new_len as u16; - let mut new_root = Root { node: BoxedNode::from_internal(new_node), height }; for i in 0..(new_len + 1) { From e97e6fbe343d0afac795e6c13201ce31047dc219 Mon Sep 17 00:00:00 2001 From: Joshua Nelson <jyn514@gmail.com> Date: Sun, 2 Aug 2020 22:24:54 -0400 Subject: [PATCH 04/10] Fix logging for rustdoc --- src/librustdoc/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 002c5f967105d..4f08452767a87 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -43,7 +43,7 @@ extern crate rustc_trait_selection; extern crate rustc_typeck; extern crate test as testing; #[macro_use] -extern crate log; +extern crate tracing as log; use std::default::Default; use std::env; From 2e5c50195aa0345e174ff9970ec58b7e154c0132 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Mon, 3 Aug 2020 12:18:10 +0900 Subject: [PATCH 05/10] Do not trigger `unused_braces` for `while let` --- src/librustc_lint/unused.rs | 5 ++++- .../issue-74883-unused-paren-baren-yield.rs | 11 ++--------- ...issue-74883-unused-paren-baren-yield.stderr | 18 +++--------------- ...used-braces-while-let-with-mutable-value.rs | 12 ++++++++++++ 4 files changed, 21 insertions(+), 25 deletions(-) create mode 100644 src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index a33f920603592..6a433f4e7c42b 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -520,7 +520,10 @@ trait UnusedDelimLint { (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right)) } - While(ref cond, ref block, ..) => { + // Do not lint `unused_braces` in `while let` expressions. + While(ref cond, ref block, ..) + if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => + { let left = e.span.lo() + rustc_span::BytePos(5); let right = block.span.lo(); (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right)) diff --git a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs index 02182ec299321..8064c3a88d1d9 100644 --- a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs +++ b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs @@ -15,15 +15,8 @@ fn main() { while let Some(_) = ((yield)) {} //~ ERROR: unnecessary parentheses {{yield}}; //~ ERROR: unnecessary braces {( yield )}; //~ ERROR: unnecessary parentheses - - // FIXME: Reduce duplicate warnings. - // Perhaps we should tweak checks in `BlockRetValue`? - while let Some(_) = {(yield)} {} - //~^ ERROR: unnecessary braces - //~| ERROR: unnecessary parentheses - while let Some(_) = {{yield}} {} - //~^ ERROR: unnecessary braces - //~| ERROR: unnecessary braces + while let Some(_) = {(yield)} {} //~ ERROR: unnecessary parentheses + while let Some(_) = {{yield}} {} //~ ERROR: unnecessary braces // FIXME: It'd be great if we could also warn them. ((yield)); diff --git a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr index 267cc9e031a11..3f6260dc6e19e 100644 --- a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr +++ b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr @@ -34,29 +34,17 @@ error: unnecessary parentheses around block return value LL | {( yield )}; | ^^^^^^^^^ help: remove these parentheses -error: unnecessary braces around `let` scrutinee expression - --> $DIR/issue-74883-unused-paren-baren-yield.rs:21:29 - | -LL | while let Some(_) = {(yield)} {} - | ^^^^^^^^^ help: remove these braces - error: unnecessary parentheses around block return value - --> $DIR/issue-74883-unused-paren-baren-yield.rs:21:30 + --> $DIR/issue-74883-unused-paren-baren-yield.rs:18:30 | LL | while let Some(_) = {(yield)} {} | ^^^^^^^ help: remove these parentheses -error: unnecessary braces around `let` scrutinee expression - --> $DIR/issue-74883-unused-paren-baren-yield.rs:24:29 - | -LL | while let Some(_) = {{yield}} {} - | ^^^^^^^^^ help: remove these braces - error: unnecessary braces around block return value - --> $DIR/issue-74883-unused-paren-baren-yield.rs:24:30 + --> $DIR/issue-74883-unused-paren-baren-yield.rs:19:30 | LL | while let Some(_) = {{yield}} {} | ^^^^^^^ help: remove these braces -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs b/src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs new file mode 100644 index 0000000000000..ac547293c583a --- /dev/null +++ b/src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(unused_braces)] + +fn main() { + let mut a = Some(3); + // Shouldn't warn below `a`. + while let Some(ref mut v) = {a} { + a.as_mut().map(|a| std::mem::swap(a, v)); + break; + } +} From d2fc809fdb2e92581a0ecd70dec3e179dbd3439a Mon Sep 17 00:00:00 2001 From: Mark Rousskov <mark.simulacrum@gmail.com> Date: Mon, 3 Aug 2020 10:11:30 -0400 Subject: [PATCH 06/10] Disable building rust-analyzer on riscv64 riscv64 has an LLVM bug that makes rust-analyzer not build. --- src/bootstrap/dist.rs | 74 +++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index a4a1d5193b9b9..98b6be29c073b 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1355,7 +1355,7 @@ pub struct RustAnalyzer { } impl Step for RustAnalyzer { - type Output = PathBuf; + type Output = Option<PathBuf>; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1373,11 +1373,17 @@ impl Step for RustAnalyzer { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Option<PathBuf> { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); + if target.contains("riscv64") { + // riscv64 currently has an LLVM bug that makes rust-analyzer unable + // to build. See #74813 for details. + return None; + } + let src = builder.src.join("src/tools/rust-analyzer"); let release_num = builder.release_num("rust-analyzer/crates/rust-analyzer"); let name = pkgname(builder, "rust-analyzer"); @@ -1431,7 +1437,7 @@ impl Step for RustAnalyzer { builder.info(&format!("Dist rust-analyzer stage{} ({})", compiler.stage, target)); let _time = timeit(builder); builder.run(&mut cmd); - distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)) + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) } } @@ -1789,7 +1795,7 @@ impl Step for Extended { tarballs.push(rustc_installer); tarballs.push(cargo_installer); tarballs.extend(rls_installer.clone()); - tarballs.push(rust_analyzer_installer.clone()); + tarballs.extend(rust_analyzer_installer.clone()); tarballs.push(clippy_installer); tarballs.extend(miri_installer.clone()); tarballs.extend(rustfmt_installer.clone()); @@ -1867,7 +1873,9 @@ impl Step for Extended { if rls_installer.is_none() { contents = filter(&contents, "rls"); } - contents = filter(&contents, "rust-analyzer"); + if rust_analyzer_installer.is_none() { + contents = filter(&contents, "rust-analyzer"); + } if miri_installer.is_none() { contents = filter(&contents, "miri"); } @@ -1914,7 +1922,9 @@ impl Step for Extended { if rls_installer.is_some() { prepare("rls"); } - prepare("rust-analyzer"); + if rust_analyzer_installer.is_some() { + prepare("rust-analyzer"); + } if miri_installer.is_some() { prepare("miri"); } @@ -1976,7 +1986,9 @@ impl Step for Extended { if rls_installer.is_some() { prepare("rls"); } - prepare("rust-analyzer"); + if rust_analyzer_installer.is_some() { + prepare("rust-analyzer"); + } if miri_installer.is_some() { prepare("miri"); } @@ -2076,23 +2088,25 @@ impl Step for Extended { .arg(etc.join("msi/remove-duplicates.xsl")), ); } - builder.run( - Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-analyzer") - .args(&heat_flags) - .arg("-cg") - .arg("RustAnalyzerGroup") - .arg("-dr") - .arg("RustAnalyzer") - .arg("-var") - .arg("var.RustAnalyzerDir") - .arg("-out") - .arg(exe.join("RustAnalyzerGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); + if rust_analyzer_installer.is_some() { + builder.run( + Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rust-analyzer") + .args(&heat_flags) + .arg("-cg") + .arg("RustAnalyzerGroup") + .arg("-dr") + .arg("RustAnalyzer") + .arg("-var") + .arg("var.RustAnalyzerDir") + .arg("-out") + .arg(exe.join("RustAnalyzerGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/remove-duplicates.xsl")), + ); + } builder.run( Command::new(&heat) .current_dir(&exe) @@ -2186,7 +2200,9 @@ impl Step for Extended { if rls_installer.is_some() { cmd.arg("-dRlsDir=rls"); } - cmd.arg("-dRustAnalyzerDir=rust-analyzer"); + if rust_analyzer_installer.is_some() { + cmd.arg("-dRustAnalyzerDir=rust-analyzer"); + } if miri_installer.is_some() { cmd.arg("-dMiriDir=miri"); } @@ -2206,7 +2222,9 @@ impl Step for Extended { if rls_installer.is_some() { candle("RlsGroup.wxs".as_ref()); } - candle("RustAnalyzerGroup.wxs".as_ref()); + if rust_analyzer_installer.is_some() { + candle("RustAnalyzerGroup.wxs".as_ref()); + } if miri_installer.is_some() { candle("MiriGroup.wxs".as_ref()); } @@ -2244,7 +2262,9 @@ impl Step for Extended { if rls_installer.is_some() { cmd.arg("RlsGroup.wixobj"); } - cmd.arg("RustAnalyzerGroup.wixobj"); + if rust_analyzer_installer.is_some() { + cmd.arg("RustAnalyzerGroup.wixobj"); + } if miri_installer.is_some() { cmd.arg("MiriGroup.wixobj"); } From 22161c30e7ab219011c280ca5358bc3acc63b9bd Mon Sep 17 00:00:00 2001 From: Rich Kadel <richkadel@google.com> Date: Sat, 1 Aug 2020 20:03:59 -0700 Subject: [PATCH 07/10] Completes support for coverage in external crates The prior PR corrected for errors encountered when trying to generate the coverage map on source code inlined from external crates (including macros and generics) by avoiding adding external DefIds to the coverage map. This made it possible to generate a coverage report including external crates, but the external crate coverage was incomplete (did not include coverage for the DefIds that were eliminated. The root issue was that the coverage map was converting Span locations to source file and locations, using the SourceMap for the current crate, and this would not work for spans from external crates (compliled with a different SourceMap). The solution was to convert the Spans to filename and location during MIR generation instead, so precompiled external crates would already have the correct source code locations embedded in their MIR, when imported into another crate. --- library/core/src/intrinsics.rs | 36 +++- .../coverageinfo/mapgen.rs | 24 +-- src/librustc_codegen_llvm/coverageinfo/mod.rs | 40 ++-- src/librustc_codegen_llvm/intrinsic.rs | 121 ++++++------ src/librustc_codegen_ssa/coverageinfo/map.rs | 184 ++++-------------- src/librustc_codegen_ssa/coverageinfo/mod.rs | 1 + .../traits/coverageinfo.rs | 15 +- src/librustc_middle/mir/coverage/mod.rs | 21 +- src/librustc_middle/mir/interpret/value.rs | 9 + src/librustc_middle/mir/mod.rs | 29 ++- .../transform/instrument_coverage.rs | 94 +++++---- src/librustc_typeck/check/intrinsic.rs | 39 +++- ...ument_coverage.bar.InstrumentCoverage.diff | 58 ++++-- ...ment_coverage.main.InstrumentCoverage.diff | 90 +++++---- src/test/mir-opt/instrument_coverage.rs | 2 +- 15 files changed, 395 insertions(+), 368 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 44b86438f2a89..3a28bc79effaf 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1950,15 +1950,20 @@ extern "rust-intrinsic" { pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize; /// Internal placeholder for injecting code coverage counters when the "instrument-coverage" - /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code - /// generation. + /// option is enabled. The source code region information is extracted prior to code generation, + /// and added to the "coverage map", which is injected into the generated code as additional + /// data. This intrinsic then triggers the generation of LLVM intrinsic call + /// `instrprof.increment`, using the remaining args (`function_source_hash` and `index`). #[cfg(not(bootstrap))] #[lang = "count_code_region"] pub fn count_code_region( function_source_hash: u64, index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, ); /// Internal marker for code coverage expressions, injected into the MIR when the @@ -1973,8 +1978,11 @@ extern "rust-intrinsic" { index: u32, left_index: u32, right_index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, ); /// This marker identifies a code region and two other counters or counter expressions @@ -1986,14 +1994,24 @@ extern "rust-intrinsic" { index: u32, left_index: u32, right_index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, ); /// This marker identifies a code region to be added to the "coverage map" to indicate source /// code that can never be reached. /// (See `coverage_counter_add` for more information.) - pub fn coverage_unreachable(start_byte_pos: u32, end_byte_pos: u32); + #[cfg(not(bootstrap))] + pub fn coverage_unreachable( + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, + ); /// See documentation of `<*const T>::guaranteed_eq` for details. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] diff --git a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs index 4d9747a43f2e2..9d2383abeed22 100644 --- a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs +++ b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs @@ -92,7 +92,7 @@ impl CoverageMapGenerator { fn write_coverage_mappings( &mut self, expressions: Vec<CounterExpression>, - counter_regions: impl Iterator<Item = (Counter, &'a Region)>, + counter_regions: impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>, coverage_mappings_buffer: &RustString, ) { let mut counter_regions = counter_regions.collect::<Vec<_>>(); @@ -102,7 +102,7 @@ impl CoverageMapGenerator { let mut virtual_file_mapping = Vec::new(); let mut mapping_regions = Vec::new(); - let mut current_file_path = None; + let mut current_file_name = None; let mut current_file_id = 0; // Convert the list of (Counter, Region) pairs to an array of `CounterMappingRegion`, sorted @@ -112,22 +112,22 @@ impl CoverageMapGenerator { // `filenames` array. counter_regions.sort_unstable_by_key(|(_counter, region)| *region); for (counter, region) in counter_regions { - let (file_path, start_line, start_col, end_line, end_col) = region.file_start_and_end(); - let same_file = current_file_path.as_ref().map_or(false, |p| p == file_path); + let Region { file_name, start_line, start_col, end_line, end_col } = *region; + let same_file = current_file_name.as_ref().map_or(false, |p| p == file_name); if !same_file { - if current_file_path.is_some() { + if current_file_name.is_some() { current_file_id += 1; } - current_file_path = Some(file_path.clone()); - let filename = CString::new(file_path.to_string_lossy().to_string()) - .expect("null error converting filename to C string"); - debug!(" file_id: {} = '{:?}'", current_file_id, filename); - let filenames_index = match self.filename_to_index.get(&filename) { + current_file_name = Some(file_name.to_string()); + let c_filename = + CString::new(file_name).expect("null error converting filename to C string"); + debug!(" file_id: {} = '{:?}'", current_file_id, c_filename); + let filenames_index = match self.filename_to_index.get(&c_filename) { Some(index) => *index, None => { let index = self.filenames.len() as u32; - self.filenames.push(filename.clone()); - self.filename_to_index.insert(filename.clone(), index); + self.filenames.push(c_filename.clone()); + self.filename_to_index.insert(c_filename.clone(), index); index } }; diff --git a/src/librustc_codegen_llvm/coverageinfo/mod.rs b/src/librustc_codegen_llvm/coverageinfo/mod.rs index 9d2090eae8f19..7b864e499d1de 100644 --- a/src/librustc_codegen_llvm/coverageinfo/mod.rs +++ b/src/librustc_codegen_llvm/coverageinfo/mod.rs @@ -6,7 +6,7 @@ use crate::common::CodegenCx; use libc::c_uint; use llvm::coverageinfo::CounterMappingRegion; use log::debug; -use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage}; +use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region}; use rustc_codegen_ssa::traits::{ BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods, }; @@ -49,19 +49,18 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { instance: Instance<'tcx>, function_source_hash: u64, id: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ) { debug!( "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={}, \ - byte range {}..{}", - instance, function_source_hash, id, start_byte_pos, end_byte_pos, + at {:?}", + instance, function_source_hash, id, region, ); let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); coverage_regions .entry(instance) .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter(function_source_hash, id, start_byte_pos, end_byte_pos); + .add_counter(function_source_hash, id, region); } fn add_counter_expression_region( @@ -71,43 +70,30 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { lhs: u32, op: ExprKind, rhs: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ) { debug!( "adding counter expression to coverage_regions: instance={:?}, id={}, {} {:?} {}, \ - byte range {}..{}", - instance, id_descending_from_max, lhs, op, rhs, start_byte_pos, end_byte_pos, + at {:?}", + instance, id_descending_from_max, lhs, op, rhs, region, ); let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); coverage_regions .entry(instance) .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter_expression( - id_descending_from_max, - lhs, - op, - rhs, - start_byte_pos, - end_byte_pos, - ); + .add_counter_expression(id_descending_from_max, lhs, op, rhs, region); } - fn add_unreachable_region( - &mut self, - instance: Instance<'tcx>, - start_byte_pos: u32, - end_byte_pos: u32, - ) { + fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>) { debug!( - "adding unreachable code to coverage_regions: instance={:?}, byte range {}..{}", - instance, start_byte_pos, end_byte_pos, + "adding unreachable code to coverage_regions: instance={:?}, at {:?}", + instance, region, ); let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); coverage_regions .entry(instance) .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_unreachable_region(start_byte_pos, end_byte_pos); + .add_unreachable_region(region); } } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 728af7b0a8cd1..c135e29ee35b3 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -13,7 +13,7 @@ use rustc_ast::ast; use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::coverageinfo::ExprKind; +use rustc_codegen_ssa::coverageinfo; use rustc_codegen_ssa::glue; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -93,64 +93,64 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let mut is_codegen_intrinsic = true; // Set `is_codegen_intrinsic` to `false` to bypass `codegen_intrinsic_call()`. - if self.tcx.sess.opts.debugging_opts.instrument_coverage { - // If the intrinsic is from the local MIR, add the coverage information to the Codegen - // context, to be encoded into the local crate's coverage map. - if caller_instance.def_id().is_local() { - // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with - // external crate dependencies, where: - // 1. Both binary and dependent crates are compiled with `-Zinstrument-coverage` - // 2. Only binary is compiled with `-Zinstrument-coverage` - // 3. Only dependent crates are compiled with `-Zinstrument-coverage` - match intrinsic { - sym::count_code_region => { - use coverage::count_code_region_args::*; - self.add_counter_region( - caller_instance, - op_to_u64(&args[FUNCTION_SOURCE_HASH]), - op_to_u32(&args[COUNTER_ID]), - op_to_u32(&args[START_BYTE_POS]), - op_to_u32(&args[END_BYTE_POS]), - ); - } - sym::coverage_counter_add | sym::coverage_counter_subtract => { - use coverage::coverage_counter_expression_args::*; - self.add_counter_expression_region( - caller_instance, - op_to_u32(&args[EXPRESSION_ID]), - op_to_u32(&args[LEFT_ID]), - if intrinsic == sym::coverage_counter_add { - ExprKind::Add - } else { - ExprKind::Subtract - }, - op_to_u32(&args[RIGHT_ID]), - op_to_u32(&args[START_BYTE_POS]), - op_to_u32(&args[END_BYTE_POS]), - ); - } - sym::coverage_unreachable => { - use coverage::coverage_unreachable_args::*; - self.add_unreachable_region( - caller_instance, - op_to_u32(&args[START_BYTE_POS]), - op_to_u32(&args[END_BYTE_POS]), - ); - } - _ => {} - } + // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with + // external crate dependencies, where: + // 1. Both binary and dependent crates are compiled with `-Zinstrument-coverage` + // 2. Only binary is compiled with `-Zinstrument-coverage` + // 3. Only dependent crates are compiled with `-Zinstrument-coverage` + match intrinsic { + sym::count_code_region => { + use coverage::count_code_region_args::*; + self.add_counter_region( + caller_instance, + op_to_u64(&args[FUNCTION_SOURCE_HASH]), + op_to_u32(&args[COUNTER_ID]), + coverageinfo::Region::new( + op_to_str_slice(&args[FILE_NAME]), + op_to_u32(&args[START_LINE]), + op_to_u32(&args[START_COL]), + op_to_u32(&args[END_LINE]), + op_to_u32(&args[END_COL]), + ), + ); } - - // Only the `count_code_region` coverage intrinsic is translated into an actual LLVM - // intrinsic call (local or not); otherwise, set `is_codegen_intrinsic` to `false`. - match intrinsic { - sym::coverage_counter_add - | sym::coverage_counter_subtract - | sym::coverage_unreachable => { - is_codegen_intrinsic = false; - } - _ => {} + sym::coverage_counter_add | sym::coverage_counter_subtract => { + is_codegen_intrinsic = false; + use coverage::coverage_counter_expression_args::*; + self.add_counter_expression_region( + caller_instance, + op_to_u32(&args[EXPRESSION_ID]), + op_to_u32(&args[LEFT_ID]), + if intrinsic == sym::coverage_counter_add { + coverageinfo::ExprKind::Add + } else { + coverageinfo::ExprKind::Subtract + }, + op_to_u32(&args[RIGHT_ID]), + coverageinfo::Region::new( + op_to_str_slice(&args[FILE_NAME]), + op_to_u32(&args[START_LINE]), + op_to_u32(&args[START_COL]), + op_to_u32(&args[END_LINE]), + op_to_u32(&args[END_COL]), + ), + ); } + sym::coverage_unreachable => { + is_codegen_intrinsic = false; + use coverage::coverage_unreachable_args::*; + self.add_unreachable_region( + caller_instance, + coverageinfo::Region::new( + op_to_str_slice(&args[FILE_NAME]), + op_to_u32(&args[START_LINE]), + op_to_u32(&args[START_COL]), + op_to_u32(&args[END_LINE]), + op_to_u32(&args[END_COL]), + ), + ); + } + _ => {} } is_codegen_intrinsic } @@ -215,9 +215,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call(llfn, &[], None) } sym::count_code_region => { - // FIXME(richkadel): The current implementation assumes the MIR for the given - // caller_instance represents a single function. Validate and/or correct if inlining - // and/or monomorphization invalidates these assumptions. let coverageinfo = tcx.coverageinfo(caller_instance.def_id()); let mangled_fn = tcx.symbol_name(caller_instance); let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name)); @@ -2283,6 +2280,10 @@ fn float_type_width(ty: Ty<'_>) -> Option<u64> { } } +fn op_to_str_slice<'tcx>(op: &Operand<'tcx>) -> &'tcx str { + Operand::value_from_const(op).try_to_str_slice().expect("Value is &str") +} + fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 { Operand::scalar_from_const(op).to_u32().expect("Scalar is u32") } diff --git a/src/librustc_codegen_ssa/coverageinfo/map.rs b/src/librustc_codegen_ssa/coverageinfo/map.rs index 72138065a90ba..7f6841f9daa60 100644 --- a/src/librustc_codegen_ssa/coverageinfo/map.rs +++ b/src/librustc_codegen_ssa/coverageinfo/map.rs @@ -3,12 +3,8 @@ pub use super::ffi::*; use rustc_index::vec::IndexVec; use rustc_middle::ty::Instance; use rustc_middle::ty::TyCtxt; -use rustc_span::source_map::{Pos, SourceMap}; -use rustc_span::{BytePos, FileName, Loc, RealFileName}; -use std::cmp::{Ord, Ordering}; -use std::fmt; -use std::path::PathBuf; +use std::cmp::Ord; rustc_index::newtype_index! { pub struct ExpressionOperandId { @@ -38,127 +34,35 @@ rustc_index::newtype_index! { } } -#[derive(Clone, Debug)] -pub struct Region { - start: Loc, - end: Loc, -} - -impl Ord for Region { - fn cmp(&self, other: &Self) -> Ordering { - (&self.start.file.name, &self.start.line, &self.start.col, &self.end.line, &self.end.col) - .cmp(&( - &other.start.file.name, - &other.start.line, - &other.start.col, - &other.end.line, - &other.end.col, - )) - } -} - -impl PartialOrd for Region { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl PartialEq for Region { - fn eq(&self, other: &Self) -> bool { - self.start.file.name == other.start.file.name - && self.start.line == other.start.line - && self.start.col == other.start.col - && self.end.line == other.end.line - && self.end.col == other.end.col - } -} - -impl Eq for Region {} - -impl fmt::Display for Region { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (file_path, start_line, start_col, end_line, end_col) = self.file_start_and_end(); - write!(f, "{:?}:{}:{} - {}:{}", file_path, start_line, start_col, end_line, end_col) - } +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Region<'tcx> { + pub file_name: &'tcx str, + pub start_line: u32, + pub start_col: u32, + pub end_line: u32, + pub end_col: u32, } -impl Region { - pub fn new(source_map: &SourceMap, start_byte_pos: u32, end_byte_pos: u32) -> Self { - let start = source_map.lookup_char_pos(BytePos::from_u32(start_byte_pos)); - let end = source_map.lookup_char_pos(BytePos::from_u32(end_byte_pos)); - assert_eq!( - start.file.name, end.file.name, - "Region start ({} -> {:?}) and end ({} -> {:?}) don't come from the same source file!", - start_byte_pos, start, end_byte_pos, end - ); - Self { start, end } - } - - pub fn file_start_and_end<'a>(&'a self) -> (&'a PathBuf, u32, u32, u32, u32) { - let start = &self.start; - let end = &self.end; - match &start.file.name { - FileName::Real(RealFileName::Named(path)) => ( - path, - start.line as u32, - start.col.to_u32() + 1, - end.line as u32, - end.col.to_u32() + 1, - ), - _ => { - bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name) - } - } +impl<'tcx> Region<'tcx> { + pub fn new( + file_name: &'tcx str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, + ) -> Self { + Self { file_name, start_line, start_col, end_line, end_col } } } #[derive(Clone, Debug)] -pub struct ExpressionRegion { +pub struct ExpressionRegion<'tcx> { lhs: ExpressionOperandId, op: ExprKind, rhs: ExpressionOperandId, - region: Region, + region: Region<'tcx>, } -// FIXME(richkadel): There seems to be a problem computing the file location in -// some cases. I need to investigate this more. When I generate and show coverage -// for the example binary in the crates.io crate `json5format`, I had a couple of -// notable problems: -// -// 1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in -// various comments (not corresponding to rustdoc code), indicating a possible -// problem with the byte_pos-to-source-map implementation. -// -// 2. And (perhaps not related) when I build the aforementioned example binary with: -// `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5` -// and then run that binary with -// `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \ -// some.json5` for some reason the binary generates *TWO* `.profraw` files. One -// named `default.profraw` and the other named `formatjson5.profraw` (the expected -// name, in this case). -// -// 3. I think that if I eliminate regions within a function, their region_ids, -// referenced in expressions, will be wrong? I think the ids are implied by their -// array position in the final coverage map output (IIRC). -// -// 4. I suspect a problem (if not the only problem) is the SourceMap is wrong for some -// region start/end byte positions. Just like I couldn't get the function hash at -// intrinsic codegen time for external crate functions, I think the SourceMap I -// have here only applies to the local crate, and I know I have coverages that -// reference external crates. -// -// I still don't know if I fixed the hash problem correctly. If external crates -// implement the function, can't I use the coverage counters already compiled -// into those external crates? (Maybe not for generics and/or maybe not for -// macros... not sure. But I need to understand this better.) -// -// If the byte range conversion is wrong, fix it. But if it -// is right, then it is possible for the start and end to be in different files. -// Can I do something other than ignore coverages that span multiple files? -// -// If I can resolve this, remove the "Option<>" result type wrapper -// `regions_in_file_order()` accordingly. - /// Collects all of the coverage regions associated with (a) injected counters, (b) counter /// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero), /// for a given Function. Counters and counter expressions have non-overlapping `id`s because they @@ -171,19 +75,17 @@ pub struct ExpressionRegion { /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count /// for a gap area is only used as the line execution count if there are no other regions on a /// line." -pub struct FunctionCoverage<'a> { - source_map: &'a SourceMap, +pub struct FunctionCoverage<'tcx> { source_hash: u64, - counters: IndexVec<CounterValueReference, Option<Region>>, - expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion>>, - unreachable_regions: Vec<Region>, + counters: IndexVec<CounterValueReference, Option<Region<'tcx>>>, + expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion<'tcx>>>, + unreachable_regions: Vec<Region<'tcx>>, } -impl<'a> FunctionCoverage<'a> { - pub fn new<'tcx: 'a>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { +impl<'tcx> FunctionCoverage<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { let coverageinfo = tcx.coverageinfo(instance.def_id()); Self { - source_map: tcx.sess.source_map(), source_hash: 0, // will be set with the first `add_counter()` counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize), expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize), @@ -194,20 +96,14 @@ impl<'a> FunctionCoverage<'a> { /// Adds a code region to be counted by an injected counter intrinsic. /// The source_hash (computed during coverage instrumentation) should also be provided, and /// should be the same for all counters in a given function. - pub fn add_counter( - &mut self, - source_hash: u64, - id: u32, - start_byte_pos: u32, - end_byte_pos: u32, - ) { + pub fn add_counter(&mut self, source_hash: u64, id: u32, region: Region<'tcx>) { if self.source_hash == 0 { self.source_hash = source_hash; } else { debug_assert_eq!(source_hash, self.source_hash); } self.counters[CounterValueReference::from(id)] - .replace(Region::new(self.source_map, start_byte_pos, end_byte_pos)) + .replace(region) .expect_none("add_counter called with duplicate `id`"); } @@ -231,8 +127,7 @@ impl<'a> FunctionCoverage<'a> { lhs: u32, op: ExprKind, rhs: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ) { let expression_id = ExpressionOperandId::from(id_descending_from_max); let lhs = ExpressionOperandId::from(lhs); @@ -240,18 +135,13 @@ impl<'a> FunctionCoverage<'a> { let expression_index = self.expression_index(expression_id); self.expressions[expression_index] - .replace(ExpressionRegion { - lhs, - op, - rhs, - region: Region::new(self.source_map, start_byte_pos, end_byte_pos), - }) + .replace(ExpressionRegion { lhs, op, rhs, region }) .expect_none("add_counter_expression called with duplicate `id_descending_from_max`"); } /// Add a region that will be marked as "unreachable", with a constant "zero counter". - pub fn add_unreachable_region(&mut self, start_byte_pos: u32, end_byte_pos: u32) { - self.unreachable_regions.push(Region::new(self.source_map, start_byte_pos, end_byte_pos)); + pub fn add_unreachable_region(&mut self, region: Region<'tcx>) { + self.unreachable_regions.push(region) } /// Return the source hash, generated from the HIR node structure, and used to indicate whether @@ -264,8 +154,8 @@ impl<'a> FunctionCoverage<'a> { /// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create /// `CounterMappingRegion`s. pub fn get_expressions_and_counter_regions( - &'a self, - ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a Region)>) { + &'tcx self, + ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>) { assert!(self.source_hash != 0); let counter_regions = self.counter_regions(); @@ -277,7 +167,7 @@ impl<'a> FunctionCoverage<'a> { (counter_expressions, counter_regions) } - fn counter_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> { + fn counter_regions(&'tcx self) -> impl Iterator<Item = (Counter, &'tcx Region<'tcx>)> { self.counters.iter_enumerated().filter_map(|(index, entry)| { // Option::map() will return None to filter out missing counters. This may happen // if, for example, a MIR-instrumented counter is removed during an optimization. @@ -288,8 +178,8 @@ impl<'a> FunctionCoverage<'a> { } fn expressions_with_regions( - &'a self, - ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a Region)>) { + &'tcx self, + ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>) { let mut counter_expressions = Vec::with_capacity(self.expressions.len()); let mut expression_regions = Vec::with_capacity(self.expressions.len()); let mut new_indexes = @@ -350,7 +240,7 @@ impl<'a> FunctionCoverage<'a> { (counter_expressions, expression_regions.into_iter()) } - fn unreachable_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> { + fn unreachable_regions(&'tcx self) -> impl Iterator<Item = (Counter, &'tcx Region<'tcx>)> { self.unreachable_regions.iter().map(|region| (Counter::zero(), region)) } diff --git a/src/librustc_codegen_ssa/coverageinfo/mod.rs b/src/librustc_codegen_ssa/coverageinfo/mod.rs index 1f0ffd289b13a..ff794a75c360d 100644 --- a/src/librustc_codegen_ssa/coverageinfo/mod.rs +++ b/src/librustc_codegen_ssa/coverageinfo/mod.rs @@ -2,3 +2,4 @@ pub mod ffi; pub mod map; pub use map::ExprKind; +pub use map::Region; diff --git a/src/librustc_codegen_ssa/traits/coverageinfo.rs b/src/librustc_codegen_ssa/traits/coverageinfo.rs index db1d86c974ea8..2b5878f46bc43 100644 --- a/src/librustc_codegen_ssa/traits/coverageinfo.rs +++ b/src/librustc_codegen_ssa/traits/coverageinfo.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use crate::coverageinfo::ExprKind; +use crate::coverageinfo::{ExprKind, Region}; use rustc_middle::ty::Instance; pub trait CoverageInfoMethods: BackendTypes { @@ -12,8 +12,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { instance: Instance<'tcx>, function_source_hash: u64, index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ); fn add_counter_expression_region( @@ -23,14 +22,8 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { lhs: u32, op: ExprKind, rhs: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ); - fn add_unreachable_region( - &mut self, - instance: Instance<'tcx>, - start_byte_pos: u32, - end_byte_pos: u32, - ); + fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>); } diff --git a/src/librustc_middle/mir/coverage/mod.rs b/src/librustc_middle/mir/coverage/mod.rs index 82365ef6a73de..6b1514da6441d 100644 --- a/src/librustc_middle/mir/coverage/mod.rs +++ b/src/librustc_middle/mir/coverage/mod.rs @@ -4,8 +4,11 @@ pub mod count_code_region_args { pub const FUNCTION_SOURCE_HASH: usize = 0; pub const COUNTER_ID: usize = 1; - pub const START_BYTE_POS: usize = 2; - pub const END_BYTE_POS: usize = 3; + pub const FILE_NAME: usize = 2; + pub const START_LINE: usize = 3; + pub const START_COL: usize = 4; + pub const END_LINE: usize = 5; + pub const END_COL: usize = 6; } /// Positional arguments to `libcore::coverage_counter_add()` and @@ -14,12 +17,18 @@ pub mod coverage_counter_expression_args { pub const EXPRESSION_ID: usize = 0; pub const LEFT_ID: usize = 1; pub const RIGHT_ID: usize = 2; - pub const START_BYTE_POS: usize = 3; - pub const END_BYTE_POS: usize = 4; + pub const FILE_NAME: usize = 3; + pub const START_LINE: usize = 4; + pub const START_COL: usize = 5; + pub const END_LINE: usize = 6; + pub const END_COL: usize = 7; } /// Positional arguments to `libcore::coverage_unreachable()` pub mod coverage_unreachable_args { - pub const START_BYTE_POS: usize = 0; - pub const END_BYTE_POS: usize = 1; + pub const FILE_NAME: usize = 0; + pub const START_LINE: usize = 1; + pub const START_COL: usize = 2; + pub const END_LINE: usize = 3; + pub const END_COL: usize = 4; } diff --git a/src/librustc_middle/mir/interpret/value.rs b/src/librustc_middle/mir/interpret/value.rs index 2c76f0b5ad022..b4e7a5b98e33b 100644 --- a/src/librustc_middle/mir/interpret/value.rs +++ b/src/librustc_middle/mir/interpret/value.rs @@ -56,6 +56,15 @@ impl<'tcx> ConstValue<'tcx> { } } + pub fn try_to_str_slice(&self) -> Option<&'tcx str> { + if let ConstValue::Slice { data, start, end } = *self { + ::std::str::from_utf8(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) + .ok() + } else { + None + } + } + pub fn try_to_bits(&self, size: Size) -> Option<u128> { self.try_to_scalar()?.to_bits(size).ok() } diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 31b8de500e030..3b0c480f6d400 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -2,7 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html -use crate::mir::interpret::{GlobalAlloc, Scalar}; +use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -1842,6 +1842,33 @@ impl<'tcx> Operand<'tcx> { } } + /// Convenience helper to make a literal-like constant from a given `&str` slice. + /// Since this is used to synthesize MIR, assumes `user_ty` is None. + pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> { + let tcx = tcx; + let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes()); + let allocation = tcx.intern_const_alloc(allocation); + let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() }; + let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_); + Operand::Constant(box Constant { + span, + user_ty: None, + literal: ty::Const::from_value(tcx, const_val, ty), + }) + } + + /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand` + /// wraps a constant value (such as a `&str` slice). Panics if this is not the case. + pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> { + match operand { + Operand::Constant(constant) => match constant.literal.val.try_to_value() { + Some(const_value) => const_value, + _ => panic!("{:?}: ConstValue expected", constant.literal.val), + }, + _ => panic!("{:?}: Constant expected", operand), + } + } + pub fn to_copy(&self) -> Self { match *self { Operand::Copy(_) | Operand::Constant(_) => self.clone(), diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs index fe63a67fdbb34..5b2954dd5b0a3 100644 --- a/src/librustc_mir/transform/instrument_coverage.rs +++ b/src/librustc_mir/transform/instrument_coverage.rs @@ -5,18 +5,19 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::lang_items; use rustc_middle::hir; use rustc_middle::ich::StableHashingContext; +use rustc_middle::mir; use rustc_middle::mir::coverage::*; use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::traversal; use rustc_middle::mir::{ - self, traversal, BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo, - SourceScope, StatementKind, Terminator, TerminatorKind, + BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo, SourceScope, + StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::FnDef; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{FnDef, TyCtxt}; use rustc_span::def_id::DefId; -use rustc_span::{Pos, Span}; +use rustc_span::{FileName, Pos, RealFileName, Span}; /// Inserts call to count_code_region() as a placeholder to be replaced during code generation with /// the intrinsic llvm.instrprof.increment. @@ -112,6 +113,7 @@ enum Op { struct InjectedCall<'tcx> { func: Operand<'tcx>, args: Vec<Operand<'tcx>>, + span: Span, inject_at: Span, } @@ -179,12 +181,11 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let _ignore = mir_body; let id = self.next_counter(); let function_source_hash = self.function_source_hash(); - let code_region = body_span; let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE; let is_cleanup = false; let next_block = rustc_middle::mir::START_BLOCK; self.inject_call( - self.make_counter(id, function_source_hash, code_region), + self.make_counter(id, function_source_hash, body_span), scope, is_cleanup, next_block, @@ -201,14 +202,13 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let op = if add { Op::Add } else { Op::Subtract }; let rhs = 2; - let code_region = body_span; let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE; let is_cleanup = false; let next_block = rustc_middle::mir::START_BLOCK; let id = self.next_expression(); self.inject_call( - self.make_expression(id, code_region, lhs, op, rhs), + self.make_expression(id, body_span, lhs, op, rhs), scope, is_cleanup, next_block, @@ -216,13 +216,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { } } - fn make_counter( - &self, - id: u32, - function_source_hash: u64, - code_region: Span, - ) -> InjectedCall<'tcx> { - let inject_at = code_region.shrink_to_lo(); + fn make_counter(&self, id: u32, function_source_hash: u64, span: Span) -> InjectedCall<'tcx> { + let inject_at = span.shrink_to_lo(); let func = function_handle( self.tcx, @@ -239,24 +234,18 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { debug_assert_eq!(COUNTER_ID, args.len()); args.push(self.const_u32(id, inject_at)); - debug_assert_eq!(START_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.lo().to_u32(), inject_at)); - - debug_assert_eq!(END_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.hi().to_u32(), inject_at)); - - InjectedCall { func, args, inject_at } + InjectedCall { func, args, span, inject_at } } fn make_expression( &self, id: u32, - code_region: Span, + span: Span, lhs: u32, op: Op, rhs: u32, ) -> InjectedCall<'tcx> { - let inject_at = code_region.shrink_to_lo(); + let inject_at = span.shrink_to_lo(); let func = function_handle( self.tcx, @@ -282,13 +271,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { debug_assert_eq!(RIGHT_ID, args.len()); args.push(self.const_u32(rhs, inject_at)); - debug_assert_eq!(START_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.lo().to_u32(), inject_at)); - - debug_assert_eq!(END_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.hi().to_u32(), inject_at)); - - InjectedCall { func, args, inject_at } + InjectedCall { func, args, span, inject_at } } fn inject_call( @@ -298,7 +281,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { is_cleanup: bool, next_block: BasicBlock, ) { - let InjectedCall { func, args, inject_at } = call; + let InjectedCall { func, mut args, span, inject_at } = call; debug!( " injecting {}call to {:?}({:?}) at: {:?}, scope: {:?}", if is_cleanup { "cleanup " } else { "" }, @@ -310,6 +293,14 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let mut patch = MirPatch::new(self.mir_body); + let (file_name, start_line, start_col, end_line, end_col) = self.code_region(&span); + + args.push(self.const_str(&file_name, inject_at)); + args.push(self.const_u32(start_line, inject_at)); + args.push(self.const_u32(start_col, inject_at)); + args.push(self.const_u32(end_line, inject_at)); + args.push(self.const_u32(end_col, inject_at)); + let temp = patch.new_temp(self.tcx.mk_unit(), inject_at); let new_block = patch.new_block(placeholder_block(inject_at, scope, is_cleanup)); patch.patch_terminator( @@ -335,6 +326,43 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.mir_body.basic_blocks_mut().swap(next_block, new_block); } + /// Convert the Span into its file name, start line and column, and end line and column + fn code_region(&self, span: &Span) -> (String, u32, u32, u32, u32) { + let source_map = self.tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = if span.hi() == span.lo() { + start.clone() + } else { + let end = source_map.lookup_char_pos(span.hi()); + debug_assert_eq!( + start.file.name, + end.file.name, + "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!", + span.lo(), + start, + span.hi(), + end + ); + end + }; + match &start.file.name { + FileName::Real(RealFileName::Named(path)) => ( + path.to_string_lossy().to_string(), + start.line as u32, + start.col.to_u32() + 1, + end.line as u32, + end.col.to_u32() + 1, + ), + _ => { + bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name) + } + } + } + + fn const_str(&self, value: &str, span: Span) -> Operand<'tcx> { + Operand::const_from_str(self.tcx, value, span) + } + fn const_u32(&self, value: u32, span: Span) -> Operand<'tcx> { Operand::const_from_scalar(self.tcx, self.tcx.types.u32, Scalar::from_u32(value), span) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index dc2172650e574..b3287caa0bfc8 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -379,17 +379,46 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), - sym::count_code_region => { - (0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit()) - } + sym::count_code_region => ( + 0, + vec![ + tcx.types.u64, + tcx.types.u32, + tcx.mk_static_str(), + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + ], + tcx.mk_unit(), + ), sym::coverage_counter_add | sym::coverage_counter_subtract => ( 0, - vec![tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32], + vec![ + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.mk_static_str(), + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + ], tcx.mk_unit(), ), - sym::coverage_unreachable => (0, vec![tcx.types.u32, tcx.types.u32], tcx.mk_unit()), + sym::coverage_unreachable => ( + 0, + vec![ + tcx.mk_static_str(), + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + ], + tcx.mk_unit(), + ), other => { struct_span_err!( diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 96df5c6a51890..af6d5519e612f 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -2,58 +2,76 @@ + // MIR for `bar` after InstrumentCoverage fn bar() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17 -+ let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18 + let mut _0: bool; // return place in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:13: 18:17 ++ let mut _1: (); // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 bb0: { -+ StorageLive(_1); // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18 -+ _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const 529_u32, const 541_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18 ++ StorageLive(_1); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 ++ _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const "/the/cwd/src/test/mir-opt/instrument_coverage.rs", const 18_u32, const 18_u32, const 20_u32, const 2_u32) -> bb2; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 + // ty::Const -+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region} ++ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region} + // + val: Value(Scalar(<ZST>)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) } ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) } + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x8dabe565aaa2aefd)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 + // + literal: Const { ty: u64, val: Value(Scalar(0x8dabe565aaa2aefd)) } + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000000)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } + // ty::Const ++ // + ty: &str ++ // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 }) ++ // mir::Constant ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 ++ // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 }) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000012)) ++ // mir::Constant ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000012)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000012)) ++ // mir::Constant ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000012)) } ++ // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x00000211)) ++ // + val: Value(Scalar(0x00000014)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000211)) } ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000014)) } + // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x0000021d)) ++ // + val: Value(Scalar(0x00000002)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x0000021d)) } ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) } + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 ++ resume; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:1: 20:2 + } + + bb2: { -+ StorageDead(_1); // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9 - _0 = const true; // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9 ++ StorageDead(_1); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:19:5: 19:9 + _0 = const true; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:19:5: 19:9 // ty::Const // + ty: bool // + val: Value(Scalar(0x01)) // mir::Constant - // + span: $DIR/instrument_coverage.rs:19:5: 19:9 + // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:19:5: 19:9 // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } - return; // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2 + return; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:20:2: 20:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 1bcc98de8d4f2..d958dd0131324 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -2,99 +2,117 @@ + // MIR for `main` after InstrumentCoverage fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 - let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 - let mut _2: bool; // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 - let mut _3: !; // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10 -+ let mut _4: (); // in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 + let mut _0: (); // return place in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 + let mut _1: (); // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:1: 15:2 + let mut _2: bool; // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17 + let mut _3: !; // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:18: 13:10 ++ let mut _4: (); // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 bb0: { -- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 -+ StorageLive(_4); // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 -+ _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const 425_u32, const 493_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 +- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6 ++ StorageLive(_4); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 ++ _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const "/the/cwd/src/test/mir-opt/instrument_coverage.rs", const 9_u32, const 11_u32, const 15_u32, const 2_u32) -> bb7; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 + // ty::Const -+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region} ++ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region} + // + val: Value(Scalar(<ZST>)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) } ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) } + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0xde1b3f75a72fc7f7)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 + // + literal: Const { ty: u64, val: Value(Scalar(0xde1b3f75a72fc7f7)) } + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000000)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } + // ty::Const ++ // + ty: &str ++ // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 }) ++ // mir::Constant ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 ++ // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 }) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000009)) ++ // mir::Constant ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000009)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x0000000b)) ++ // mir::Constant ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x0000000b)) } ++ // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x000001a9)) ++ // + val: Value(Scalar(0x0000000f)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x000001a9)) } ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x0000000f)) } + // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x000001ed)) ++ // + val: Value(Scalar(0x00000002)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x000001ed)) } ++ // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) } } bb1: { - StorageLive(_2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 - _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 + StorageLive(_2); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17 + _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17 // ty::Const // + ty: fn() -> bool {bar} // + val: Value(Scalar(<ZST>)) // mir::Constant - // + span: $DIR/instrument_coverage.rs:11:12: 11:15 + // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) } } bb2 (cleanup): { - resume; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 + resume; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:1: 15:2 } bb3: { - FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 - switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + FakeRead(ForMatchedPlace, _2); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17 + switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10 } bb4: { - falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10 } bb5: { - _1 = const (); // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + _1 = const (); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10 // ty::Const // + ty: () // + val: Value(Scalar(<ZST>)) // mir::Constant - // + span: $DIR/instrument_coverage.rs:11:9: 13:10 + // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10 // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } - StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6 - goto -> bb0; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 + StorageDead(_2); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:14:5: 14:6 + goto -> bb0; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6 } bb6: { - _0 = const (); // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18 + _0 = const (); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:12:13: 12:18 // ty::Const // + ty: () // + val: Value(Scalar(<ZST>)) // mir::Constant - // + span: $DIR/instrument_coverage.rs:12:13: 12:18 + // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:12:13: 12:18 // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } - StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6 - return; // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2 + StorageDead(_2); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:14:5: 14:6 + return; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:15:2: 15:2 + } + + bb7: { -+ StorageDead(_4); // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 -+ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 ++ StorageDead(_4); // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6 ++ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6 } } diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs index 4770ec9b66e8f..c734951476ce4 100644 --- a/src/test/mir-opt/instrument_coverage.rs +++ b/src/test/mir-opt/instrument_coverage.rs @@ -3,7 +3,7 @@ // intrinsics, during codegen. // needs-profiler-support -// compile-flags: -Zinstrument-coverage +// compile-flags: -Zinstrument-coverage --remap-path-prefix={{cwd}}=/the/cwd // EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff // EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff fn main() { From 6deda6a6a05e6e6ace8fb015d610c6355efb0fd7 Mon Sep 17 00:00:00 2001 From: Aaron Hill <aa1ronham@gmail.com> Date: Sun, 2 Aug 2020 23:53:41 -0400 Subject: [PATCH 08/10] Stabilize Ident::new_raw Tracking issue: #54723 This is a continuation of PR #59002 --- library/proc_macro/src/lib.rs | 7 ++-- src/test/ui/proc-macro/auxiliary/raw-ident.rs | 35 +++++++++++++++++++ src/test/ui/proc-macro/raw-ident.rs | 16 +++++++++ src/test/ui/proc-macro/raw-ident.stderr | 10 ++++++ 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/proc-macro/auxiliary/raw-ident.rs create mode 100644 src/test/ui/proc-macro/raw-ident.rs create mode 100644 src/test/ui/proc-macro/raw-ident.stderr diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 42ba7f5c02591..de3866d92fc3f 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -848,7 +848,7 @@ impl Ident { /// Creates a new `Ident` with the given `string` as well as the specified /// `span`. /// The `string` argument must be a valid identifier permitted by the - /// language, otherwise the function will panic. + /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. /// /// Note that `span`, currently in rustc, configures the hygiene information /// for this identifier. @@ -870,7 +870,10 @@ impl Ident { } /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). - #[unstable(feature = "proc_macro_raw_ident", issue = "54723")] + /// The `string` argument be a valid identifier permitted by the language + /// (including keywords, e.g. `fn`). Keywords which are usable in path segments + /// (e.g. `self`, `super`) are not supported, and will cause a panic. + #[stable(feature = "proc_macro_raw_ident", since = "1.47.0")] pub fn new_raw(string: &str, span: Span) -> Ident { Ident(bridge::client::Ident::new(string, span.0, true)) } diff --git a/src/test/ui/proc-macro/auxiliary/raw-ident.rs b/src/test/ui/proc-macro/auxiliary/raw-ident.rs new file mode 100644 index 0000000000000..9daee21aa17d4 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/raw-ident.rs @@ -0,0 +1,35 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::{TokenStream, TokenTree, Ident, Punct, Spacing, Span}; + +#[proc_macro] +pub fn make_struct(input: TokenStream) -> TokenStream { + match input.into_iter().next().unwrap() { + TokenTree::Ident(ident) => { + vec![ + TokenTree::Ident(Ident::new("struct", Span::call_site())), + TokenTree::Ident(Ident::new_raw(&ident.to_string(), Span::call_site())), + TokenTree::Punct(Punct::new(';', Spacing::Alone)) + ].into_iter().collect() + } + _ => panic!() + } +} + +#[proc_macro] +pub fn make_bad_struct(input: TokenStream) -> TokenStream { + match input.into_iter().next().unwrap() { + TokenTree::Ident(ident) => { + vec![ + TokenTree::Ident(Ident::new_raw("struct", Span::call_site())), + TokenTree::Ident(Ident::new(&ident.to_string(), Span::call_site())), + TokenTree::Punct(Punct::new(';', Spacing::Alone)) + ].into_iter().collect() + } + _ => panic!() + } +} diff --git a/src/test/ui/proc-macro/raw-ident.rs b/src/test/ui/proc-macro/raw-ident.rs new file mode 100644 index 0000000000000..03cb4571496e9 --- /dev/null +++ b/src/test/ui/proc-macro/raw-ident.rs @@ -0,0 +1,16 @@ +// aux-build:raw-ident.rs + +#[macro_use] extern crate raw_ident; + +fn main() { + make_struct!(fn); + make_struct!(Foo); + make_struct!(await); + + r#fn; + r#Foo; + Foo; + r#await; + + make_bad_struct!(S); //~ ERROR expected one of +} diff --git a/src/test/ui/proc-macro/raw-ident.stderr b/src/test/ui/proc-macro/raw-ident.stderr new file mode 100644 index 0000000000000..e82a1226b5aef --- /dev/null +++ b/src/test/ui/proc-macro/raw-ident.stderr @@ -0,0 +1,10 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `S` + --> $DIR/raw-ident.rs:15:5 + | +LL | make_bad_struct!(S); + | ^^^^^^^^^^^^^^^^^^^^ expected one of 8 possible tokens + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + From 0a88346be64d0c64771d72ada8583e5795416556 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sun, 2 Aug 2020 13:17:20 +0300 Subject: [PATCH 09/10] rustc_ast: `(Nested)MetaItem::check_name` -> `has_name` For consistency with `Attribute::has_name` which doesn't mark the attribute as used either. Replace all uses of `check_name` with `has_name` outside of rustc --- src/librustc_ast/attr/mod.rs | 13 +++++----- src/librustc_ast_passes/feature_gate.rs | 4 ++-- src/librustc_attr/builtin.rs | 10 ++++---- .../proc_macro_harness.rs | 2 +- src/librustc_builtin_macros/test.rs | 2 +- src/librustc_expand/expand.rs | 4 ++-- .../assert_module_sources.rs | 2 +- .../persist/dirty_clean.rs | 10 ++++---- src/librustc_lint/builtin.rs | 2 +- src/librustc_metadata/native_libs.rs | 8 +++---- src/librustc_mir/dataflow/framework/engine.rs | 4 ++-- src/librustc_mir/dataflow/mod.rs | 2 +- src/librustc_passes/check_attr.rs | 2 +- src/librustc_save_analysis/lib.rs | 4 ++-- .../traits/on_unimplemented.rs | 10 ++++---- src/librustc_typeck/collect.rs | 8 +++---- src/librustdoc/clean/mod.rs | 8 +++---- src/librustdoc/clean/types.rs | 24 +++++++++---------- src/librustdoc/html/render/cache.rs | 2 +- src/librustdoc/test.rs | 8 +++---- src/librustdoc/visit_ast.rs | 12 +++++----- src/tools/clippy/clippy_lints/src/attrs.rs | 18 +++++++------- src/tools/clippy/clippy_lints/src/doc.rs | 2 +- .../src/inline_fn_without_body.rs | 2 +- .../clippy_lints/src/manual_non_exhaustive.rs | 2 +- .../clippy/clippy_lints/src/missing_doc.rs | 2 +- .../clippy/clippy_lints/src/missing_inline.rs | 2 +- .../clippy_lints/src/needless_borrow.rs | 2 +- .../src/needless_pass_by_value.rs | 2 +- src/tools/clippy/clippy_lints/src/returns.rs | 2 +- .../src/trivially_copy_pass_by_ref.rs | 2 +- .../clippy/clippy_lints/src/utils/conf.rs | 2 +- 32 files changed, 90 insertions(+), 89 deletions(-) diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 9d4b6dbed9870..022e49a7ea4c2 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -100,8 +100,8 @@ impl NestedMetaItem { } /// Returns `true` if this list item is a MetaItem with a name of `name`. - pub fn check_name(&self, name: Symbol) -> bool { - self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) + pub fn has_name(&self, name: Symbol) -> bool { + self.meta_item().map_or(false, |meta_item| meta_item.has_name(name)) } /// For a single-segment meta item, returns its name; otherwise, returns `None`. @@ -173,8 +173,9 @@ impl Attribute { } } - /// Returns `true` if the attribute's path matches the argument. If it matches, then the - /// attribute is marked as used. + /// Returns `true` if the attribute's path matches the argument. + /// If it matches, then the attribute is marked as used. + /// Should only be used by rustc, other tools can use `has_name` instead. pub fn check_name(&self, name: Symbol) -> bool { let matches = self.has_name(name); if matches { @@ -278,7 +279,7 @@ impl MetaItem { } } - pub fn check_name(&self, name: Symbol) -> bool { + pub fn has_name(&self, name: Symbol) -> bool { self.path == name } @@ -405,7 +406,7 @@ pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribut } pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { - items.iter().any(|item| item.check_name(name)) + items.iter().any(|item| item.has_name(name)) } pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 2fe208c3ce68c..22eaca4f071e2 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -243,7 +243,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if attr.check_name(sym::doc) { for nested_meta in attr.meta_item_list().unwrap_or_default() { macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => { - $(if nested_meta.check_name(sym::$name) { + $(if nested_meta.has_name(sym::$name) { let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental"); gate_feature_post!(self, $feature, attr.span, msg); })* @@ -314,7 +314,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ItemKind::Struct(..) => { for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(sym::simd) { + if item.has_name(sym::simd) { gate_feature_post!( &self, repr_simd, diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index 1e088b52dcc35..983202aafabd5 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -92,9 +92,9 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op if let Some(meta) = attr.meta() { if let MetaItemKind::List(items) = meta.kind { if items.len() == 1 { - if items[0].check_name(sym::allowed) { + if items[0].has_name(sym::allowed) { return Some(UnwindAttr::Allowed); - } else if items[0].check_name(sym::aborts) { + } else if items[0].has_name(sym::aborts) { return Some(UnwindAttr::Aborts); } } @@ -168,7 +168,7 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool item.check_name(sym::feature) && item .meta_item_list() - .map(|list| list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name))) + .map(|list| list.iter().any(|mi| mi.is_word() && mi.has_name(feature_name))) .unwrap_or(false) }) } @@ -505,7 +505,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat } fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| cfg.check_name(sym)); + let gate = find_gated_cfg(|sym| cfg.has_name(sym)); if let (Some(feats), Some(gated_cfg)) = (features, gate) { gate_cfg(&gated_cfg, cfg.span, sess, feats); } @@ -898,7 +898,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> { } } else { if let Some(meta_item) = item.meta_item() { - if meta_item.check_name(sym::align) { + if meta_item.has_name(sym::align) { if let MetaItemKind::NameValue(ref value) = meta_item.kind { recognised = true; let mut err = struct_span_err!( diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/src/librustc_builtin_macros/proc_macro_harness.rs index f044ce41e879e..763bdca35ebe6 100644 --- a/src/librustc_builtin_macros/proc_macro_harness.rs +++ b/src/librustc_builtin_macros/proc_macro_harness.rs @@ -143,7 +143,7 @@ impl<'a> CollectProcMacros<'a> { let attributes_attr = list.get(1); let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { - if !attr.check_name(sym::attributes) { + if !attr.has_name(sym::attributes) { self.handler.span_err(attr.span(), "second argument must be `attributes`") } attr.meta_item_list() diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index 460f947a792af..29095034ba9f1 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -336,7 +336,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { Some(list) => { let msg = list .iter() - .find(|mi| mi.check_name(sym::expected)) + .find(|mi| mi.has_name(sym::expected)) .and_then(|mi| mi.meta_item()) .and_then(|mi| mi.value_str()); if list.len() != 1 || msg.is_none() { diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index e4c0fcaa298d2..0cc340c205ac8 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1644,14 +1644,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } if let Some(list) = at.meta_item_list() { - if !list.iter().any(|it| it.check_name(sym::include)) { + if !list.iter().any(|it| it.has_name(sym::include)) { return noop_visit_attribute(at, self); } let mut items = vec![]; for mut it in list { - if !it.check_name(sym::include) { + if !it.has_name(sym::include) { items.push({ noop_visit_meta_list_item(&mut it, self); it diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index cd5da7a67685c..d451d9a22a48b 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -149,7 +149,7 @@ impl AssertModuleSource<'tcx> { fn field(&self, attr: &ast::Attribute, name: Symbol) -> Symbol { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(name) { + if item.has_name(name) { if let Some(value) = item.value_str() { return value; } else { diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index d48810f1cf103..02f37f82352a9 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -231,7 +231,7 @@ impl DirtyCleanVisitor<'tcx> { fn labels(&self, attr: &Attribute) -> Option<Labels> { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(LABEL) { + if item.has_name(LABEL) { let value = expect_associated_value(self.tcx, &item); return Some(self.resolve_labels(&item, value)); } @@ -242,7 +242,7 @@ impl DirtyCleanVisitor<'tcx> { /// `except=` attribute value fn except(&self, attr: &Attribute) -> Labels { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(EXCEPT) { + if item.has_name(EXCEPT) { let value = expect_associated_value(self.tcx, &item); return self.resolve_labels(&item, value); } @@ -474,15 +474,15 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { debug!("check_config: config={:?}", config); let (mut cfg, mut except, mut label) = (None, false, false); for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(CFG) { + if item.has_name(CFG) { let value = expect_associated_value(tcx, &item); debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); } - if item.check_name(LABEL) { + if item.has_name(LABEL) { label = true; } - if item.check_name(EXCEPT) { + if item.has_name(EXCEPT) { except = true; } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e32c8fbee6852..6515708e115a5 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -330,7 +330,7 @@ fn has_doc(attr: &ast::Attribute) -> bool { if let Some(list) = attr.meta_item_list() { for meta in list { - if meta.check_name(sym::include) || meta.check_name(sym::hidden) { + if meta.has_name(sym::include) || meta.has_name(sym::hidden) { return true; } } diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index fc4235a3eda09..d01c598d059c0 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -58,7 +58,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { let mut kind_specified = false; for item in items.iter() { - if item.check_name(sym::kind) { + if item.has_name(sym::kind) { kind_specified = true; let kind = match item.value_str() { Some(name) => name, @@ -84,9 +84,9 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { NativeLibKind::Unspecified } }; - } else if item.check_name(sym::name) { + } else if item.has_name(sym::name) { lib.name = item.value_str(); - } else if item.check_name(sym::cfg) { + } else if item.has_name(sym::cfg) { let cfg = match item.meta_item_list() { Some(list) => list, None => continue, // skip like historical compilers @@ -98,7 +98,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { } else { self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`"); } - } else if item.check_name(sym::wasm_import_module) { + } else if item.has_name(sym::wasm_import_module) { match item.value_str() { Some(s) => lib.wasm_import_module = Some(s), None => { diff --git a/src/librustc_mir/dataflow/framework/engine.rs b/src/librustc_mir/dataflow/framework/engine.rs index 003c40f290b8d..2113d40a594eb 100644 --- a/src/librustc_mir/dataflow/framework/engine.rs +++ b/src/librustc_mir/dataflow/framework/engine.rs @@ -339,7 +339,7 @@ impl RustcMirAttrs { .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); for attr in rustc_mir_attrs { - let attr_result = if attr.check_name(sym::borrowck_graphviz_postflow) { + let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) { Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| { let path = PathBuf::from(s.to_string()); match path.file_name() { @@ -350,7 +350,7 @@ impl RustcMirAttrs { } } }) - } else if attr.check_name(sym::borrowck_graphviz_format) { + } else if attr.has_name(sym::borrowck_graphviz_format) { Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s { sym::gen_kill | sym::two_phase => Ok(s), _ => { diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index ae1328dbd12c7..8a9edb23a10ef 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -34,7 +34,7 @@ pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Opti let items = attr.meta_item_list(); for item in items.iter().flat_map(|l| l.iter()) { match item.meta_item() { - Some(mi) if mi.check_name(name) => return Some(mi.clone()), + Some(mi) if mi.has_name(name) => return Some(mi.clone()), _ => continue, } } diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 3e63a63d9d0f9..1ff47ee038d3b 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -222,7 +222,7 @@ impl CheckAttrVisitor<'tcx> { if let Some(mi) = attr.meta() { if let Some(list) = mi.meta_item_list() { for meta in list { - if meta.check_name(sym::alias) { + if meta.has_name(sym::alias) { if !meta.is_value_str() || meta .value_str() diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 0751dbb027ae2..8e379a3510038 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -832,10 +832,10 @@ impl<'tcx> SaveContext<'tcx> { if let Some(meta_list) = attr.meta_item_list() { meta_list .into_iter() - .filter(|it| it.check_name(sym::include)) + .filter(|it| it.has_name(sym::include)) .filter_map(|it| it.meta_item_list().map(|l| l.to_owned())) .flat_map(|it| it) - .filter(|meta| meta.check_name(sym::contents)) + .filter(|meta| meta.has_name(sym::contents)) .filter_map(|meta| meta.value_str()) .for_each(|val| { result.push_str(&val.as_str()); diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs index deb33708681fa..446d5a489df48 100644 --- a/src/librustc_trait_selection/traits/on_unimplemented.rs +++ b/src/librustc_trait_selection/traits/on_unimplemented.rs @@ -95,27 +95,27 @@ impl<'tcx> OnUnimplementedDirective { }; for item in item_iter { - if item.check_name(sym::message) && message.is_none() { + if item.has_name(sym::message) && message.is_none() { if let Some(message_) = item.value_str() { message = parse_value(message_)?; continue; } - } else if item.check_name(sym::label) && label.is_none() { + } else if item.has_name(sym::label) && label.is_none() { if let Some(label_) = item.value_str() { label = parse_value(label_)?; continue; } - } else if item.check_name(sym::note) && note.is_none() { + } else if item.has_name(sym::note) && note.is_none() { if let Some(note_) = item.value_str() { note = parse_value(note_)?; continue; } - } else if item.check_name(sym::enclosing_scope) && enclosing_scope.is_none() { + } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() { if let Some(enclosing_scope_) = item.value_str() { enclosing_scope = parse_value(enclosing_scope_)?; continue; } - } else if item.check_name(sym::on) + } else if item.has_name(sym::on) && is_root && message.is_none() && label.is_none() diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8715dacb324b0..97df065500a16 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2231,7 +2231,7 @@ fn from_target_feature( let rust_features = tcx.features(); for item in list { // Only `enable = ...` is accepted in the meta-item list. - if !item.check_name(sym::enable) { + if !item.has_name(sym::enable) { bad_item(item.span()); continue; } @@ -2483,11 +2483,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { no_sanitize_span = Some(attr.span); if let Some(list) = attr.meta_item_list() { for item in list.iter() { - if item.check_name(sym::address) { + if item.has_name(sym::address) { codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS; - } else if item.check_name(sym::memory) { + } else if item.has_name(sym::memory) { codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; - } else if item.check_name(sym::thread) { + } else if item.has_name(sym::thread) { codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; } else { tcx.sess diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5b048372624a4..2a090d6efa5fd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -113,7 +113,7 @@ impl Clean<ExternalCrate> for CrateNum { let mut prim = None; for attr in attrs.lists(sym::doc) { if let Some(v) = attr.value_str() { - if attr.check_name(sym::primitive) { + if attr.has_name(sym::primitive) { prim = PrimitiveType::from_symbol(v); if prim.is_some() { break; @@ -168,7 +168,7 @@ impl Clean<ExternalCrate> for CrateNum { let mut keyword = None; for attr in attrs.lists(sym::doc) { if let Some(v) = attr.value_str() { - if attr.check_name(sym::keyword) { + if attr.has_name(sym::keyword) { if v.is_doc_keyword() { keyword = Some(v.to_string()); break; @@ -2157,7 +2157,7 @@ impl Clean<Vec<Item>> for doctree::ExternCrate<'_> { fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> { let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| { - a.check_name(sym::doc) + a.has_name(sym::doc) && match a.meta_item_list() { Some(l) => attr::list_contains_name(&l, sym::inline), None => false, @@ -2197,7 +2197,7 @@ impl Clean<Vec<Item>> for doctree::Import<'_> { // Don't inline doc(hidden) imports so they can be stripped at a later stage. let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { - a.check_name(sym::doc) + a.has_name(sym::doc) && match a.meta_item_list() { Some(l) => { attr::list_contains_name(&l, sym::no_inline) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 89549eae2cb0e..1bea41b658532 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -210,7 +210,7 @@ impl Item { } pub fn is_non_exhaustive(&self) -> bool { - self.attrs.other_attrs.iter().any(|a| a.check_name(sym::non_exhaustive)) + self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) } /// Returns a documentation-level item type from the item. @@ -309,7 +309,7 @@ impl<'a> Iterator for ListAttributesIter<'a> { for attr in &mut self.attrs { if let Some(list) = attr.meta_item_list() { - if attr.check_name(self.name) { + if attr.has_name(self.name) { self.current_list = list.into_iter(); if let Some(nested) = self.current_list.next() { return Some(nested); @@ -345,7 +345,7 @@ pub trait NestedAttributesExt { impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I { fn has_word(self, word: Symbol) -> bool { - self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) + self.into_iter().any(|attr| attr.is_word() && attr.has_name(word)) } } @@ -425,7 +425,7 @@ impl Attributes { if let ast::MetaItemKind::List(ref nmis) = mi.kind { if nmis.len() == 1 { if let MetaItem(ref cfg_mi) = nmis[0] { - if cfg_mi.check_name(sym::cfg) { + if cfg_mi.has_name(sym::cfg) { if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { if cfg_nmis.len() == 1 { if let MetaItem(ref content_mi) = cfg_nmis[0] { @@ -447,7 +447,7 @@ impl Attributes { pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> { mi.meta_item_list().and_then(|list| { for meta in list { - if meta.check_name(sym::include) { + if meta.has_name(sym::include) { // the actual compiled `#[doc(include="filename")]` gets expanded to // `#[doc(include(file="filename", contents="file contents")]` so we need to // look for that instead @@ -456,11 +456,11 @@ impl Attributes { let mut contents: Option<String> = None; for it in list { - if it.check_name(sym::file) { + if it.has_name(sym::file) { if let Some(name) = it.value_str() { filename = Some(name.to_string()); } - } else if it.check_name(sym::contents) { + } else if it.has_name(sym::contents) { if let Some(docs) = it.value_str() { contents = Some(docs.to_string()); } @@ -482,12 +482,12 @@ impl Attributes { pub fn has_doc_flag(&self, flag: Symbol) -> bool { for attr in &self.other_attrs { - if !attr.check_name(sym::doc) { + if !attr.has_name(sym::doc) { continue; } if let Some(items) = attr.meta_item_list() { - if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) { + if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) { return true; } } @@ -521,7 +521,7 @@ impl Attributes { } None } else { - if attr.check_name(sym::doc) { + if attr.has_name(sym::doc) { if let Some(mi) = attr.meta() { if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { // Extracted #[doc(cfg(...))] @@ -548,7 +548,7 @@ impl Attributes { // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well for attr in attrs.lists(sym::target_feature) { - if attr.check_name(sym::enable) { + if attr.has_name(sym::enable) { if let Some(feat) = attr.value_str() { let meta = attr::mk_name_value_item_str( Ident::with_dummy_span(sym::target_feature), @@ -648,7 +648,7 @@ impl Attributes { pub fn get_doc_aliases(&self) -> FxHashSet<String> { self.other_attrs .lists(sym::doc) - .filter(|a| a.check_name(sym::alias)) + .filter(|a| a.has_name(sym::alias)) .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) .filter(|v| !v.is_empty()) .collect::<FxHashSet<_>>() diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 378efa1a1bed7..5a9e9dda6771e 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -48,7 +48,7 @@ pub fn extern_location( // external crate e.attrs .lists(sym::doc) - .filter(|a| a.check_name(sym::html_root_url)) + .filter(|a| a.has_name(sym::html_root_url)) .filter_map(|a| a.value_str()) .map(|url| { let mut url = url.to_string(); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e8ea71997109a..ba1341e652c39 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -175,17 +175,17 @@ fn scrape_test_config(krate: &::rustc_hir::Crate<'_>) -> TestOptions { .item .attrs .iter() - .filter(|a| a.check_name(sym::doc)) + .filter(|a| a.has_name(sym::doc)) .flat_map(|a| a.meta_item_list().unwrap_or_else(Vec::new)) - .filter(|a| a.check_name(sym::test)) + .filter(|a| a.has_name(sym::test)) .collect(); let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[])); for attr in attrs { - if attr.check_name(sym::no_crate_inject) { + if attr.has_name(sym::no_crate_inject) { opts.no_crate_inject = true; } - if attr.check_name(sym::attr) { + if attr.has_name(sym::attr) { if let Some(l) = attr.meta_item_list() { for item in l { opts.attrs.push(pprust::meta_list_item_to_string(item)); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 735446d235c2e..cf57ffd0b4b30 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -165,11 +165,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ) { debug!("visiting fn"); let macro_kind = item.attrs.iter().find_map(|a| { - if a.check_name(sym::proc_macro) { + if a.has_name(sym::proc_macro) { Some(MacroKind::Bang) - } else if a.check_name(sym::proc_macro_derive) { + } else if a.has_name(sym::proc_macro_derive) { Some(MacroKind::Derive) - } else if a.check_name(sym::proc_macro_attribute) { + } else if a.has_name(sym::proc_macro_attribute) { Some(MacroKind::Attr) } else { None @@ -189,7 +189,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let mut helpers = Vec::new(); for mi in item.attrs.lists(sym::proc_macro_derive) { - if !mi.check_name(sym::attributes) { + if !mi.has_name(sym::attributes) { continue; } @@ -419,8 +419,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // anything as it will probably be stripped anyway. if item.vis.node.is_pub() && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| match item.meta_item_list() { - Some(ref list) if item.check_name(sym::doc) => { - list.iter().any(|i| i.check_name(sym::inline)) + Some(ref list) if item.has_name(sym::doc) => { + list.iter().any(|i| i.has_name(sym::inline)) } _ => false, }); diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 27a7fa8862237..40af6bb3d7bcf 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -286,14 +286,14 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { }, _ => {}, } - if items.is_empty() || !attr.check_name(sym!(deprecated)) { + if items.is_empty() || !attr.has_name(sym!(deprecated)) { return; } for item in items { if_chain! { if let NestedMetaItem::MetaItem(mi) = &item; if let MetaItemKind::NameValue(lit) = &mi.kind; - if mi.check_name(sym!(since)); + if mi.has_name(sym!(since)); then { check_semver(cx, item.span(), lit); } @@ -309,7 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } match item.kind { ItemKind::ExternCrate(..) | ItemKind::Use(..) => { - let skip_unused_imports = item.attrs.iter().any(|attr| attr.check_name(sym!(macro_use))); + let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym!(macro_use))); for attr in item.attrs { if in_external_macro(cx.sess(), attr.span) { @@ -524,7 +524,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Name, attrs: &[Attribute] for attr in attrs { if let Some(values) = attr.meta_item_list() { - if values.len() != 1 || !attr.check_name(sym!(inline)) { + if values.len() != 1 || !attr.has_name(sym!(inline)) { continue; } if is_word(&values[0], sym!(always)) { @@ -558,7 +558,7 @@ fn check_semver(cx: &LateContext<'_>, span: Span, lit: &Lit) { fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { if let NestedMetaItem::MetaItem(mi) = &nmi { - mi.is_word() && mi.check_name(expected) + mi.is_word() && mi.has_name(expected) } else { false } @@ -618,15 +618,15 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::as fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { if_chain! { // check cfg_attr - if attr.check_name(sym!(cfg_attr)); + if attr.has_name(sym!(cfg_attr)); if let Some(items) = attr.meta_item_list(); if items.len() == 2; // check for `rustfmt` if let Some(feature_item) = items[0].meta_item(); - if feature_item.check_name(sym!(rustfmt)); + if feature_item.has_name(sym!(rustfmt)); // check for `rustfmt_skip` and `rustfmt::skip` if let Some(skip_item) = &items[1].meta_item(); - if skip_item.check_name(sym!(rustfmt_skip)) || + if skip_item.has_name(sym!(rustfmt_skip)) || skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym!(skip); // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 @@ -685,7 +685,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { } if_chain! { - if attr.check_name(sym!(cfg)); + if attr.has_name(sym!(cfg)); if let Some(list) = attr.meta_item_list(); let mismatched = find_mismatched_target_os(&list); if !mismatched.is_empty(); diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index d52bb8961fae7..e87c33d1b09dd 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -323,7 +323,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs let (comment, current_spans) = strip_doc_comment_decoration(&comment, attr.span); spans.extend_from_slice(¤t_spans); doc.push_str(&comment); - } else if attr.check_name(sym!(doc)) { + } else if attr.has_name(sym!(doc)) { // ignore mix of sugared and non-sugared doc // don't trigger the safety or errors check return DocHeaders { diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index decbee278154a..4b605fdb366a9 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { for attr in attrs { - if !attr.check_name(sym!(inline)) { + if !attr.has_name(sym!(inline)) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index f3b8902e26f67..ca1381852daee 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -83,7 +83,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants } fn is_doc_hidden(attr: &Attribute) -> bool { - attr.check_name(sym!(doc)) + attr.has_name(sym!(doc)) && match attr.meta_item_list() { Some(l) => attr::list_contains_name(&l, sym!(hidden)), None => false, diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 06e0f43c10bb8..813f9c4394819 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.check_name(sym!(doc)) + attr.has_name(sym!(doc)) && match attr.meta_item_list() { None => false, Some(l) => attr::list_contains_name(&l[..], sym!(hidden)), diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 9c96267353701..3eae45b2819d8 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -57,7 +57,7 @@ declare_clippy_lint! { } fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { - let has_inline = attrs.iter().any(|a| a.check_name(sym!(inline))); + let has_inline = attrs.iter().any(|a| a.has_name(sym!(inline))); if !has_inline { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs index 415ab556c9fd4..9391049c6e8f9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if item.attrs.iter().any(|a| a.check_name(sym!(automatically_derived))) { + if item.attrs.iter().any(|a| a.has_name(sym!(automatically_derived))) { debug_assert!(self.derived_item.is_none()); self.derived_item = Some(item.hir_id); } diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 0957787774498..a7f7c97fc487c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -312,7 +312,7 @@ fn requires_exact_signature(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { [sym!(proc_macro), sym!(proc_macro_attribute), sym!(proc_macro_derive)] .iter() - .any(|&allow| attr.check_name(allow)) + .any(|&allow| attr.has_name(allow)) }) } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index faef7e724dd05..8ed20995a70af 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -235,7 +235,7 @@ impl EarlyLintPass for Return { } fn attr_is_cfg(attr: &ast::Attribute) -> bool { - attr.meta_item_list().is_some() && attr.check_name(sym!(cfg)) + attr.meta_item_list().is_some() && attr.has_name(sym!(cfg)) } // get the def site diff --git a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs index 6a2b05e3e6df7..7948d99162b81 100644 --- a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -155,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for TriviallyCopyPassByRef { return; } for a in attrs { - if a.meta_item_list().is_some() && a.check_name(sym!(proc_macro_derive)) { + if a.meta_item_list().is_some() && a.has_name(sym!(proc_macro_derive)) { return; } } diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index de425211e38ef..ba3492a6fff11 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -13,7 +13,7 @@ use std::{env, fmt, fs, io}; /// Gets the configuration file from arguments. pub fn file_from_args(args: &[NestedMetaItem]) -> Result<Option<PathBuf>, (&'static str, Span)> { for arg in args.iter().filter_map(NestedMetaItem::meta_item) { - if arg.check_name(sym!(conf_file)) { + if arg.has_name(sym!(conf_file)) { return match arg.kind { MetaItemKind::Word | MetaItemKind::List(_) => Err(("`conf_file` must be a named value", arg.span)), MetaItemKind::NameValue(ref value) => { From 05f414b72a26b285c7a7f6c9632945ab567a9757 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Tue, 4 Aug 2020 00:33:56 +0300 Subject: [PATCH 10/10] rustc_ast: More detailed docs for `Attribute::check_name` --- src/librustc_ast/attr/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 022e49a7ea4c2..809fda865422a 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -175,7 +175,11 @@ impl Attribute { /// Returns `true` if the attribute's path matches the argument. /// If it matches, then the attribute is marked as used. - /// Should only be used by rustc, other tools can use `has_name` instead. + /// Should only be used by rustc, other tools can use `has_name` instead, + /// because only rustc is supposed to report the `unused_attributes` lint. + /// `MetaItem` and `NestedMetaItem` are produced by "lowering" an `Attribute` + /// and don't have identity, so they only has the `has_name` method, + /// and you need to mark the original `Attribute` as used when necessary. pub fn check_name(&self, name: Symbol) -> bool { let matches = self.has_name(name); if matches {