From 51ed1ecefd016bd90b09fea399b9a989d756609d Mon Sep 17 00:00:00 2001 From: Richo Healey Date: Mon, 2 Feb 2015 19:33:50 -0800 Subject: [PATCH 1/9] lint: Deny #[no_mangle] const items This renames the PrivateNoMangleFns lint to allow both to happen in a single pass, since they do roughly the same work. --- src/librustc/lint/builtin.rs | 19 ++++++++++++++++--- src/librustc/lint/context.rs | 2 +- .../compile-fail/lint-unexported-no-mangle.rs | 9 ++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 904c9c3adb567..fdc2bed781a13 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -2065,12 +2065,19 @@ declare_lint! { "functions marked #[no_mangle] should be exported" } +declare_lint! { + NO_MANGLE_CONST_ITEMS, + Deny, + "const items will not have their symbols exported" +} + #[derive(Copy)] -pub struct PrivateNoMangleFns; +pub struct InvalidNoMangleItems; -impl LintPass for PrivateNoMangleFns { +impl LintPass for InvalidNoMangleItems { fn get_lints(&self) -> LintArray { - lint_array!(PRIVATE_NO_MANGLE_FNS) + lint_array!(PRIVATE_NO_MANGLE_FNS, + NO_MANGLE_CONST_ITEMS) } fn check_item(&mut self, cx: &Context, it: &ast::Item) { @@ -2083,6 +2090,12 @@ impl LintPass for PrivateNoMangleFns { cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, msg.as_slice()); } }, + ast::ItemConst(..) => { + if attr::contains_name(it.attrs.as_slice(), "no_mangle") { + let msg = "const items should never be #[no_mangle]"; + cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); + } + } _ => {}, } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index c649ff2635bf0..730a125fe9724 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -213,7 +213,7 @@ impl LintStore { UnstableFeatures, Stability, UnconditionalRecursion, - PrivateNoMangleFns, + InvalidNoMangleItems, ); add_builtin_with_new!(sess, diff --git a/src/test/compile-fail/lint-unexported-no-mangle.rs b/src/test/compile-fail/lint-unexported-no-mangle.rs index 3227a78c2ef00..fed1157b1cf1c 100644 --- a/src/test/compile-fail/lint-unexported-no-mangle.rs +++ b/src/test/compile-fail/lint-unexported-no-mangle.rs @@ -8,13 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags:-F private_no_mangle_fns +// compile-flags:-F private_no_mangle_fns -F no_mangle_const_items // FIXME(#19495) no_mangle'ing main ICE's. #[no_mangle] fn foo() { //~ ERROR function foo is marked #[no_mangle], but not exported } +#[allow(dead_code)] +#[no_mangle] +const FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] + +#[no_mangle] +pub const PUB_FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] + #[no_mangle] pub fn bar() { } From 73d5d89567ef155dc12ee7d7ed61e206e43bf74e Mon Sep 17 00:00:00 2001 From: Richo Healey Date: Mon, 2 Feb 2015 22:03:39 -0800 Subject: [PATCH 2/9] lint: Warn about no-mangled statics that are not exported --- src/librustc/lint/builtin.rs | 15 +++++++++++++++ .../compile-fail/lint-unexported-no-mangle.rs | 10 +++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index fdc2bed781a13..697810fa0e95e 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -2065,6 +2065,12 @@ declare_lint! { "functions marked #[no_mangle] should be exported" } +declare_lint! { + PRIVATE_NO_MANGLE_STATICS, + Warn, + "statics marked #[no_mangle] should be exported" +} + declare_lint! { NO_MANGLE_CONST_ITEMS, Deny, @@ -2077,6 +2083,7 @@ pub struct InvalidNoMangleItems; impl LintPass for InvalidNoMangleItems { fn get_lints(&self) -> LintArray { lint_array!(PRIVATE_NO_MANGLE_FNS, + PRIVATE_NO_MANGLE_STATICS, NO_MANGLE_CONST_ITEMS) } @@ -2090,6 +2097,14 @@ impl LintPass for InvalidNoMangleItems { cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, msg.as_slice()); } }, + ast::ItemStatic(..) => { + if attr::contains_name(it.attrs.as_slice(), "no_mangle") && + !cx.exported_items.contains(&it.id) { + let msg = format!("static {} is marked #[no_mangle], but not exported", + it.ident); + cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, msg.as_slice()); + } + }, ast::ItemConst(..) => { if attr::contains_name(it.attrs.as_slice(), "no_mangle") { let msg = "const items should never be #[no_mangle]"; diff --git a/src/test/compile-fail/lint-unexported-no-mangle.rs b/src/test/compile-fail/lint-unexported-no-mangle.rs index fed1157b1cf1c..216fcf9353578 100644 --- a/src/test/compile-fail/lint-unexported-no-mangle.rs +++ b/src/test/compile-fail/lint-unexported-no-mangle.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags:-F private_no_mangle_fns -F no_mangle_const_items +// compile-flags:-F private_no_mangle_fns -F no_mangle_const_items -F private_no_mangle_statics // FIXME(#19495) no_mangle'ing main ICE's. #[no_mangle] @@ -26,6 +26,14 @@ pub const PUB_FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] pub fn bar() { } +#[no_mangle] +pub static BAR: u64 = 1; + +#[allow(dead_code)] +#[no_mangle] +static PRIVATE_BAR: u64 = 1; //~ ERROR static PRIVATE_BAR is marked #[no_mangle], but not exported + + fn main() { foo(); bar(); From b6f55efd5b21b2132dafa85c112b339ba498bc7c Mon Sep 17 00:00:00 2001 From: Richo Healey Date: Tue, 3 Feb 2015 12:09:45 -0800 Subject: [PATCH 3/9] lint: Document the why and how of the no_mangle const lint --- src/librustc/lint/builtin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 697810fa0e95e..22f5ca150219b 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -2107,7 +2107,10 @@ impl LintPass for InvalidNoMangleItems { }, ast::ItemConst(..) => { if attr::contains_name(it.attrs.as_slice(), "no_mangle") { - let msg = "const items should never be #[no_mangle]"; + // Const items do not refer to a particular location in memory, and therefore + // don't have anything to attach a symbol to + let msg = "const items should never be #[no_mangle], consider instead using \ + `pub static`"; cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); } } From 73201fd675e6d7d6f1ab6c116a360a39a593de93 Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Sat, 7 Feb 2015 13:14:17 +0100 Subject: [PATCH 4/9] Make the live code analysis visit method declarations. The live code analysis only visited the function's body when visiting a method, and not the FnDecl and the generics, resulting in code to be incorrectly marked as unused when it only appeared in the generics, the arguments, or the return type, whereas the same code in non-method functions was correctly detected as used. Fixes #20343. --- src/librustc/middle/dead.rs | 2 +- src/test/run-pass/issue-20343.rs | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-20343.rs diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 90d26f0f6bf53..cf680871dcf22 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { ast_map::NodeImplItem(impl_item) => { match *impl_item { ast::MethodImplItem(ref method) => { - visit::walk_block(self, method.pe_body()); + visit::walk_method_helper(self, method); } ast::TypeImplItem(_) => {} } diff --git a/src/test/run-pass/issue-20343.rs b/src/test/run-pass/issue-20343.rs new file mode 100644 index 0000000000000..79034a4a4a6d6 --- /dev/null +++ b/src/test/run-pass/issue-20343.rs @@ -0,0 +1,38 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for Issue #20343. + +#![deny(dead_code)] + +struct B { b: u32 } +struct C; +struct D; + +trait T {} +impl T for () {} + +impl B { + // test for unused code in arguments + fn foo(B { b }: B) -> u32 { b } + + // test for unused code in return type + fn bar() -> C { unsafe { ::std::mem::transmute(()) } } + + // test for unused code in generics + fn baz>() {} +} + +pub fn main() { + let b = B { b: 3 }; + B::foo(b); + B::bar(); + B::baz::<()>(); +} From b24c6fde477dd7a8734a783dc0f4eeb9a1ea4f18 Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 10 Feb 2015 13:41:05 -0500 Subject: [PATCH 5/9] fix and macro-ify map benches, fixes #22134 --- src/libcollections/bench.rs | 196 +++++++++++++++++--------------- src/libcollections/btree/map.rs | 72 ++---------- src/libcollections/lib.rs | 2 +- src/libcollections/vec_map.rs | 73 ++---------- 4 files changed, 120 insertions(+), 223 deletions(-) diff --git a/src/libcollections/bench.rs b/src/libcollections/bench.rs index b0a5911720a40..b59799b49971f 100644 --- a/src/libcollections/bench.rs +++ b/src/libcollections/bench.rs @@ -8,103 +8,113 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::*; -use std::rand; -use std::rand::Rng; -use test::{Bencher, black_box}; - -pub fn insert_rand_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut remove: R) where - I: FnMut(&mut M, usize), - R: FnMut(&mut M, usize), -{ - // setup - let mut rng = rand::weak_rng(); - - for _ in 0..n { - insert(map, rng.gen::() % n); - } - - // measure - b.iter(|| { - let k = rng.gen::() % n; - insert(map, k); - remove(map, k); - }); - black_box(map); +macro_rules! map_insert_rand_bench { + ($name: ident, $n: expr, $map: ident) => ( + #[bench] + pub fn $name(b: &mut ::test::Bencher) { + use std::rand; + use std::rand::Rng; + use test::black_box; + + let n: usize = $n; + let mut map = $map::new(); + // setup + let mut rng = rand::weak_rng(); + + for _ in 0..n { + let i = rng.gen() % n; + map.insert(i, i); + } + + // measure + b.iter(|| { + let k = rng.gen() % n; + map.insert(k, k); + map.remove(&k); + }); + black_box(map); + } + ) } -pub fn insert_seq_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut remove: R) where - I: FnMut(&mut M, usize), - R: FnMut(&mut M, usize), -{ - // setup - for i in 0..n { - insert(map, i * 2); - } - - // measure - let mut i = 1; - b.iter(|| { - insert(map, i); - remove(map, i); - i = (i + 2) % n; - }); - black_box(map); +macro_rules! map_insert_seq_bench { + ($name: ident, $n: expr, $map: ident) => ( + #[bench] + pub fn $name(b: &mut ::test::Bencher) { + use test::black_box; + + let mut map = $map::new(); + let n: usize = $n; + // setup + for i in 0..n { + map.insert(i * 2, i * 2); + } + + // measure + let mut i = 1; + b.iter(|| { + map.insert(i, i); + map.remove(&i); + i = (i + 2) % n; + }); + black_box(map); + } + ) } -pub fn find_rand_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut find: F) where - I: FnMut(&mut M, usize), - F: FnMut(&M, usize) -> T, -{ - // setup - let mut rng = rand::weak_rng(); - let mut keys: Vec<_> = (0..n).map(|_| rng.gen::() % n).collect(); - - for k in &keys { - insert(map, *k); - } - - rng.shuffle(&mut keys); - - // measure - let mut i = 0; - b.iter(|| { - let t = find(map, keys[i]); - i = (i + 1) % n; - black_box(t); - }) +macro_rules! map_find_rand_bench { + ($name: ident, $n: expr, $map: ident) => ( + #[bench] + pub fn $name(b: &mut ::test::Bencher) { + use std::rand; + use std::rand::Rng; + use test::black_box; + + let mut map = $map::new(); + let n: usize = $n; + + // setup + let mut rng = rand::weak_rng(); + let mut keys: Vec<_> = (0..n).map(|_| rng.gen() % n).collect(); + + for &k in &keys { + map.insert(k, k); + } + + rng.shuffle(&mut keys); + + // measure + let mut i = 0; + b.iter(|| { + let t = map.get(&keys[i]); + i = (i + 1) % n; + black_box(t); + }) + } + ) } -pub fn find_seq_n(n: usize, - map: &mut M, - b: &mut Bencher, - mut insert: I, - mut find: F) where - I: FnMut(&mut M, usize), - F: FnMut(&M, usize) -> T, -{ - // setup - for i in 0..n { - insert(map, i); - } - - // measure - let mut i = 0; - b.iter(|| { - let x = find(map, i); - i = (i + 1) % n; - black_box(x); - }) +macro_rules! map_find_seq_bench { + ($name: ident, $n: expr, $map: ident) => ( + #[bench] + pub fn $name(b: &mut ::test::Bencher) { + use test::black_box; + + let mut map = $map::new(); + let n: usize = $n; + + // setup + for i in 0..n { + map.insert(i, i); + } + + // measure + let mut i = 0; + b.iter(|| { + let x = map.get(&i); + i = (i + 1) % n; + black_box(x); + }) + } + ) } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index aec50d5380880..31604bcd5b986 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1843,74 +1843,18 @@ mod bench { use test::{Bencher, black_box}; use super::BTreeMap; - use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n}; - #[bench] - pub fn insert_rand_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_rand_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - // Insert seq - #[bench] - pub fn insert_seq_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_seq_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - insert_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } + map_insert_rand_bench!{insert_rand_100, 100, BTreeMap} + map_insert_rand_bench!{insert_rand_10_000, 10_000, BTreeMap} - // Find rand - #[bench] - pub fn find_rand_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } - - #[bench] - pub fn find_rand_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_insert_seq_bench!{insert_seq_100, 100, BTreeMap} + map_insert_seq_bench!{insert_seq_10_000, 10_000, BTreeMap} - // Find seq - #[bench] - pub fn find_seq_100(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_rand_bench!{find_rand_100, 100, BTreeMap} + map_find_rand_bench!{find_rand_10_000, 10_000, BTreeMap} - #[bench] - pub fn find_seq_10_000(b: &mut Bencher) { - let mut m = BTreeMap::new(); - find_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_seq_bench!{find_seq_100, 100, BTreeMap} + map_find_seq_bench!{find_seq_10_000, 10_000, BTreeMap} fn bench_iter(b: &mut Bencher, size: i32) { let mut map = BTreeMap::::new(); diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index f220724c42e09..6b7aa2546cc48 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -101,7 +101,7 @@ pub mod btree_set { } -#[cfg(test)] mod bench; +#[cfg(test)] #[macro_use] mod bench; // FIXME(#14344) this shouldn't be necessary #[doc(hidden)] diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 739b8d8ce19c2..ddd4713e4ccf8 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -1321,74 +1321,17 @@ mod test_map { #[cfg(test)] mod bench { - use test::Bencher; use super::VecMap; - use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n}; - #[bench] - pub fn insert_rand_100(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_rand_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - // Insert seq - #[bench] - pub fn insert_seq_100(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } - - #[bench] - pub fn insert_seq_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - insert_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.remove(&i); }); - } + map_insert_rand_bench!{insert_rand_100, 100, VecMap} + map_insert_rand_bench!{insert_rand_10_000, 10_000, VecMap} - // Find rand - #[bench] - pub fn find_rand_100(b: &mut Bencher) { - let mut m = VecMap::new(); - find_rand_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } - - #[bench] - pub fn find_rand_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - find_rand_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_insert_seq_bench!{insert_seq_100, 100, VecMap} + map_insert_seq_bench!{insert_seq_10_000, 10_000, VecMap} - // Find seq - #[bench] - pub fn find_seq_100(b: &mut Bencher) { - let mut m = VecMap::new(); - find_seq_n(100, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_rand_bench!{find_rand_100, 100, VecMap} + map_find_rand_bench!{find_rand_10_000, 10_000, VecMap} - #[bench] - pub fn find_seq_10_000(b: &mut Bencher) { - let mut m = VecMap::new(); - find_seq_n(10_000, &mut m, b, - |m, i| { m.insert(i, 1); }, - |m, i| { m.get(&i); }); - } + map_find_seq_bench!{find_seq_100, 100, VecMap} + map_find_seq_bench!{find_seq_10_000, 10_000, VecMap} } From 07f1d3d5d948c09d383748e1d5bd8a219bf5e78d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 10 Feb 2015 19:39:25 -0500 Subject: [PATCH 6/9] Remove FIXME in librbml Given that this is entirely internal, this enhancement isn't going to be needed. And if it is, we'll add it. Closes #2741. --- src/librbml/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index e204a2a65958f..91dd246e8b931 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -738,7 +738,6 @@ pub mod writer { }) } - // FIXME (#2741): Provide a function to write the standard rbml header. impl<'a, W: Writer + Seek> Encoder<'a, W> { pub fn new(w: &'a mut W) -> Encoder<'a, W> { Encoder { From c324a8ace0b51ea6f7301f686677131b661f3294 Mon Sep 17 00:00:00 2001 From: Ben S Date: Wed, 11 Feb 2015 00:45:43 +0000 Subject: [PATCH 7/9] Documentation fix for PathBuf#pop It returns `false`, not `none`. --- src/libstd/path.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 776fa27086781..4984b4f9aba78 100755 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -878,7 +878,8 @@ impl PathBuf { /// Truncate `self` to `self.parent()`. /// - /// Returns `None` and does nothing if `self.parent()` is `None`. + /// Returns `false` and does nothing if `self.parent()` is `None`. + /// Otherwise, returns `true`. pub fn pop(&mut self) -> bool { match self.parent().map(|p| p.as_u8_slice().len()) { Some(len) => { From d8d3761899720dd07a4be84d455f1ab1ee2f9f34 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 11 Feb 2015 13:58:11 +1100 Subject: [PATCH 8/9] Tweak wording of copy_nonoverlapping_memory to remove misleading 'allocated'. It doesn't have to be a literal memory allocation (ala malloc), e.g. it can be in static memory, so saying "allocated" is mildly misleading. --- src/libcore/intrinsics.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5562845e11d6f..050c144b74299 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -262,11 +262,12 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// Beyond requiring that both regions of memory be allocated, it is Undefined Behaviour - /// for source and destination to overlap. Care must also be taken with the ownership of - /// `src` and `dst`. This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents of `src` - /// from being dropped or used. + /// Beyond requiring that the program must be allowed to access both regions + /// of memory, it is Undefined Behaviour for source and destination to + /// overlap. Care must also be taken with the ownership of `src` and + /// `dst`. This method semantically moves the values of `src` into `dst`. + /// However it does not drop the contents of `dst`, or prevent the contents + /// of `src` from being dropped or used. /// /// # Examples /// From d4288717c48c61e13d9bed39717101a1782b8cdf Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Tue, 10 Feb 2015 19:30:33 -0800 Subject: [PATCH 9/9] Forbid undefined names in macro use / macro reexport Fixes #21062. --- src/librustc/plugin/load.rs | 67 ++++++++++++------- src/test/compile-fail/macro-reexport-undef.rs | 20 ++++++ src/test/compile-fail/macro-use-undef.rs | 19 ++++++ 3 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 src/test/compile-fail/macro-reexport-undef.rs create mode 100644 src/test/compile-fail/macro-use-undef.rs diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs index a2ce474eda840..b46454bfdd04e 100644 --- a/src/librustc/plugin/load.rs +++ b/src/librustc/plugin/load.rs @@ -17,7 +17,7 @@ use plugin::registry::Registry; use std::mem; use std::env; use std::dynamic_lib::DynamicLibrary; -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; use std::borrow::ToOwned; use syntax::ast; use syntax::attr; @@ -116,6 +116,8 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate, return loader.plugins; } +pub type MacroSelection = HashMap; + // note that macros aren't expanded yet, and therefore macros can't add plugins. impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { fn visit_item(&mut self, item: &ast::Item) { @@ -128,9 +130,9 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { } } - // Parse the attributes relating to macro / plugin loading. - let mut macro_selection = Some(HashSet::new()); // None => load all - let mut reexport = HashSet::new(); + // Parse the attributes relating to macro loading. + let mut import = Some(HashMap::new()); // None => load all + let mut reexport = HashMap::new(); for attr in &item.attrs { let mut used = true; match &attr.name()[] { @@ -147,14 +149,14 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { let names = attr.meta_item_list(); if names.is_none() { // no names => load all - macro_selection = None; + import = None; } - if let (Some(sel), Some(names)) = (macro_selection.as_mut(), names) { - for name in names { - if let ast::MetaWord(ref name) = name.node { - sel.insert(name.clone()); + if let (Some(sel), Some(names)) = (import.as_mut(), names) { + for attr in names { + if let ast::MetaWord(ref name) = attr.node { + sel.insert(name.clone(), attr.span); } else { - self.sess.span_err(name.span, "bad macro import"); + self.sess.span_err(attr.span, "bad macro import"); } } } @@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { } }; - for name in names { - if let ast::MetaWord(ref name) = name.node { - reexport.insert(name.clone()); + for attr in names { + if let ast::MetaWord(ref name) = attr.node { + reexport.insert(name.clone(), attr.span); } else { - self.sess.span_err(name.span, "bad macro reexport"); + self.sess.span_err(attr.span, "bad macro reexport"); } } } @@ -183,7 +185,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { } } - self.load_macros(item, macro_selection, Some(reexport)) + self.load_macros(item, import, reexport) } fn visit_mac(&mut self, _: &ast::Mac) { @@ -195,10 +197,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> { impl<'a> PluginLoader<'a> { pub fn load_macros<'b>(&mut self, vi: &ast::Item, - macro_selection: Option>, - reexport: Option>) { - if let (Some(sel), Some(re)) = (macro_selection.as_ref(), reexport.as_ref()) { - if sel.is_empty() && re.is_empty() { + import: Option, + reexport: MacroSelection) { + if let Some(sel) = import.as_ref() { + if sel.is_empty() && reexport.is_empty() { return; } } @@ -211,19 +213,32 @@ impl<'a> PluginLoader<'a> { let pmd = self.reader.read_plugin_metadata(CrateOrString::Krate(vi)); + let mut seen = HashSet::new(); for mut def in pmd.exported_macros() { let name = token::get_ident(def.ident); - def.use_locally = match macro_selection.as_ref() { + seen.insert(name.clone()); + + def.use_locally = match import.as_ref() { None => true, - Some(sel) => sel.contains(&name), - }; - def.export = if let Some(ref re) = reexport { - re.contains(&name) - } else { - false // Don't reexport macros from crates loaded from the command line + Some(sel) => sel.contains_key(&name), }; + def.export = reexport.contains_key(&name); self.plugins.macros.push(def); } + + if let Some(sel) = import.as_ref() { + for (name, span) in sel.iter() { + if !seen.contains(name) { + self.sess.span_err(*span, "imported macro not found"); + } + } + } + + for (name, span) in reexport.iter() { + if !seen.contains(name) { + self.sess.span_err(*span, "reexported macro not found"); + } + } } pub fn load_plugin<'b>(&mut self, diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/compile-fail/macro-reexport-undef.rs new file mode 100644 index 0000000000000..e9b3ceff83de4 --- /dev/null +++ b/src/test/compile-fail/macro-reexport-undef.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs +// ignore-stage1 + +#[macro_use(macro_two)] +#[macro_reexport(no_way)] //~ ERROR reexported macro not found +extern crate two_macros; + +pub fn main() { + macro_two!(); +} diff --git a/src/test/compile-fail/macro-use-undef.rs b/src/test/compile-fail/macro-use-undef.rs new file mode 100644 index 0000000000000..a5a350bd30e1a --- /dev/null +++ b/src/test/compile-fail/macro-use-undef.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs +// ignore-stage1 + +#[macro_use(macro_two, no_way)] //~ ERROR imported macro not found +extern crate two_macros; + +pub fn main() { + macro_two!(); +}