Skip to content

Commit 8c4d880

Browse files
committed
Auto merge of #31539 - michaelwoerister:stable-symbols, r=nikomatsakis
WIP: Implement stable symbol-name generation algorithm. This PR changes the way symbol names are generated by the compiler. The new algorithm reflects the current state of the discussion over at rust-lang/rfcs#689. Once it is done, it will also fix issue #30330. I want to add a test case for that before closing it though. I also want to do some performance tests. The new algorithm does a little more work than the previous one due to various reasons, and it might make sense to adapt it in a way that allows it to be implemented more efficiently. @nikomatsakis: It would be nice if there was a way of finding out if a `DefPath` refers to something in the current crate or in an external one. The information is already there, it's just not accessible at the moment. I'll probably propose some minor changes there, together with some facilities to allow for accessing `DefPaths` without allocating a `Vec` for them. **TODO** - ~~Actually "crate qualify" symbols, as promised in the docs.~~ - ~~Add a test case showing that symbol names are deterministic~~. - Maybe add a test case showing that symbol names are stable against small code changes. ~~One thing that might be interesting to the @rust-lang/compiler team: I've used SipHash exclusively now for generating symbol hashes. Previously it was only used for monomorphizations and the rest of the code used a truncated version on SHA256. Is there any benefit to sticking to SHA? I don't really see one since we only used 64 bits of the digest anyway, but maybe I'm missing something?~~ ==> Just switched things back to SHA-2 for now.
2 parents 483fc71 + f6b0f17 commit 8c4d880

Some content is hidden

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

66 files changed

+1038
-389
lines changed

mk/tests.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ $(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)): \
383383
@$$(call E, rustc: $$@)
384384
$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(2)) \
385385
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \
386-
-L "$$(RT_OUTPUT_DIR_$(2))" \
386+
-Cmetadata="test-crate" -L "$$(RT_OUTPUT_DIR_$(2))" \
387387
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
388388
$$(RUSTFLAGS_$(4))
389389

src/compiletest/common.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ impl fmt::Display for Mode {
6969
#[derive(Clone)]
7070
pub struct Config {
7171
// The library paths required for running the compiler
72-
pub compile_lib_path: String,
72+
pub compile_lib_path: PathBuf,
7373

7474
// The library paths required for running compiled programs
75-
pub run_lib_path: String,
75+
pub run_lib_path: PathBuf,
7676

7777
// The rustc executable
7878
pub rustc_path: PathBuf,

src/compiletest/compiletest.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,23 @@ pub fn parse_config(args: Vec<String> ) -> Config {
116116
}
117117
}
118118

119+
fn make_absolute(path: PathBuf) -> PathBuf {
120+
if path.is_relative() {
121+
env::current_dir().unwrap().join(path)
122+
} else {
123+
path
124+
}
125+
}
126+
127+
let filter = if !matches.free.is_empty() {
128+
Some(matches.free[0].clone())
129+
} else {
130+
None
131+
};
132+
119133
Config {
120-
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
121-
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
134+
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
135+
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
122136
rustc_path: opt_path(matches, "rustc-path"),
123137
rustdoc_path: opt_path(matches, "rustdoc-path"),
124138
python: matches.opt_str("python").unwrap(),

src/compiletest/runtest.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ fn run_pretty_test_revision(config: &Config,
316316
testpaths,
317317
pretty_type.to_owned()),
318318
props.exec_env.clone(),
319-
&config.compile_lib_path,
319+
config.compile_lib_path.to_str().unwrap(),
320320
Some(aux_dir.to_str().unwrap()),
321321
Some(src))
322322
}
@@ -635,7 +635,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPa
635635
testpaths,
636636
proc_args,
637637
environment,
638-
&config.run_lib_path,
638+
config.run_lib_path.to_str().unwrap(),
639639
None,
640640
None);
641641
}
@@ -1292,7 +1292,7 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
12921292
testpaths,
12931293
make_run_args(config, props, testpaths),
12941294
env,
1295-
&config.run_lib_path,
1295+
config.run_lib_path.to_str().unwrap(),
12961296
Some(aux_dir.to_str().unwrap()),
12971297
None)
12981298
}
@@ -1364,7 +1364,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
13641364
&aux_testpaths,
13651365
aux_args,
13661366
Vec::new(),
1367-
&config.compile_lib_path,
1367+
config.compile_lib_path.to_str().unwrap(),
13681368
Some(aux_dir.to_str().unwrap()),
13691369
None);
13701370
if !auxres.status.success() {
@@ -1387,7 +1387,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
13871387
testpaths,
13881388
args,
13891389
Vec::new(),
1390-
&config.compile_lib_path,
1390+
config.compile_lib_path.to_str().unwrap(),
13911391
Some(aux_dir.to_str().unwrap()),
13921392
input)
13931393
}

src/librbml/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,15 @@ impl<'doc> Doc<'doc> {
165165
}
166166
}
167167

168-
pub fn get<'a>(&'a self, tag: usize) -> Doc<'a> {
168+
pub fn get(&self, tag: usize) -> Doc<'doc> {
169169
reader::get_doc(*self, tag)
170170
}
171171

172172
pub fn is_empty(&self) -> bool {
173173
self.start == self.end
174174
}
175175

176-
pub fn as_str_slice<'a>(&'a self) -> &'a str {
176+
pub fn as_str_slice(&self) -> &'doc str {
177177
str::from_utf8(&self.data[self.start..self.end]).unwrap()
178178
}
179179

src/librustc/middle/cstore.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use syntax::ast_util::{IdVisitingOperation};
4242
use syntax::attr;
4343
use syntax::codemap::Span;
4444
use syntax::ptr::P;
45+
use syntax::parse::token::InternedString;
4546
use rustc_back::target::Target;
4647
use rustc_front::hir;
4748
use rustc_front::intravisit::Visitor;
@@ -203,8 +204,13 @@ pub trait CrateStore<'tcx> : Any {
203204
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
204205
fn is_allocator(&self, cnum: ast::CrateNum) -> bool;
205206
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
206-
fn crate_name(&self, cnum: ast::CrateNum) -> String;
207+
/// The name of the crate as it is referred to in source code of the current
208+
/// crate.
209+
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString;
210+
/// The name of the crate as it is stored in the crate's metadata.
211+
fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString;
207212
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh;
213+
fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString;
208214
fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
209215
-> FnvHashMap<DefId, Vec<ast::Attribute>>;
210216
fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option<DefId>;
@@ -236,7 +242,11 @@ pub trait CrateStore<'tcx> : Any {
236242
// utility functions
237243
fn metadata_filename(&self) -> &str;
238244
fn metadata_section_name(&self, target: &Target) -> &str;
239-
fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<u8>;
245+
fn encode_type(&self,
246+
tcx: &TyCtxt<'tcx>,
247+
ty: Ty<'tcx>,
248+
def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String)
249+
-> Vec<u8>;
240250
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>;
241251
fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource;
242252
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum>;
@@ -378,8 +388,12 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
378388
fn is_allocator(&self, cnum: ast::CrateNum) -> bool { unimplemented!() }
379389
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
380390
{ unimplemented!() }
381-
fn crate_name(&self, cnum: ast::CrateNum) -> String { unimplemented!() }
391+
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
392+
fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString {
393+
unimplemented!()
394+
}
382395
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { unimplemented!() }
396+
fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
383397
fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
384398
-> FnvHashMap<DefId, Vec<ast::Attribute>>
385399
{ unimplemented!() }
@@ -419,8 +433,13 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
419433
// utility functions
420434
fn metadata_filename(&self) -> &str { unimplemented!() }
421435
fn metadata_section_name(&self, target: &Target) -> &str { unimplemented!() }
422-
fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<u8>
423-
{ unimplemented!() }
436+
fn encode_type(&self,
437+
tcx: &TyCtxt<'tcx>,
438+
ty: Ty<'tcx>,
439+
def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String)
440+
-> Vec<u8> {
441+
unimplemented!()
442+
}
424443
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>
425444
{ vec![] }
426445
fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource { unimplemented!() }

src/librustc/middle/ty/context.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use std::hash::{Hash, Hasher};
4343
use std::rc::Rc;
4444
use syntax::ast::{self, Name, NodeId};
4545
use syntax::attr;
46-
use syntax::parse::token::special_idents;
46+
use syntax::parse::token::{self, special_idents};
4747

4848
use rustc_front::hir;
4949

@@ -415,6 +415,10 @@ pub struct TyCtxt<'tcx> {
415415
/// fragmented data to the set of unfragmented pieces that
416416
/// constitute it.
417417
pub fragment_infos: RefCell<DefIdMap<Vec<ty::FragmentInfo>>>,
418+
419+
/// The definite name of the current crate after taking into account
420+
/// attributes, commandline parameters, etc.
421+
pub crate_name: token::InternedString,
418422
}
419423

420424
impl<'tcx> TyCtxt<'tcx> {
@@ -511,6 +515,7 @@ impl<'tcx> TyCtxt<'tcx> {
511515
region_maps: RegionMaps,
512516
lang_items: middle::lang_items::LanguageItems,
513517
stability: stability::Index<'tcx>,
518+
crate_name: &str,
514519
f: F) -> R
515520
where F: FnOnce(&TyCtxt<'tcx>) -> R
516521
{
@@ -570,7 +575,8 @@ impl<'tcx> TyCtxt<'tcx> {
570575
const_qualif_map: RefCell::new(NodeMap()),
571576
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
572577
cast_kinds: RefCell::new(NodeMap()),
573-
fragment_infos: RefCell::new(DefIdMap())
578+
fragment_infos: RefCell::new(DefIdMap()),
579+
crate_name: token::intern_and_get_ident(crate_name),
574580
}, f)
575581
}
576582
}

src/librustc/session/mod.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,12 @@ pub struct Session {
6464
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
6565
pub crate_types: RefCell<Vec<config::CrateType>>,
6666
pub dependency_formats: RefCell<dependency_format::Dependencies>,
67-
pub crate_metadata: RefCell<Vec<String>>,
67+
// The crate_disambiguator is constructed out of all the `-C metadata`
68+
// arguments passed to the compiler. Its value together with the crate-name
69+
// forms a unique global identifier for the crate. It is used to allow
70+
// multiple crates with the same name to coexist. See the
71+
// trans::back::symbol_names module for more information.
72+
pub crate_disambiguator: RefCell<String>,
6873
pub features: RefCell<feature_gate::Features>,
6974

7075
/// The maximum recursion limit for potentially infinitely recursive
@@ -481,7 +486,7 @@ pub fn build_session_(sopts: config::Options,
481486
plugin_attributes: RefCell::new(Vec::new()),
482487
crate_types: RefCell::new(Vec::new()),
483488
dependency_formats: RefCell::new(FnvHashMap()),
484-
crate_metadata: RefCell::new(Vec::new()),
489+
crate_disambiguator: RefCell::new(String::new()),
485490
features: RefCell::new(feature_gate::Features::new()),
486491
recursion_limit: Cell::new(64),
487492
next_node_id: Cell::new(1),

src/librustc_back/svh.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl Svh {
6666
&self.hash
6767
}
6868

69-
pub fn calculate(metadata: &Vec<String>, krate: &hir::Crate) -> Svh {
69+
pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh {
7070
// FIXME (#14132): This is better than it used to be, but it still not
7171
// ideal. We now attempt to hash only the relevant portions of the
7272
// Crate AST as well as the top-level crate attributes. (However,
@@ -78,9 +78,9 @@ impl Svh {
7878
// avoid collisions.
7979
let mut state = SipHasher::new();
8080

81-
for data in metadata {
82-
data.hash(&mut state);
83-
}
81+
"crate_disambiguator".hash(&mut state);
82+
crate_disambiguator.len().hash(&mut state);
83+
crate_disambiguator.hash(&mut state);
8484

8585
{
8686
let mut visit = svh_visitor::make(&mut state, krate);

src/librustc_driver/driver.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc::middle::privacy::AccessLevels;
2222
use rustc::middle::ty::TyCtxt;
2323
use rustc::util::common::time;
2424
use rustc::util::nodemap::NodeSet;
25+
use rustc_back::sha2::{Sha256, Digest};
2526
use rustc_borrowck as borrowck;
2627
use rustc_resolve as resolve;
2728
use rustc_metadata::macro_import;
@@ -500,7 +501,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
500501
}));
501502

502503
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
503-
*sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs);
504+
*sess.crate_disambiguator.borrow_mut() = compute_crate_disambiguator(sess);
504505

505506
time(time_passes, "recursion limit", || {
506507
middle::recursion_limit::update_recursion_limit(sess, &krate);
@@ -525,11 +526,15 @@ pub fn phase_2_configure_and_expand(sess: &Session,
525526

526527
let macros = time(time_passes,
527528
"macro loading",
528-
|| macro_import::read_macro_defs(sess, &cstore, &krate));
529+
|| macro_import::read_macro_defs(sess, &cstore, &krate, crate_name));
529530

530531
let mut addl_plugins = Some(addl_plugins);
531532
let registrars = time(time_passes, "plugin loading", || {
532-
plugin::load::load_plugins(sess, &cstore, &krate, addl_plugins.take().unwrap())
533+
plugin::load::load_plugins(sess,
534+
&cstore,
535+
&krate,
536+
crate_name,
537+
addl_plugins.take().unwrap())
533538
});
534539

535540
let mut registry = Registry::new(sess, &krate);
@@ -754,7 +759,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
754759

755760
time(time_passes,
756761
"external crate/lib resolution",
757-
|| LocalCrateReader::new(sess, cstore, &hir_map).read_crates());
762+
|| LocalCrateReader::new(sess, cstore, &hir_map, name).read_crates());
758763

759764
let lang_items = try!(time(time_passes, "language item collection", || {
760765
sess.track_errors(|| {
@@ -817,6 +822,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
817822
region_map,
818823
lang_items,
819824
index,
825+
name,
820826
|tcx| {
821827
// passes are timed inside typeck
822828
try_with_f!(typeck::check_crate(tcx, trait_map), (tcx, None, analysis));
@@ -1121,8 +1127,34 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
11211127
.collect()
11221128
}
11231129

1124-
pub fn collect_crate_metadata(session: &Session, _attrs: &[ast::Attribute]) -> Vec<String> {
1125-
session.opts.cg.metadata.clone()
1130+
pub fn compute_crate_disambiguator(session: &Session) -> String {
1131+
let mut hasher = Sha256::new();
1132+
1133+
let mut metadata = session.opts.cg.metadata.clone();
1134+
// We don't want the crate_disambiguator to dependent on the order
1135+
// -C metadata arguments, so sort them:
1136+
metadata.sort();
1137+
// Every distinct -C metadata value is only incorporated once:
1138+
metadata.dedup();
1139+
1140+
hasher.input_str("metadata");
1141+
for s in &metadata {
1142+
// Also incorporate the length of a metadata string, so that we generate
1143+
// different values for `-Cmetadata=ab -Cmetadata=c` and
1144+
// `-Cmetadata=a -Cmetadata=bc`
1145+
hasher.input_str(&format!("{}", s.len())[..]);
1146+
hasher.input_str(&s[..]);
1147+
}
1148+
1149+
let mut hash = hasher.result_str();
1150+
1151+
// If this is an executable, add a special suffix, so that we don't get
1152+
// symbol conflicts when linking against a library of the same name.
1153+
if session.crate_types.borrow().contains(&config::CrateTypeExecutable) {
1154+
hash.push_str("-exe");
1155+
}
1156+
1157+
hash
11261158
}
11271159

11281160
pub fn build_output_filenames(input: &Input,

src/librustc_driver/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -567,8 +567,6 @@ impl RustcDefaultCalls {
567567
continue;
568568
}
569569
let crate_types = driver::collect_crate_types(sess, attrs);
570-
let metadata = driver::collect_crate_metadata(sess, attrs);
571-
*sess.crate_metadata.borrow_mut() = metadata;
572570
for &style in &crate_types {
573571
let fname = link::filename_for_input(sess, style, &id, &t_outputs);
574572
println!("{}",

src/librustc_driver/test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ fn test_env<F>(source_string: &str,
146146
region_map,
147147
lang_items,
148148
index,
149+
"test_crate",
149150
|tcx| {
150151
let infcx = infer::new_infer_ctxt(tcx,
151152
&tcx.tables,

src/librustc_metadata/common.rs

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub const tag_crate_dep: usize = 0x35;
7373

7474
pub const tag_crate_hash: usize = 0x103; // top-level only
7575
pub const tag_crate_crate_name: usize = 0x104; // top-level only
76+
pub const tag_crate_disambiguator: usize = 0x113; // top-level only
7677

7778
pub const tag_crate_dep_crate_name: usize = 0x36;
7879
pub const tag_crate_dep_hash: usize = 0x37;

0 commit comments

Comments
 (0)