Skip to content

Commit f836ae4

Browse files
committed
Rollup merge of #48883 - alexcrichton:wasm-custom-sections, r=nikomatsakis
rustc: Add a `#[wasm_custom_section]` attribute This commit is an implementation of adding custom sections to wasm artifacts in rustc. The intention here is to expose the ability of the wasm binary format to contain custom sections with arbitrary user-defined data. Currently neither our version of LLVM nor LLD supports this so the implementation is currently custom to rustc itself. The implementation here is to attach a `#[wasm_custom_section = "foo"]` attribute to any `const` which has a type like `[u8; N]`. Other types of constants aren't supported yet but may be added one day! This should hopefully be enough to get off the ground with *some* custom section support. The current semantics are that any constant tagged with `#[wasm_custom_section]` section will be *appended* to the corresponding section in the final output wasm artifact (and this affects dependencies linked in as well, not just the final crate). This means that whatever is interpreting the contents must be able to interpret binary-concatenated sections (or each constant needs to be in its own custom section). To test this change the existing `run-make` test suite was moved to a `run-make-fulldeps` folder and a new `run-make` test suite was added which applies to all targets by default. This test suite currently only has one test which only runs for the wasm target (using a node.js script to use `WebAssembly` in JS to parse the wasm output).
2 parents 16eeb10 + d889957 commit f836ae4

File tree

591 files changed

+1145
-62
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

591 files changed

+1145
-62
lines changed

src/bootstrap/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ impl<'a> Builder<'a> {
313313
test::RunPassFullDepsPretty, test::RunFailFullDepsPretty,
314314
test::Crate, test::CrateLibrustc, test::CrateRustdoc, test::Linkcheck,
315315
test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck,
316+
test::RunMakeFullDeps,
316317
test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample,
317318
test::TheBook, test::UnstableBook,
318319
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme,

src/bootstrap/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ impl Step for Assemble {
915915
}
916916
}
917917

918-
let lld_install = if build.config.lld_enabled && target_compiler.stage > 0 {
918+
let lld_install = if build.config.lld_enabled {
919919
Some(builder.ensure(native::Lld {
920920
target: target_compiler.host,
921921
}))

src/bootstrap/test.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -759,12 +759,18 @@ test!(RunFailFullDepsPretty {
759759
host: true
760760
});
761761

762-
host_test!(RunMake {
762+
default_test!(RunMake {
763763
path: "src/test/run-make",
764764
mode: "run-make",
765765
suite: "run-make"
766766
});
767767

768+
host_test!(RunMakeFullDeps {
769+
path: "src/test/run-make-fulldeps",
770+
mode: "run-make",
771+
suite: "run-make-fulldeps"
772+
});
773+
768774
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
769775
struct Compiletest {
770776
compiler: Compiler,
@@ -827,8 +833,7 @@ impl Step for Compiletest {
827833
// FIXME: Does pretty need librustc compiled? Note that there are
828834
// fulldeps test suites with mode = pretty as well.
829835
mode == "pretty" ||
830-
mode == "rustdoc" ||
831-
mode == "run-make" {
836+
mode == "rustdoc" {
832837
builder.ensure(compile::Rustc { compiler, target });
833838
}
834839

@@ -849,7 +854,7 @@ impl Step for Compiletest {
849854
cmd.arg("--rustc-path").arg(builder.rustc(compiler));
850855

851856
// Avoid depending on rustdoc when we don't need it.
852-
if mode == "rustdoc" || mode == "run-make" {
857+
if mode == "rustdoc" || (mode == "run-make" && suite.ends_with("fulldeps")) {
853858
cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host));
854859
}
855860

@@ -931,7 +936,7 @@ impl Step for Compiletest {
931936

932937
// Only pass correct values for these flags for the `run-make` suite as it
933938
// requires that a C++ compiler was configured which isn't always the case.
934-
if suite == "run-make" {
939+
if suite == "run-make-fulldeps" {
935940
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
936941
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
937942
cmd.arg("--cc").arg(build.cc(target))
@@ -944,12 +949,12 @@ impl Step for Compiletest {
944949
}
945950
}
946951
}
947-
if suite == "run-make" && !build.config.llvm_enabled {
952+
if suite == "run-make-fulldeps" && !build.config.llvm_enabled {
948953
println!("Ignoring run-make test suite as they generally don't work without LLVM");
949954
return;
950955
}
951956

952-
if suite != "run-make" {
957+
if suite != "run-make-fulldeps" {
953958
cmd.arg("--cc").arg("")
954959
.arg("--cxx").arg("")
955960
.arg("--cflags").arg("")

src/ci/docker/wasm32-unknown/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ ENV RUST_CONFIGURE_ARGS \
2626
--set rust.lld
2727

2828
ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \
29+
src/test/run-make \
2930
src/test/ui \
3031
src/test/run-pass \
3132
src/test/compile-fail \

src/librustc/dep_graph/dep_node.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ define_dep_nodes!( <'tcx>
593593
[] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId },
594594
[] AllTraitImplementations(CrateNum),
595595

596+
[] DllimportForeignItems(CrateNum),
596597
[] IsDllimportForeignItem(DefId),
597598
[] IsStaticallyIncludedForeignItem(DefId),
598599
[] NativeLibraryKind(DefId),
@@ -650,9 +651,13 @@ define_dep_nodes!( <'tcx>
650651

651652
[] GetSymbolExportLevel(DefId),
652653

654+
[] WasmCustomSections(CrateNum),
655+
653656
[input] Features,
654657

655658
[] ProgramClausesFor(DefId),
659+
[] WasmImportModuleMap(CrateNum),
660+
[] ForeignModules(CrateNum),
656661
);
657662

658663
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {

src/librustc/hir/check_attr.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ enum Target {
2525
Struct,
2626
Union,
2727
Enum,
28+
Const,
29+
ForeignMod,
2830
Other,
2931
}
3032

@@ -35,6 +37,8 @@ impl Target {
3537
hir::ItemStruct(..) => Target::Struct,
3638
hir::ItemUnion(..) => Target::Union,
3739
hir::ItemEnum(..) => Target::Enum,
40+
hir::ItemConst(..) => Target::Const,
41+
hir::ItemForeignMod(..) => Target::ForeignMod,
3842
_ => Target::Other,
3943
}
4044
}
@@ -55,14 +59,42 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
5559
.emit();
5660
}
5761

62+
let mut has_wasm_import_module = false;
5863
for attr in &item.attrs {
59-
if let Some(name) = attr.name() {
60-
if name == "inline" {
61-
self.check_inline(attr, item, target)
64+
if attr.check_name("inline") {
65+
self.check_inline(attr, item, target)
66+
} else if attr.check_name("wasm_import_module") {
67+
has_wasm_import_module = true;
68+
if attr.value_str().is_none() {
69+
self.tcx.sess.span_err(attr.span, "\
70+
must be of the form #[wasm_import_module = \"...\"]");
71+
}
72+
if target != Target::ForeignMod {
73+
self.tcx.sess.span_err(attr.span, "\
74+
must only be attached to foreign modules");
75+
}
76+
} else if attr.check_name("wasm_custom_section") {
77+
if target != Target::Const {
78+
self.tcx.sess.span_err(attr.span, "only allowed on consts");
79+
}
80+
81+
if attr.value_str().is_none() {
82+
self.tcx.sess.span_err(attr.span, "must be of the form \
83+
#[wasm_custom_section = \"foo\"]");
6284
}
6385
}
6486
}
6587

88+
if target == Target::ForeignMod &&
89+
!has_wasm_import_module &&
90+
self.tcx.sess.target.target.arch == "wasm32" &&
91+
false // FIXME: eventually enable this warning when stable
92+
{
93+
self.tcx.sess.span_warn(item.span, "\
94+
must have a #[wasm_import_module = \"...\"] attribute, this \
95+
will become a hard error before too long");
96+
}
97+
6698
self.check_repr(item, target);
6799
}
68100

src/librustc/ich/impls_cstore.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ impl_stable_hash_for!(struct middle::cstore::NativeLibrary {
3333
kind,
3434
name,
3535
cfg,
36-
foreign_items
36+
foreign_module
37+
});
38+
39+
impl_stable_hash_for!(struct middle::cstore::ForeignModule {
40+
foreign_items,
41+
def_id
3742
});
3843

3944
impl_stable_hash_for!(enum middle::cstore::LinkagePreference {

src/librustc/middle/cstore.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,13 @@ pub struct NativeLibrary {
132132
pub kind: NativeLibraryKind,
133133
pub name: Symbol,
134134
pub cfg: Option<ast::MetaItem>,
135+
pub foreign_module: Option<DefId>,
136+
}
137+
138+
#[derive(Clone, Hash, RustcEncodable, RustcDecodable)]
139+
pub struct ForeignModule {
135140
pub foreign_items: Vec<DefId>,
141+
pub def_id: DefId,
136142
}
137143

138144
pub enum LoadedMacro {

src/librustc/middle/dead.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
318318
return true;
319319
}
320320

321+
// These constants are special for wasm
322+
if attr::contains_name(attrs, "wasm_custom_section") {
323+
return true;
324+
}
325+
321326
tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
322327
}
323328

src/librustc/ty/maps/config.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::native_libraries<'tcx> {
430430
}
431431
}
432432

433+
impl<'tcx> QueryDescription<'tcx> for queries::foreign_modules<'tcx> {
434+
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
435+
format!("looking up the foreign modules of a linked crate")
436+
}
437+
}
438+
433439
impl<'tcx> QueryDescription<'tcx> for queries::plugin_registrar_fn<'tcx> {
434440
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
435441
format!("looking up the plugin registrar for a crate")
@@ -678,6 +684,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx>
678684
}
679685
}
680686

687+
impl<'tcx> QueryDescription<'tcx> for queries::wasm_custom_sections<'tcx> {
688+
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
689+
format!("custom wasm sections for a crate")
690+
}
691+
}
692+
681693
impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> {
682694
#[inline]
683695
fn cache_on_disk(def_id: Self::Key) -> bool {
@@ -699,6 +711,18 @@ impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> {
699711
}
700712
}
701713

714+
impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> {
715+
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
716+
format!("wasm import module map")
717+
}
718+
}
719+
720+
impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> {
721+
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
722+
format!("wasm import module map")
723+
}
724+
}
725+
702726
macro_rules! impl_disk_cacheable_query(
703727
($query_name:ident, |$key:tt| $cond:expr) => {
704728
impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> {

0 commit comments

Comments
 (0)