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 2cef08725a2f6..0e4a4002d6a09 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 a542ee5d47d36..f32b42d9624d9 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 93d02de9b550e..ba358ada0adac 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} } 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 /// 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 { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 638ecf4572d5d..ef9bed45814b1 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -2080,12 +2080,26 @@ 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, + "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, + PRIVATE_NO_MANGLE_STATICS, + NO_MANGLE_CONST_ITEMS) } fn check_item(&mut self, cx: &Context, it: &ast::Item) { @@ -2098,6 +2112,23 @@ impl LintPass for PrivateNoMangleFns { cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg); } }, + 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") { + // 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); + } + } _ => {}, } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 18628f6903f5d..616af79326d9a 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/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a157d5d712b58..b2335f91ad986 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/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/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) => { diff --git a/src/test/compile-fail/lint-unexported-no-mangle.rs b/src/test/compile-fail/lint-unexported-no-mangle.rs index 3227a78c2ef00..216fcf9353578 100644 --- a/src/test/compile-fail/lint-unexported-no-mangle.rs +++ b/src/test/compile-fail/lint-unexported-no-mangle.rs @@ -8,17 +8,32 @@ // 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 -F private_no_mangle_statics // 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() { } +#[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(); 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!(); +} 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::<()>(); +}