Skip to content

rustc: Stabilize #[wasm_import_module] as #[link(...)] #52445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions src/librustc/hir/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,35 +65,14 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
.emit();
}

let mut has_wasm_import_module = false;
for attr in &item.attrs {
if attr.check_name("inline") {
self.check_inline(attr, &item.span, target)
} else if attr.check_name("non_exhaustive") {
self.check_non_exhaustive(attr, item, target)
} else if attr.check_name("wasm_import_module") {
has_wasm_import_module = true;
if attr.value_str().is_none() {
self.tcx.sess.span_err(attr.span, "\
must be of the form #[wasm_import_module = \"...\"]");
}
if target != Target::ForeignMod {
self.tcx.sess.span_err(attr.span, "\
must only be attached to foreign modules");
}
}
}

if target == Target::ForeignMod &&
!has_wasm_import_module &&
self.tcx.sess.target.target.arch == "wasm32" &&
false // FIXME: eventually enable this warning when stable
{
self.tcx.sess.span_warn(item.span, "\
must have a #[wasm_import_module = \"...\"] attribute, this \
will become a hard error before too long");
}

self.check_repr(item, target);
self.check_used(item, target);
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/ich/impls_cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ impl_stable_hash_for!(struct middle::cstore::NativeLibrary {
kind,
name,
cfg,
foreign_module
foreign_module,
wasm_import_module
});

impl_stable_hash_for!(struct middle::cstore::ForeignModule {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ pub enum NativeLibraryKind {
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct NativeLibrary {
pub kind: NativeLibraryKind,
pub name: Symbol,
pub name: Option<Symbol>,
pub cfg: Option<ast::MetaItem>,
pub foreign_module: Option<DefId>,
pub wasm_import_module: Option<Symbol>,
}

#[derive(Clone, Hash, RustcEncodable, RustcDecodable)]
Expand Down
21 changes: 15 additions & 6 deletions src/librustc_codegen_llvm/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,22 @@ pub fn provide(providers: &mut Providers) {

pub fn provide_extern(providers: &mut Providers) {
providers.wasm_import_module_map = |tcx, cnum| {
// Build up a map from DefId to a `NativeLibrary` structure, where
// `NativeLibrary` internally contains information about
// `#[link(wasm_import_module = "...")]` for example.
let native_libs = tcx.native_libraries(cnum);
let mut def_id_to_native_lib = FxHashMap();
for lib in native_libs.iter() {
if let Some(id) = lib.foreign_module {
def_id_to_native_lib.insert(id, lib);
}
}

let mut ret = FxHashMap();
for lib in tcx.foreign_modules(cnum).iter() {
let attrs = tcx.get_attrs(lib.def_id);
let mut module = None;
for attr in attrs.iter().filter(|a| a.check_name("wasm_import_module")) {
module = attr.value_str();
}
let module = def_id_to_native_lib
.get(&lib.def_id)
.and_then(|s| s.wasm_import_module);
let module = match module {
Some(s) => s,
None => continue,
Expand All @@ -244,7 +253,7 @@ pub fn provide_extern(providers: &mut Providers) {
}

Lrc::new(ret)
}
};
}

fn wasm_import_module(tcx: TyCtxt, id: DefId) -> Option<CString> {
Expand Down
59 changes: 36 additions & 23 deletions src/librustc_codegen_llvm/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,9 @@ fn link_rlib<'a>(sess: &'a Session,
NativeLibraryKind::NativeFramework |
NativeLibraryKind::NativeUnknown => continue,
}
ab.add_native_library(&lib.name.as_str());
if let Some(name) = lib.name {
ab.add_native_library(&name.as_str());
}
}

// After adding all files to the archive, we need to update the
Expand Down Expand Up @@ -583,21 +585,24 @@ fn link_staticlib(sess: &Session,
fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
let lib_args: Vec<_> = all_native_libs.iter()
.filter(|l| relevant_lib(sess, l))
.filter_map(|lib| match lib.kind {
NativeLibraryKind::NativeStaticNobundle |
NativeLibraryKind::NativeUnknown => {
if sess.target.target.options.is_like_msvc {
Some(format!("{}.lib", lib.name))
} else {
Some(format!("-l{}", lib.name))
}
},
NativeLibraryKind::NativeFramework => {
// ld-only syntax, since there are no frameworks in MSVC
Some(format!("-framework {}", lib.name))
},
// These are included, no need to print them
NativeLibraryKind::NativeStatic => None,
.filter_map(|lib| {
let name = lib.name?;
match lib.kind {
NativeLibraryKind::NativeStaticNobundle |
NativeLibraryKind::NativeUnknown => {
if sess.target.target.options.is_like_msvc {
Some(format!("{}.lib", name))
} else {
Some(format!("-l{}", name))
}
},
NativeLibraryKind::NativeFramework => {
// ld-only syntax, since there are no frameworks in MSVC
Some(format!("-framework {}", name))
},
// These are included, no need to print them
NativeLibraryKind::NativeStatic => None,
}
})
.collect();
if !lib_args.is_empty() {
Expand Down Expand Up @@ -1211,11 +1216,15 @@ fn add_local_native_libraries(cmd: &mut dyn Linker,

let search_path = archive_search_paths(sess);
for lib in relevant_libs {
let name = match lib.name {
Some(ref l) => l,
None => continue,
};
match lib.kind {
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()),
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()),
NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()),
NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(),
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()),
NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(),
&search_path)
}
}
Expand Down Expand Up @@ -1578,19 +1587,23 @@ fn add_upstream_native_libraries(cmd: &mut dyn Linker,
let crates = &codegen_results.crate_info.used_crates_static;
for &(cnum, _) in crates {
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
let name = match lib.name {
Some(ref l) => l,
None => continue,
};
if !relevant_lib(sess, &lib) {
continue
}
match lib.kind {
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()),
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()),
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
NativeLibraryKind::NativeStaticNobundle => {
// Link "static-nobundle" native libs only if the crate they originate from
// is being linked statically to the current crate. If it's linked dynamically
// or is an rlib already included via some other dylib crate, the symbols from
// native libs will have already been included in that dylib.
if data[cnum.as_usize() - 1] == Linkage::Static {
cmd.link_staticlib(&lib.name.as_str())
cmd.link_staticlib(&name.as_str())
}
},
// ignore statically included native libraries here as we've
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_codegen_llvm/back/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3;
///
/// This function is intended as a hack for now where we manually rewrite the
/// wasm output by LLVM to have the correct import modules listed. The
/// `#[wasm_import_module]` attribute in Rust translates to the module that each
/// symbol is imported from, so here we manually go through the wasm file,
/// decode it, rewrite imports, and then rewrite the wasm module.
/// `#[link(wasm_import_module = "...")]` attribute in Rust translates to the
/// module that each symbol is imported from, so here we manually go through the
/// wasm file, decode it, rewrite imports, and then rewrite the wasm module.
///
/// Support for this was added to LLVM in
/// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still
Expand Down
132 changes: 80 additions & 52 deletions src/librustc_metadata/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,56 +61,75 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
Some(item) => item,
None => continue,
};
let kind = items.iter().find(|k| {
k.check_name("kind")
}).and_then(|a| a.value_str()).map(Symbol::as_str);
let kind = match kind.as_ref().map(|s| &s[..]) {
Some("static") => cstore::NativeStatic,
Some("static-nobundle") => cstore::NativeStaticNobundle,
Some("dylib") => cstore::NativeUnknown,
Some("framework") => cstore::NativeFramework,
Some(k) => {
struct_span_err!(self.tcx.sess, m.span, E0458,
"unknown kind: `{}`", k)
.span_label(m.span, "unknown kind").emit();
cstore::NativeUnknown
}
None => cstore::NativeUnknown
};
let n = items.iter().find(|n| {
n.check_name("name")
}).and_then(|a| a.value_str());
let n = match n {
Some(n) => n,
None => {
struct_span_err!(self.tcx.sess, m.span, E0459,
"#[link(...)] specified without `name = \"foo\"`")
.span_label(m.span, "missing `name` argument").emit();
Symbol::intern("foo")
}
let mut lib = NativeLibrary {
name: None,
kind: cstore::NativeUnknown,
cfg: None,
foreign_module: Some(self.tcx.hir.local_def_id(it.id)),
wasm_import_module: None,
};
let cfg = items.iter().find(|k| {
k.check_name("cfg")
}).and_then(|a| a.meta_item_list());
let cfg = if let Some(list) = cfg {
if list.is_empty() {
self.tcx.sess.span_err(m.span(), "`cfg()` must have an argument");
return;
} else if let cfg @ Some(..) = list[0].meta_item() {
cfg.cloned()
let mut kind_specified = false;

for item in items.iter() {
if item.check_name("kind") {
kind_specified = true;
let kind = match item.value_str() {
Some(name) => name,
None => continue, // skip like historical compilers
};
lib.kind = match &kind.as_str()[..] {
"static" => cstore::NativeStatic,
"static-nobundle" => cstore::NativeStaticNobundle,
"dylib" => cstore::NativeUnknown,
"framework" => cstore::NativeFramework,
k => {
struct_span_err!(self.tcx.sess, m.span, E0458,
"unknown kind: `{}`", k)
.span_label(item.span, "unknown kind").emit();
cstore::NativeUnknown
}
};
} else if item.check_name("name") {
lib.name = item.value_str();
} else if item.check_name("cfg") {
let cfg = match item.meta_item_list() {
Some(list) => list,
None => continue, // skip like historical compilers
};
if cfg.is_empty() {
self.tcx.sess.span_err(
item.span(),
"`cfg()` must have an argument",
);
} else if let cfg @ Some(..) = cfg[0].meta_item() {
lib.cfg = cfg.cloned();
} else {
self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
}
} else if item.check_name("wasm_import_module") {
match item.value_str() {
Some(s) => lib.wasm_import_module = Some(s),
None => {
let msg = "must be of the form #[link(wasm_import_module = \"...\")]";
self.tcx.sess.span_err(item.span(), msg);
}
}
} else {
self.tcx.sess.span_err(list[0].span(), "invalid argument for `cfg(..)`");
return;
// currently, like past compilers, ignore unknown
// directives here.
}
} else {
None
};
let lib = NativeLibrary {
name: n,
kind,
cfg,
foreign_module: Some(self.tcx.hir.local_def_id(it.id)),
};
}

// In general we require #[link(name = "...")] but we allow
// #[link(wasm_import_module = "...")] without the `name`.
let requires_name = kind_specified || lib.wasm_import_module.is_none();
if lib.name.is_none() && requires_name {
struct_span_err!(self.tcx.sess, m.span, E0459,
"#[link(...)] specified without \
`name = \"foo\"`")
.span_label(m.span, "missing `name` argument")
.emit();
}
self.register_native_lib(Some(m.span), lib);
}
}
Expand All @@ -121,7 +140,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {

impl<'a, 'tcx> Collector<'a, 'tcx> {
fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
if lib.name.as_str().is_empty() {
if lib.name.as_ref().map(|s| s.as_str().is_empty()).unwrap_or(false) {
match span {
Some(span) => {
struct_span_err!(self.tcx.sess, span, E0454,
Expand Down Expand Up @@ -167,10 +186,14 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
let mut renames = FxHashSet();
for &(ref name, ref new_name, _) in &self.tcx.sess.opts.libs {
if let &Some(ref new_name) = new_name {
let any_duplicate = self.libs
.iter()
.filter_map(|lib| lib.name.as_ref())
.any(|n| n == name);
if new_name.is_empty() {
self.tcx.sess.err(
&format!("an empty renaming target was specified for library `{}`",name));
} else if !self.libs.iter().any(|lib| lib.name == name as &str) {
} else if !any_duplicate {
self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \
however this crate contains no #[link(...)] \
attributes referencing this library.", name));
Expand All @@ -189,14 +212,18 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
let mut found = false;
for lib in self.libs.iter_mut() {
if lib.name == name as &str {
let lib_name = match lib.name {
Some(n) => n,
None => continue,
};
if lib_name == name as &str {
let mut changed = false;
if let Some(k) = kind {
lib.kind = k;
changed = true;
}
if let &Some(ref new_name) = new_name {
lib.name = Symbol::intern(new_name);
lib.name = Some(Symbol::intern(new_name));
changed = true;
}
if !changed {
Expand All @@ -212,10 +239,11 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
// Add if not found
let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
let lib = NativeLibrary {
name: Symbol::intern(new_name.unwrap_or(name)),
name: Some(Symbol::intern(new_name.unwrap_or(name))),
kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
cfg: None,
foreign_module: None,
wasm_import_module: None,
};
self.register_native_lib(None, lib);
}
Expand Down
Loading