Skip to content

Commit 3a2c603

Browse files
committed
Auto merge of #53640 - alexcrichton:more-symbol-tweaks, r=michaelwoerister
rustc: Continue to tweak "std internal symbols" In investigating [an issue][1] with `panic_implementation` defined in an executable that's optimized I once again got to rethinking a bit about the `rustc_std_internal_symbol` attribute as well as weak lang items. We've sort of been non-stop tweaking these items ever since their inception, and this continues to the trend. The crux of the bug was that in the reachability we have a [different branch][2] for non-library builds which meant that weak lang items (and std internal symbols) weren't considered reachable, causing them to get eliminiated by ThinLTO passes. The fix was to basically tweak that branch to consider these symbols to ensure that they're propagated all the way to the linker. Along the way I've attempted to erode the distinction between std internal symbols and weak lang items by having weak lang items automatically configure fields of `CodegenFnAttrs`. That way most code no longer even considers weak lang items and they're simply considered normal functions with attributes about the ABI. In the end this fixes the final comment of #51342 [1]: #51342 (comment) [2]: https://github.com/rust-lang/rust/blob/35bf1ae25799a4e62131159f052e0a3cbd27c960/src/librustc/middle/reachable.rs#L225-L238
2 parents 51777b1 + 0a2282e commit 3a2c603

File tree

15 files changed

+151
-35
lines changed

15 files changed

+151
-35
lines changed

src/liballoc_jemalloc/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -89,25 +89,25 @@ mod contents {
8989
// linkage directives are provided as part of the current compiler allocator
9090
// ABI
9191

92-
#[no_mangle]
9392
#[rustc_std_internal_symbol]
93+
#[cfg_attr(stage0, no_mangle)]
9494
pub unsafe extern fn __rde_alloc(size: usize, align: usize) -> *mut u8 {
9595
let flags = align_to_flags(align, size);
9696
let ptr = mallocx(size as size_t, flags) as *mut u8;
9797
ptr
9898
}
9999

100-
#[no_mangle]
101100
#[rustc_std_internal_symbol]
101+
#[cfg_attr(stage0, no_mangle)]
102102
pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
103103
size: usize,
104104
align: usize) {
105105
let flags = align_to_flags(align, size);
106106
sdallocx(ptr as *mut c_void, size, flags);
107107
}
108108

109-
#[no_mangle]
110109
#[rustc_std_internal_symbol]
110+
#[cfg_attr(stage0, no_mangle)]
111111
pub unsafe extern fn __rde_realloc(ptr: *mut u8,
112112
_old_size: usize,
113113
align: usize,
@@ -117,8 +117,8 @@ mod contents {
117117
ptr
118118
}
119119

120-
#[no_mangle]
121120
#[rustc_std_internal_symbol]
121+
#[cfg_attr(stage0, no_mangle)]
122122
pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
123123
let ptr = if align <= MIN_ALIGN && align <= size {
124124
calloc(size as size_t, 1) as *mut u8

src/libpanic_abort/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
// Rust's "try" function, but if we're aborting on panics we just call the
3333
// function as there's nothing else we need to do here.
34-
#[no_mangle]
34+
#[cfg_attr(stage0, no_mangle)]
3535
#[rustc_std_internal_symbol]
3636
pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
3737
data: *mut u8,
@@ -51,7 +51,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
5151
// which would break compat with XP. For now just use `intrinsics::abort` which
5252
// will kill us with an illegal instruction, which will do a good enough job for
5353
// now hopefully.
54-
#[no_mangle]
54+
#[cfg_attr(stage0, no_mangle)]
5555
#[rustc_std_internal_symbol]
5656
pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
5757
abort();

src/librustc/hir/mod.rs

+35
Original file line numberDiff line numberDiff line change
@@ -2287,25 +2287,59 @@ pub fn provide(providers: &mut Providers) {
22872287
#[derive(Clone, RustcEncodable, RustcDecodable)]
22882288
pub struct CodegenFnAttrs {
22892289
pub flags: CodegenFnAttrFlags,
2290+
/// Parsed representation of the `#[inline]` attribute
22902291
pub inline: InlineAttr,
2292+
/// The `#[export_name = "..."]` attribute, indicating a custom symbol a
2293+
/// function should be exported under
22912294
pub export_name: Option<Symbol>,
2295+
/// The `#[link_name = "..."]` attribute, indicating a custom symbol an
2296+
/// imported function should be imported as. Note that `export_name`
2297+
/// probably isn't set when this is set, this is for foreign items while
2298+
/// `#[export_name]` is for Rust-defined functions.
2299+
pub link_name: Option<Symbol>,
2300+
/// The `#[target_feature(enable = "...")]` attribute and the enabled
2301+
/// features (only enabled features are supported right now).
22922302
pub target_features: Vec<Symbol>,
2303+
/// The `#[linkage = "..."]` attribute and the value we found.
22932304
pub linkage: Option<Linkage>,
2305+
/// The `#[link_section = "..."]` attribute, or what executable section this
2306+
/// should be placed in.
22942307
pub link_section: Option<Symbol>,
22952308
}
22962309

22972310
bitflags! {
22982311
#[derive(RustcEncodable, RustcDecodable)]
22992312
pub struct CodegenFnAttrFlags: u32 {
2313+
/// #[cold], a hint to LLVM that this function, when called, is never on
2314+
/// the hot path
23002315
const COLD = 1 << 0;
2316+
/// #[allocator], a hint to LLVM that the pointer returned from this
2317+
/// function is never null
23012318
const ALLOCATOR = 1 << 1;
2319+
/// #[unwind], an indicator that this function may unwind despite what
2320+
/// its ABI signature may otherwise imply
23022321
const UNWIND = 1 << 2;
2322+
/// #[rust_allocator_nounwind], an indicator that an imported FFI
2323+
/// function will never unwind. Probably obsolete by recent changes with
2324+
/// #[unwind], but hasn't been removed/migrated yet
23032325
const RUSTC_ALLOCATOR_NOUNWIND = 1 << 3;
2326+
/// #[naked], indicates to LLVM that no function prologue/epilogue
2327+
/// should be generated
23042328
const NAKED = 1 << 4;
2329+
/// #[no_mangle], the function's name should be the same as its symbol
23052330
const NO_MANGLE = 1 << 5;
2331+
/// #[rustc_std_internal_symbol], and indicator that this symbol is a
2332+
/// "weird symbol" for the standard library in that it has slightly
2333+
/// different linkage, visibility, and reachability rules.
23062334
const RUSTC_STD_INTERNAL_SYMBOL = 1 << 6;
2335+
/// #[no_debug], indicates that no debugging information should be
2336+
/// generated for this function by LLVM
23072337
const NO_DEBUG = 1 << 7;
2338+
/// #[thread_local], indicates a static is actually a thread local
2339+
/// piece of memory
23082340
const THREAD_LOCAL = 1 << 8;
2341+
/// #[used], indicates that LLVM can't eliminate this function (but the
2342+
/// linker can!)
23092343
const USED = 1 << 9;
23102344
}
23112345
}
@@ -2316,6 +2350,7 @@ impl CodegenFnAttrs {
23162350
flags: CodegenFnAttrFlags::empty(),
23172351
inline: InlineAttr::None,
23182352
export_name: None,
2353+
link_name: None,
23192354
target_features: vec![],
23202355
linkage: None,
23212356
link_section: None,

src/librustc/ich/impls_hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,7 @@ impl_stable_hash_for!(struct hir::CodegenFnAttrs {
11361136
flags,
11371137
inline,
11381138
export_name,
1139+
link_name,
11391140
target_features,
11401141
linkage,
11411142
link_section,

src/librustc/middle/reachable.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
231231
false
232232
};
233233
let def_id = self.tcx.hir.local_def_id(item.id);
234-
let is_extern = self.tcx.codegen_fn_attrs(def_id).contains_extern_indicator();
235-
if reachable || is_extern {
234+
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
235+
let is_extern = codegen_attrs.contains_extern_indicator();
236+
let std_internal = codegen_attrs.flags.contains(
237+
CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
238+
if reachable || is_extern || std_internal {
236239
self.reachable_symbols.insert(search_item);
237240
}
238241
}

src/librustc_allocator/expand.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,9 @@ impl<'a> AllocFnFactory<'a> {
236236
}
237237

238238
fn attrs(&self) -> Vec<Attribute> {
239-
let no_mangle = Symbol::intern("no_mangle");
240-
let no_mangle = self.cx.meta_word(self.span, no_mangle);
241-
242239
let special = Symbol::intern("rustc_std_internal_symbol");
243240
let special = self.cx.meta_word(self.span, special);
244-
vec![
245-
self.cx.attribute(self.span, no_mangle),
246-
self.cx.attribute(self.span, special),
247-
]
241+
vec![self.cx.attribute(self.span, special)]
248242
}
249243

250244
fn arg_ty(

src/librustc_codegen_utils/symbol_names.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@
9999
100100
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
101101
use rustc::hir::map as hir_map;
102+
use rustc::hir::CodegenFnAttrFlags;
102103
use rustc::hir::map::definitions::DefPathData;
103104
use rustc::ich::NodeIdHashingMode;
104-
use rustc::middle::weak_lang_items;
105105
use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
106106
use rustc::ty::query::Providers;
107107
use rustc::ty::subst::Substs;
@@ -111,7 +111,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
111111
use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
112112
use rustc_mir::monomorphize::Instance;
113113

114-
use syntax::attr;
115114
use syntax_pos::symbol::Symbol;
116115

117116
use std::fmt::Write;
@@ -260,7 +259,6 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
260259
}
261260

262261
// FIXME(eddyb) Precompute a custom symbol name based on attributes.
263-
let attrs = tcx.get_attrs(def_id);
264262
let is_foreign = if let Some(id) = node_id {
265263
match tcx.hir.get(id) {
266264
hir_map::NodeForeignItem(_) => true,
@@ -270,24 +268,21 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
270268
tcx.is_foreign_item(def_id)
271269
};
272270

273-
if let Some(name) = weak_lang_items::link_name(&attrs) {
274-
return name.to_string();
275-
}
276-
271+
let attrs = tcx.codegen_fn_attrs(def_id);
277272
if is_foreign {
278-
if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") {
273+
if let Some(name) = attrs.link_name {
279274
return name.to_string();
280275
}
281276
// Don't mangle foreign items.
282277
return tcx.item_name(def_id).to_string();
283278
}
284279

285-
if let Some(name) = tcx.codegen_fn_attrs(def_id).export_name {
280+
if let Some(name) = &attrs.export_name {
286281
// Use provided name
287282
return name.to_string();
288283
}
289284

290-
if attr::contains_name(&attrs, "no_mangle") {
285+
if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
291286
// Don't mangle
292287
return tcx.item_name(def_id).to_string();
293288
}

src/librustc_mir/monomorphize/collector.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,6 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> {
10231023
MonoItemCollectionMode::Lazy => {
10241024
self.entry_fn == Some(def_id) ||
10251025
self.tcx.is_reachable_non_generic(def_id) ||
1026-
self.tcx.is_weak_lang_item(def_id) ||
10271026
self.tcx.codegen_fn_attrs(def_id).flags.contains(
10281027
CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
10291028
}

src/librustc_mir/monomorphize/partitioning.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -516,10 +516,8 @@ fn mono_item_visibility(
516516
// visibility below. Like the weak lang items, though, we can't let
517517
// LLVM internalize them as this decision is left up to the linker to
518518
// omit them, so prevent them from being internalized.
519-
let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
520-
let std_internal_symbol = codegen_fn_attrs.flags
521-
.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
522-
if tcx.is_weak_lang_item(def_id) || std_internal_symbol {
519+
let attrs = tcx.codegen_fn_attrs(def_id);
520+
if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
523521
*can_be_internalized = false;
524522
}
525523

src/librustc_typeck/collect.rs

+23
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use constrained_type_params as ctp;
2929
use lint;
3030
use middle::lang_items::SizedTraitLangItem;
3131
use middle::resolve_lifetime as rl;
32+
use middle::weak_lang_items;
3233
use rustc::mir::mono::Linkage;
3334
use rustc::ty::query::Providers;
3435
use rustc::ty::subst::Substs;
@@ -2281,6 +2282,8 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
22812282
codegen_fn_attrs.link_section = Some(val);
22822283
}
22832284
}
2285+
} else if attr.check_name("link_name") {
2286+
codegen_fn_attrs.link_name = attr.value_str();
22842287
}
22852288
}
22862289

@@ -2300,5 +2303,25 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
23002303
}
23012304
}
23022305

2306+
// Weak lang items have the same semantics as "std internal" symbols in the
2307+
// sense that they're preserved through all our LTO passes and only
2308+
// strippable by the linker.
2309+
//
2310+
// Additionally weak lang items have predetermined symbol names.
2311+
if tcx.is_weak_lang_item(id) {
2312+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
2313+
}
2314+
if let Some(name) = weak_lang_items::link_name(&attrs) {
2315+
codegen_fn_attrs.export_name = Some(name);
2316+
codegen_fn_attrs.link_name = Some(name);
2317+
}
2318+
2319+
// Internal symbols to the standard library all have no_mangle semantics in
2320+
// that they have defined symbol names present in the function name. This
2321+
// also applies to weak symbols where they all have known symbol names.
2322+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
2323+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
2324+
}
2325+
23032326
codegen_fn_attrs
23042327
}

src/libstd/alloc.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,23 @@ pub mod __default_lib_allocator {
150150
// linkage directives are provided as part of the current compiler allocator
151151
// ABI
152152

153-
#[no_mangle]
154153
#[rustc_std_internal_symbol]
154+
#[cfg_attr(stage0, no_mangle)]
155155
pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
156156
let layout = Layout::from_size_align_unchecked(size, align);
157157
System.alloc(layout)
158158
}
159159

160-
#[no_mangle]
161160
#[rustc_std_internal_symbol]
161+
#[cfg_attr(stage0, no_mangle)]
162162
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
163163
size: usize,
164164
align: usize) {
165165
System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
166166
}
167167

168-
#[no_mangle]
169168
#[rustc_std_internal_symbol]
169+
#[cfg_attr(stage0, no_mangle)]
170170
pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
171171
old_size: usize,
172172
align: usize,
@@ -175,8 +175,8 @@ pub mod __default_lib_allocator {
175175
System.realloc(ptr, old_layout, new_size)
176176
}
177177

178-
#[no_mangle]
179178
#[rustc_std_internal_symbol]
179+
#[cfg_attr(stage0, no_mangle)]
180180
pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
181181
let layout = Layout::from_size_align_unchecked(size, align);
182182
System.alloc_zeroed(layout)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-include ../../run-make-fulldeps/tools.mk
2+
3+
ifeq ($(TARGET),wasm32-unknown-unknown)
4+
all:
5+
$(RUSTC) foo.rs --target wasm32-unknown-unknown
6+
$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
7+
$(RUSTC) foo.rs --target wasm32-unknown-unknown -C lto
8+
$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
9+
$(RUSTC) foo.rs --target wasm32-unknown-unknown -O
10+
$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
11+
$(RUSTC) foo.rs --target wasm32-unknown-unknown -O -C lto
12+
$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
13+
else
14+
all:
15+
endif
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "cdylib"]
12+
13+
#![feature(panic_implementation)]
14+
#![no_std]
15+
16+
use core::panic::PanicInfo;
17+
18+
#[no_mangle]
19+
pub extern fn foo() {
20+
panic!()
21+
}
22+
23+
#[panic_implementation]
24+
fn panic(_info: &PanicInfo) -> ! {
25+
loop {}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
const fs = require('fs');
12+
const process = require('process');
13+
const assert = require('assert');
14+
const buffer = fs.readFileSync(process.argv[2]);
15+
16+
let m = new WebAssembly.Module(buffer);
17+
let list = WebAssembly.Module.imports(m);
18+
console.log('imports', list);
19+
if (list.length !== 0)
20+
throw new Error("there are some imports");

src/test/ui/panic-handler/panic-handler-std.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ LL | | }
88
|
99
= note: first defined in crate `std`.
1010

11-
error: aborting due to previous error
11+
error: argument should be `&PanicInfo`
12+
--> $DIR/panic-handler-std.rs:18:16
13+
|
14+
LL | fn panic(info: PanicInfo) -> ! {
15+
| ^^^^^^^^^
16+
17+
error: aborting due to 2 previous errors
1218

1319
For more information about this error, try `rustc --explain E0152`.

0 commit comments

Comments
 (0)