about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-07-13 11:30:47 -0700
committerAlex Crichton <alex@alexcrichton.com>2018-07-16 09:40:45 -0700
commitb7ef674832c0d7e703e12f7880a928bf8cd0c9c5 (patch)
treede7e6f9b4ba9a23814eb1c8846a5a8f93e6739c1 /src
parent50702b28383c15907c29e8f70256cdd439800834 (diff)
downloadrust-b7ef674832c0d7e703e12f7880a928bf8cd0c9c5.tar.gz
rust-b7ef674832c0d7e703e12f7880a928bf8cd0c9c5.zip
rustc: Use link_section, not wasm_custom_section
This commit transitions definitions of custom sections on the wasm target from
the unstable `#[wasm_custom_section]` attribute to the
already-stable-for-other-targets `#[link_section]` attribute. Mostly the same
restrictions apply as before, except that this now applies only to statics.

Closes #51088
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/check_attr.rs4
-rw-r--r--src/librustc/hir/mod.rs24
-rw-r--r--src/librustc/ich/impls_hir.rs2
-rw-r--r--src/librustc/middle/dead.rs5
-rw-r--r--src/librustc/mir/mono.rs7
-rw-r--r--src/librustc_codegen_llvm/base.rs66
-rw-r--r--src/librustc_codegen_llvm/consts.rs45
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs15
-rw-r--r--src/librustc_mir/monomorphize/collector.rs10
-rw-r--r--src/librustc_mir/monomorphize/item.rs14
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs7
-rw-r--r--src/librustc_typeck/check/mod.rs49
-rw-r--r--src/librustc_typeck/collect.rs18
-rw-r--r--src/libsyntax/feature_gate.rs8
-rw-r--r--src/test/incremental/issue-49595/issue_49595.rs2
-rw-r--r--src/test/run-make/wasm-custom-section/bar.rs8
-rw-r--r--src/test/run-make/wasm-custom-section/foo.rs8
-rw-r--r--src/test/ui/feature-gate-wasm_custom_section.rs14
-rw-r--r--src/test/ui/feature-gate-wasm_custom_section.stderr11
-rw-r--r--src/test/ui/wasm-custom-section-relocations.rs (renamed from src/test/ui/wasm-custom-section/malformed.rs)16
-rw-r--r--src/test/ui/wasm-custom-section-relocations.stderr19
-rw-r--r--src/test/ui/wasm-custom-section/malformed.stderr14
-rw-r--r--src/test/ui/wasm-custom-section/not-const.rs29
-rw-r--r--src/test/ui/wasm-custom-section/not-const.stderr38
-rw-r--r--src/test/ui/wasm-custom-section/not-slice.rs22
-rw-r--r--src/test/ui/wasm-custom-section/not-slice.stderr20
26 files changed, 147 insertions, 328 deletions
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 3f6d34617c8..79d0aed10ed 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -81,10 +81,6 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                     self.tcx.sess.span_err(attr.span, "\
                         must only be attached to foreign modules");
                 }
-            } else if attr.check_name("wasm_custom_section") {
-                if target != Target::Const {
-                    self.tcx.sess.span_err(attr.span, "only allowed on consts");
-                }
             }
         }
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index c1a885d80bf..1df756d204d 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2266,20 +2266,22 @@ pub struct CodegenFnAttrs {
     pub export_name: Option<Symbol>,
     pub target_features: Vec<Symbol>,
     pub linkage: Option<Linkage>,
-    pub wasm_custom_section: Option<Symbol>,
+    pub link_section: Option<Symbol>,
 }
 
 bitflags! {
     #[derive(RustcEncodable, RustcDecodable)]
-    pub struct CodegenFnAttrFlags: u8 {
-        const COLD                      = 0b0000_0001;
-        const ALLOCATOR                 = 0b0000_0010;
-        const UNWIND                    = 0b0000_0100;
-        const RUSTC_ALLOCATOR_NOUNWIND  = 0b0000_1000;
-        const NAKED                     = 0b0001_0000;
-        const NO_MANGLE                 = 0b0010_0000;
-        const RUSTC_STD_INTERNAL_SYMBOL = 0b0100_0000;
-        const NO_DEBUG                  = 0b1000_0000;
+    pub struct CodegenFnAttrFlags: u32 {
+        const COLD                      = 1 << 0;
+        const ALLOCATOR                 = 1 << 1;
+        const UNWIND                    = 1 << 2;
+        const RUSTC_ALLOCATOR_NOUNWIND  = 1 << 3;
+        const NAKED                     = 1 << 4;
+        const NO_MANGLE                 = 1 << 5;
+        const RUSTC_STD_INTERNAL_SYMBOL = 1 << 6;
+        const NO_DEBUG                  = 1 << 7;
+        const THREAD_LOCAL              = 1 << 8;
+        const USED                      = 1 << 9;
     }
 }
 
@@ -2291,7 +2293,7 @@ impl CodegenFnAttrs {
             export_name: None,
             target_features: vec![],
             linkage: None,
-            wasm_custom_section: None,
+            link_section: None,
         }
     }
 
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index d1fb05ceafb..28f3f20a82b 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -1120,7 +1120,7 @@ impl_stable_hash_for!(struct hir::CodegenFnAttrs {
     export_name,
     target_features,
     linkage,
-    wasm_custom_section,
+    link_section,
 });
 
 impl<'hir> HashStable<StableHashingContext<'hir>> for hir::CodegenFnAttrFlags
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index da59bced760..126abb0d359 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -313,11 +313,6 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
         return true;
     }
 
-    // These constants are special for wasm
-    if attr::contains_name(attrs, "wasm_custom_section") {
-        return true;
-    }
-
     tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
 }
 
diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index 79566fbbc11..f0d6b8170eb 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -24,7 +24,6 @@ pub enum MonoItem<'tcx> {
     Fn(Instance<'tcx>),
     Static(DefId),
     GlobalAsm(NodeId),
-    CustomSection(DefId),
 }
 
 impl<'tcx> MonoItem<'tcx> {
@@ -38,8 +37,7 @@ impl<'tcx> MonoItem<'tcx> {
             // Conservatively estimate the size of a static declaration
             // or assembly to be 1.
             MonoItem::Static(_) |
-            MonoItem::GlobalAsm(_) |
-            MonoItem::CustomSection(_) => 1,
+            MonoItem::GlobalAsm(_) => 1,
         }
     }
 }
@@ -54,8 +52,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
             MonoItem::Fn(ref instance) => {
                 instance.hash_stable(hcx, hasher);
             }
-            MonoItem::Static(def_id) |
-            MonoItem::CustomSection(def_id) => {
+            MonoItem::Static(def_id) => {
                 def_id.hash_stable(hcx, hasher);
             }
             MonoItem::GlobalAsm(node_id) => {
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index d4d0b67523e..6d37f1ca3ca 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -33,7 +33,6 @@ use back::link;
 use back::write::{self, OngoingCodegen, create_target_machine};
 use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param};
 use llvm;
-use libc::c_uint;
 use metadata;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::middle::lang_items::StartFnLangItem;
@@ -87,8 +86,7 @@ use std::sync::mpsc;
 use syntax_pos::Span;
 use syntax_pos::symbol::InternedString;
 use syntax::attr;
-use rustc::hir;
-use syntax::ast;
+use rustc::hir::{self, CodegenFnAttrs};
 
 use mir::operand::OperandValue;
 
@@ -513,17 +511,14 @@ pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'
     mir::codegen_mir(cx, lldecl, &mir, instance, sig);
 }
 
-pub fn set_link_section(cx: &CodegenCx,
-                        llval: ValueRef,
-                        attrs: &[ast::Attribute]) {
-    if let Some(sect) = attr::first_attr_value_str_by_name(attrs, "link_section") {
-        if contains_null(&sect.as_str()) {
-            cx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", &sect));
-        }
-        unsafe {
-            let buf = CString::new(sect.as_str().as_bytes()).unwrap();
-            llvm::LLVMSetSection(llval, buf.as_ptr());
-        }
+pub fn set_link_section(llval: ValueRef, attrs: &CodegenFnAttrs) {
+    let sect = match attrs.link_section {
+        Some(name) => name,
+        None => return,
+    };
+    unsafe {
+        let buf = CString::new(sect.as_str().as_bytes()).unwrap();
+        llvm::LLVMSetSection(llval, buf.as_ptr());
     }
 }
 
@@ -613,10 +608,6 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) {
     }
 }
 
-fn contains_null(s: &str) -> bool {
-    s.bytes().any(|b| b == 0)
-}
-
 fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
                             llmod_id: &str,
                             link_meta: &LinkMeta)
@@ -1369,42 +1360,3 @@ mod temp_stable_hash_impls {
         }
     }
 }
-
-pub fn define_custom_section(cx: &CodegenCx, def_id: DefId) {
-    use rustc::mir::interpret::GlobalId;
-
-    assert!(cx.tcx.sess.opts.target_triple.triple().starts_with("wasm32"));
-
-    info!("loading wasm section {:?}", def_id);
-
-    let section = cx.tcx.codegen_fn_attrs(def_id).wasm_custom_section.unwrap();
-
-    let instance = ty::Instance::mono(cx.tcx, def_id);
-    let cid = GlobalId {
-        instance,
-        promoted: None
-    };
-    let param_env = ty::ParamEnv::reveal_all();
-    let val = cx.tcx.const_eval(param_env.and(cid)).unwrap();
-    let alloc = cx.tcx.const_value_to_allocation(val);
-
-    unsafe {
-        let section = llvm::LLVMMDStringInContext(
-            cx.llcx,
-            section.as_str().as_ptr() as *const _,
-            section.as_str().len() as c_uint,
-        );
-        let alloc = llvm::LLVMMDStringInContext(
-            cx.llcx,
-            alloc.bytes.as_ptr() as *const _,
-            alloc.bytes.len() as c_uint,
-        );
-        let data = [section, alloc];
-        let meta = llvm::LLVMMDNodeInContext(cx.llcx, data.as_ptr(), 2);
-        llvm::LLVMAddNamedMetadataOperand(
-            cx.llmod,
-            "wasm.custom_sections\0".as_ptr() as *const _,
-            meta,
-        );
-    }
-}
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 6e3096d4cd5..5c00947889d 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use libc::c_uint;
 use llvm;
 use llvm::{SetUnnamedAddr};
 use llvm::{ValueRef, True};
@@ -24,11 +25,9 @@ use type_of::LayoutLlvmExt;
 use rustc::ty;
 use rustc::ty::layout::{Align, LayoutOf};
 
-use rustc::hir;
+use rustc::hir::{self, CodegenFnAttrFlags};
 
 use std::ffi::{CStr, CString};
-use syntax::ast;
-use syntax::attr;
 
 pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
     unsafe {
@@ -244,11 +243,10 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
 }
 
 pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                              def_id: DefId,
-                              is_mutable: bool,
-                              attrs: &[ast::Attribute]) {
+                                def_id: DefId,
+                                is_mutable: bool) {
     unsafe {
-        let g = get_static(cx, def_id);
+        let attrs = cx.tcx.codegen_fn_attrs(def_id);
 
         let (v, alloc) = match ::mir::codegen_static_initializer(cx, def_id) {
             Ok(v) => v,
@@ -256,6 +254,8 @@ pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             Err(_) => return,
         };
 
+        let g = get_static(cx, def_id);
+
         // boolean SSA values are i1, but they have to be stored in i8 slots,
         // otherwise some LLVM optimization passes don't work as expected
         let mut val_llty = val_ty(v);
@@ -307,7 +307,7 @@ pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
         debuginfo::create_global_var_metadata(cx, def_id, g);
 
-        if attr::contains_name(attrs, "thread_local") {
+        if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
             llvm::set_thread_local_mode(g, cx.tls_model);
 
             // Do not allow LLVM to change the alignment of a TLS on macOS.
@@ -349,9 +349,34 @@ pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             }
         }
 
-        base::set_link_section(cx, g, attrs);
 
-        if attr::contains_name(attrs, "used") {
+        // Wasm statics with custom link sections get special treatment as they
+        // go into custom sections of the wasm executable.
+        if cx.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+            if let Some(section) = attrs.link_section {
+                let section = llvm::LLVMMDStringInContext(
+                    cx.llcx,
+                    section.as_str().as_ptr() as *const _,
+                    section.as_str().len() as c_uint,
+                );
+                let alloc = llvm::LLVMMDStringInContext(
+                    cx.llcx,
+                    alloc.bytes.as_ptr() as *const _,
+                    alloc.bytes.len() as c_uint,
+                );
+                let data = [section, alloc];
+                let meta = llvm::LLVMMDNodeInContext(cx.llcx, data.as_ptr(), 2);
+                llvm::LLVMAddNamedMetadataOperand(
+                    cx.llmod,
+                    "wasm.custom_sections\0".as_ptr() as *const _,
+                    meta,
+                );
+            }
+        } else {
+            base::set_link_section(g, &attrs);
+        }
+
+        if attrs.flags.contains(CodegenFnAttrFlags::USED) {
             // This static will be stored in the llvm.used variable which is an array of i8*
             let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref());
             cx.used_statics.borrow_mut().push(cast);
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index b512a6f1bb4..a528008e3b4 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -54,9 +54,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
                         bug!("Expected Def::Static for {:?}, found nothing", def_id)
                     }
                 };
-                let attrs = tcx.get_attrs(def_id);
-
-                consts::codegen_static(&cx, def_id, is_mutable, &attrs);
+                consts::codegen_static(&cx, def_id, is_mutable);
             }
             MonoItem::GlobalAsm(node_id) => {
                 let item = cx.tcx.hir.expect_item(node_id);
@@ -66,9 +64,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
                     span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type")
                 }
             }
-            MonoItem::CustomSection(def_id) => {
-                base::define_custom_section(cx, def_id);
-            }
             MonoItem::Fn(instance) => {
                 base::codegen_instance(&cx, instance);
             }
@@ -100,7 +95,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
             MonoItem::Fn(instance) => {
                 predefine_fn(cx, instance, linkage, visibility, &symbol_name);
             }
-            MonoItem::CustomSection(..) => {}
             MonoItem::GlobalAsm(..) => {}
         }
 
@@ -120,9 +114,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
             MonoItem::Static(id) => {
                 format!("Static({:?})", id)
             }
-            MonoItem::CustomSection(id) => {
-                format!("CustomSection({:?})", id)
-            }
             MonoItem::GlobalAsm(id) => {
                 format!("GlobalAsm({:?})", id)
             }
@@ -164,10 +155,10 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             !instance.substs.has_param_types());
 
     let mono_ty = instance.ty(cx.tcx);
-    let attrs = instance.def.attrs(cx.tcx);
+    let attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
     let lldecl = declare::declare_fn(cx, symbol_name, mono_ty);
     unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
-    base::set_link_section(cx, lldecl, &attrs);
+    base::set_link_section(lldecl, &attrs);
     if linkage == Linkage::LinkOnceODR ||
         linkage == Linkage::WeakODR {
         llvm::SetUniqueComdat(cx.llmod, lldecl);
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index a2d620db924..2f983e25acd 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -414,9 +414,6 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         MonoItem::GlobalAsm(..) => {
             recursion_depth_reset = None;
         }
-        MonoItem::CustomSection(..) => {
-            recursion_depth_reset = None;
-        }
     }
 
     record_accesses(tcx, starting_point, &neighbors[..], inlining_map);
@@ -993,13 +990,6 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
             hir::ItemKind::Const(..) => {
                 // const items only generate mono items if they are
                 // actually used somewhere. Just declaring them is insufficient.
-
-                let def_id = self.tcx.hir.local_def_id(item.id);
-                if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") &&
-                    self.tcx.codegen_fn_attrs(def_id).wasm_custom_section.is_some()
-                {
-                    self.output.push(MonoItem::CustomSection(def_id));
-                }
             }
             hir::ItemKind::Fn(..) => {
                 let def_id = self.tcx.hir.local_def_id(item.id);
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index 1389ad63c3a..95968c0ea4f 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -63,7 +63,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
                 instance.substs.types().next().is_some()
             }
             MonoItem::Static(..) |
-            MonoItem::CustomSection(..) |
             MonoItem::GlobalAsm(..) => false,
         }
     }
@@ -74,9 +73,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
             MonoItem::Static(def_id) => {
                 tcx.symbol_name(Instance::mono(tcx, def_id))
             }
-            MonoItem::CustomSection(def_id) => {
-                tcx.symbol_name(Instance::mono(tcx, def_id))
-            }
             MonoItem::GlobalAsm(node_id) => {
                 let def_id = tcx.hir.local_def_id(node_id);
                 ty::SymbolName {
@@ -126,7 +122,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
                 }
             }
             MonoItem::Static(..) |
-            MonoItem::CustomSection(..) |
             MonoItem::GlobalAsm(..) => {
                 InstantiationMode::GloballyShared { may_conflict: false }
             }
@@ -137,7 +132,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
         let def_id = match *self.as_mono_item() {
             MonoItem::Fn(ref instance) => instance.def_id(),
             MonoItem::Static(def_id) => def_id,
-            MonoItem::CustomSection(..) => return None,
             MonoItem::GlobalAsm(..) => return None,
         };
 
@@ -175,7 +169,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
         let (def_id, substs) = match *self.as_mono_item() {
             MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs),
             MonoItem::Static(def_id) => (def_id, Substs::empty()),
-            MonoItem::CustomSection(..) => return true,
             // global asm never has predicates
             MonoItem::GlobalAsm(..) => return true
         };
@@ -192,10 +185,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
                 let instance = Instance::new(def_id, tcx.intern_substs(&[]));
                 to_string_internal(tcx, "static ", instance)
             },
-            MonoItem::CustomSection(def_id) => {
-                let instance = Instance::new(def_id, tcx.intern_substs(&[]));
-                to_string_internal(tcx, "custom-section ", instance)
-            },
             MonoItem::GlobalAsm(..) => {
                 "global_asm".to_string()
             }
@@ -221,9 +210,6 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
             MonoItem::Static(def_id) => {
                 tcx.hir.as_local_node_id(def_id)
             }
-            MonoItem::CustomSection(def_id) => {
-                tcx.hir.as_local_node_id(def_id)
-            }
             MonoItem::GlobalAsm(node_id) => {
                 Some(node_id)
             }
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 5f15870d6fb..f83ea6fa13b 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -180,8 +180,7 @@ pub trait CodegenUnitExt<'tcx> {
                         }
                     }
                 }
-                MonoItem::Static(def_id) |
-                MonoItem::CustomSection(def_id) => {
+                MonoItem::Static(def_id) => {
                     tcx.hir.as_local_node_id(def_id)
                 }
                 MonoItem::GlobalAsm(node_id) => {
@@ -450,9 +449,6 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         };
                         (Linkage::External, visibility)
                     }
-                    MonoItem::CustomSection(..) => {
-                        (Linkage::External, Visibility::Hidden)
-                    }
                     MonoItem::GlobalAsm(node_id) => {
                         let def_id = tcx.hir.local_def_id(node_id);
                         let visibility = if tcx.is_reachable_non_generic(def_id) {
@@ -718,7 +714,6 @@ fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             Some(def_id)
         }
         MonoItem::Static(def_id) => Some(def_id),
-        MonoItem::CustomSection(def_id) => Some(def_id),
         MonoItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)),
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9f83f8a00b1..53d1e6008b8 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1270,14 +1270,12 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
       hir::ItemKind::Static(..) => {
-        tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
+        let def_id = tcx.hir.local_def_id(it.id);
+        tcx.typeck_tables_of(def_id);
+        maybe_check_static_with_link_section(tcx, def_id, it.span);
       }
       hir::ItemKind::Const(..) => {
         tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
-        if it.attrs.iter().any(|a| a.check_name("wasm_custom_section")) {
-            let def_id = tcx.hir.local_def_id(it.id);
-            check_const_is_u8_array(tcx, def_id, it.span);
-        }
       }
       hir::ItemKind::Enum(ref enum_definition, _) => {
         check_enum(tcx,
@@ -1350,19 +1348,38 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
     }
 }
 
-fn check_const_is_u8_array<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     def_id: DefId,
-                                     span: Span) {
-    match tcx.type_of(def_id).sty {
-        ty::TyArray(t, _) => {
-            match t.sty {
-                ty::TyUint(ast::UintTy::U8) => return,
-                _ => {}
-            }
+fn maybe_check_static_with_link_section(tcx: TyCtxt, id: DefId, span: Span) {
+    // Only restricted on wasm32 target for now
+    if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+        return
+    }
+
+    // If `#[link_section]` is missing, then nothing to verify
+    let attrs = tcx.codegen_fn_attrs(id);
+    if attrs.link_section.is_none() {
+        return
+    }
+
+    // For the wasm32 target statics with #[link_section] are placed into custom
+    // sections of the final output file, but this isn't link custom sections of
+    // other executable formats. Namely we can only embed a list of bytes,
+    // nothing with pointers to anything else or relocations. If any relocation
+    // show up, reject them here.
+    let instance = ty::Instance::mono(tcx, id);
+    let cid = GlobalId {
+        instance,
+        promoted: None
+    };
+    let param_env = ty::ParamEnv::reveal_all();
+    if let Ok(static_) = tcx.const_eval(param_env.and(cid)) {
+        let alloc = tcx.const_value_to_allocation(static_);
+        if alloc.relocations.len() != 0 {
+            let msg = "statics with a custom `#[link_section]` must be a \
+                       simple list of bytes on the wasm target with no \
+                       extra levels of indirection such as references";
+            tcx.sess.span_err(span, msg);
         }
-        _ => {}
     }
-    tcx.sess.span_err(span, "must be an array of bytes like `[u8; N]`");
 }
 
 fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 4b628d6ffad..03fa7f521d9 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1867,6 +1867,10 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
         } else if attr.check_name("no_debug") {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_DEBUG;
+        } else if attr.check_name("used") {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+        } else if attr.check_name("thread_local") {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
         } else if attr.check_name("inline") {
             codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
                 if attr.path != "inline" {
@@ -1929,12 +1933,14 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
             if let Some(val) = attr.value_str() {
                 codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
             }
-        } else if attr.check_name("wasm_custom_section") {
-            match attr.value_str() {
-                Some(name) => codegen_fn_attrs.wasm_custom_section = Some(name),
-                None => {
-                    tcx.sess.span_err(attr.span, "must be of the form \
-                        #[wasm_custom_section = \"foo\"]");
+        } else if attr.check_name("link_section") {
+            if let Some(val) = attr.value_str() {
+                if val.as_str().bytes().any(|b| b == 0) {
+                    let msg = format!("illegal null byte in link_section \
+                                       value: `{}`", &val);
+                    tcx.sess.span_err(attr.span, &msg);
+                } else {
+                    codegen_fn_attrs.link_section = Some(val);
                 }
             }
         }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index f033c5006c5..189a36427db 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -417,9 +417,6 @@ declare_features! (
     // `use path as _;` and `extern crate c as _;`
     (active, underscore_imports, "1.26.0", Some(48216), None),
 
-    // The #[wasm_custom_section] attribute
-    (active, wasm_custom_section, "1.26.0", Some(51088), None),
-
     // The #![wasm_import_module] attribute
     (active, wasm_import_module, "1.26.0", Some(52090), None),
 
@@ -1077,11 +1074,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                    "infer outlives requirements is an experimental feature",
                                    cfg_fn!(infer_outlives_requirements))),
 
-    ("wasm_custom_section", Whitelisted, Gated(Stability::Unstable,
-                                 "wasm_custom_section",
-                                 "attribute is currently unstable",
-                                 cfg_fn!(wasm_custom_section))),
-
     // RFC 2070
     ("panic_implementation", Normal, Gated(Stability::Unstable,
                            "panic_implementation",
diff --git a/src/test/incremental/issue-49595/issue_49595.rs b/src/test/incremental/issue-49595/issue_49595.rs
index dfa92d425f4..134f114e6ac 100644
--- a/src/test/incremental/issue-49595/issue_49595.rs
+++ b/src/test/incremental/issue-49595/issue_49595.rs
@@ -15,7 +15,7 @@
 #![feature(rustc_attrs)]
 #![crate_type = "rlib"]
 
-#![rustc_partition_codegened(module="issue_49595-tests", cfg="cfail2")]
+#![rustc_partition_codegened(module="issue_49595-__test", cfg="cfail2")]
 #![rustc_partition_codegened(module="issue_49595-lit_test", cfg="cfail3")]
 
 mod tests {
diff --git a/src/test/run-make/wasm-custom-section/bar.rs b/src/test/run-make/wasm-custom-section/bar.rs
index e3db36d6dbd..ed537280e6c 100644
--- a/src/test/run-make/wasm-custom-section/bar.rs
+++ b/src/test/run-make/wasm-custom-section/bar.rs
@@ -14,11 +14,11 @@
 
 extern crate foo;
 
-#[wasm_custom_section = "foo"]
-const A: [u8; 2] = [5, 6];
+#[link_section = "foo"]
+pub static A: [u8; 2] = [5, 6];
 
-#[wasm_custom_section = "baz"]
-const B: [u8; 2] = [7, 8];
+#[link_section = "baz"]
+pub static B: [u8; 2] = [7, 8];
 
 #[no_mangle]
 pub extern fn foo() {}
diff --git a/src/test/run-make/wasm-custom-section/foo.rs b/src/test/run-make/wasm-custom-section/foo.rs
index 44d1efd7c2d..fb3bec31ada 100644
--- a/src/test/run-make/wasm-custom-section/foo.rs
+++ b/src/test/run-make/wasm-custom-section/foo.rs
@@ -12,8 +12,8 @@
 #![feature(wasm_custom_section)]
 #![deny(warnings)]
 
-#[wasm_custom_section = "foo"]
-const A: [u8; 2] = [1, 2];
+#[link_section = "foo"]
+pub static A: [u8; 2] = [1, 2];
 
-#[wasm_custom_section = "bar"]
-const B: [u8; 2] = [3, 4];
+#[link_section = "bar"]
+pub static B: [u8; 2] = [3, 4];
diff --git a/src/test/ui/feature-gate-wasm_custom_section.rs b/src/test/ui/feature-gate-wasm_custom_section.rs
deleted file mode 100644
index c695ef4ff06..00000000000
--- a/src/test/ui/feature-gate-wasm_custom_section.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2018 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[wasm_custom_section = "foo"] //~ ERROR: attribute is currently unstable
-const A: [u8; 2] = [1, 2];
-
-fn main() {}
diff --git a/src/test/ui/feature-gate-wasm_custom_section.stderr b/src/test/ui/feature-gate-wasm_custom_section.stderr
deleted file mode 100644
index 91f75d6817f..00000000000
--- a/src/test/ui/feature-gate-wasm_custom_section.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: attribute is currently unstable (see issue #51088)
-  --> $DIR/feature-gate-wasm_custom_section.rs:11:1
-   |
-LL | #[wasm_custom_section = "foo"] //~ ERROR: attribute is currently unstable
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(wasm_custom_section)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/wasm-custom-section/malformed.rs b/src/test/ui/wasm-custom-section-relocations.rs
index 13b1685a480..5631a70192a 100644
--- a/src/test/ui/wasm-custom-section/malformed.rs
+++ b/src/test/ui/wasm-custom-section-relocations.rs
@@ -8,12 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(wasm_custom_section)]
+// only-wasm32
 
-#[wasm_custom_section] //~ ERROR: must be of the form
-const A: [u8; 1] = [0];
+#[link_section = "test"]
+pub static A: &[u8] = &[1]; //~ ERROR: no extra levels of indirection
 
-#[wasm_custom_section(foo)] //~ ERROR: must be of the form
-const B: [u8; 1] = [0];
+#[link_section = "test"]
+pub static B: [u8; 3] = [1, 2, 3];
 
-fn main() {}
+#[link_section = "test"]
+pub static C: usize = 3;
+
+#[link_section = "test"]
+pub static D: &usize = &C; //~ ERROR: no extra levels of indirection
diff --git a/src/test/ui/wasm-custom-section-relocations.stderr b/src/test/ui/wasm-custom-section-relocations.stderr
new file mode 100644
index 00000000000..9b96b99e02a
--- /dev/null
+++ b/src/test/ui/wasm-custom-section-relocations.stderr
@@ -0,0 +1,19 @@
+error[E0601]: `main` function not found in crate `wasm_custom_section_relocations`
+   |
+   = note: consider adding a `main` function to `$DIR/wasm-custom-section-relocations.rs`
+
+error: statics with a custom `#[link_section]` must be a simple list of bytes on the wasm target with no extra levels of indirection such as references
+  --> $DIR/wasm-custom-section-relocations.rs:14:1
+   |
+LL | pub static A: &[u8] = &[1]; //~ ERROR: no extra levels of indirection
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: statics with a custom `#[link_section]` must be a simple list of bytes on the wasm target with no extra levels of indirection such as references
+  --> $DIR/wasm-custom-section-relocations.rs:23:1
+   |
+LL | pub static D: &usize = &C; //~ ERROR: no extra levels of indirection
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/wasm-custom-section/malformed.stderr b/src/test/ui/wasm-custom-section/malformed.stderr
deleted file mode 100644
index c716c824aeb..00000000000
--- a/src/test/ui/wasm-custom-section/malformed.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: must be of the form #[wasm_custom_section = "foo"]
-  --> $DIR/malformed.rs:13:1
-   |
-LL | #[wasm_custom_section] //~ ERROR: must be of the form
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: must be of the form #[wasm_custom_section = "foo"]
-  --> $DIR/malformed.rs:16:1
-   |
-LL | #[wasm_custom_section(foo)] //~ ERROR: must be of the form
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/wasm-custom-section/not-const.rs b/src/test/ui/wasm-custom-section/not-const.rs
deleted file mode 100644
index 68077fb2fe4..00000000000
--- a/src/test/ui/wasm-custom-section/not-const.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2018 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(wasm_custom_section)]
-
-#[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-static A: [u8; 2] = [1, 2];
-
-#[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-struct B {}
-
-#[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-enum C {}
-
-#[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-impl B {}
-
-#[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-mod d {}
-
-#[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-fn main() {}
diff --git a/src/test/ui/wasm-custom-section/not-const.stderr b/src/test/ui/wasm-custom-section/not-const.stderr
deleted file mode 100644
index 17c85b3e848..00000000000
--- a/src/test/ui/wasm-custom-section/not-const.stderr
+++ /dev/null
@@ -1,38 +0,0 @@
-error: only allowed on consts
-  --> $DIR/not-const.rs:13:1
-   |
-LL | #[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: only allowed on consts
-  --> $DIR/not-const.rs:16:1
-   |
-LL | #[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: only allowed on consts
-  --> $DIR/not-const.rs:19:1
-   |
-LL | #[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: only allowed on consts
-  --> $DIR/not-const.rs:22:1
-   |
-LL | #[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: only allowed on consts
-  --> $DIR/not-const.rs:25:1
-   |
-LL | #[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: only allowed on consts
-  --> $DIR/not-const.rs:28:1
-   |
-LL | #[wasm_custom_section = "foo"] //~ ERROR: only allowed on consts
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 6 previous errors
-
diff --git a/src/test/ui/wasm-custom-section/not-slice.rs b/src/test/ui/wasm-custom-section/not-slice.rs
deleted file mode 100644
index 2d91641a5f7..00000000000
--- a/src/test/ui/wasm-custom-section/not-slice.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(wasm_custom_section)]
-
-#[wasm_custom_section = "foo"]
-const A: u8 = 0; //~ ERROR: must be an array of bytes
-
-#[wasm_custom_section = "foo"]
-const B: &[u8] = &[0]; //~ ERROR: must be an array of bytes
-
-#[wasm_custom_section = "foo"]
-const C: &[u8; 1] = &[0]; //~ ERROR: must be an array of bytes
-
-fn main() {}
diff --git a/src/test/ui/wasm-custom-section/not-slice.stderr b/src/test/ui/wasm-custom-section/not-slice.stderr
deleted file mode 100644
index f2563ce0ddd..00000000000
--- a/src/test/ui/wasm-custom-section/not-slice.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: must be an array of bytes like `[u8; N]`
-  --> $DIR/not-slice.rs:14:1
-   |
-LL | const A: u8 = 0; //~ ERROR: must be an array of bytes
-   | ^^^^^^^^^^^^^^^^
-
-error: must be an array of bytes like `[u8; N]`
-  --> $DIR/not-slice.rs:17:1
-   |
-LL | const B: &[u8] = &[0]; //~ ERROR: must be an array of bytes
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: must be an array of bytes like `[u8; N]`
-  --> $DIR/not-slice.rs:20:1
-   |
-LL | const C: &[u8; 1] = &[0]; //~ ERROR: must be an array of bytes
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-