Skip to content

Commit a83b64d

Browse files
committed
Rework how linkage attributes are determined
The meta items within a crate's link attribute are used in linkage: #[link(name = "std", vers = "1.0", custom = "whatever")]; Name and vers are treated specially, and everything else is hashed together into the crate meta hash. Issue #487
1 parent 0608e27 commit a83b64d

File tree

7 files changed

+322
-129
lines changed

7 files changed

+322
-129
lines changed

src/comp/back/link.rs

Lines changed: 45 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
import driver::session;
33
import lib::llvm::llvm;
4+
import middle::attr;
45
import middle::trans;
56
import middle::ty;
67
import std::str;
@@ -274,57 +275,38 @@ mod write {
274275
* system linkers understand.
275276
*
276277
*/
277-
iter crate_export_metas(&ast::crate c) -> @ast::meta_item {
278-
// FIXME: Need to identify exported attributes as described above,
279-
// reevaluate how the above strategy fits in with attributes
280-
for (ast::attribute attr in c.node.attrs) {
281-
put @attr.node.value;
282-
}
283-
}
284-
285-
iter crate_local_metas(&ast::crate c) -> @ast::meta_item {
286-
// FIXME: As above
287-
}
288-
289-
fn get_crate_meta_export(&session::session sess, &ast::crate c, str k,
290-
str default, bool warn_default) -> str {
291-
let vec[@ast::meta_item] v = [];
292-
for each (@ast::meta_item mi in crate_export_metas(c)) {
293-
// FIXME (#487): Support all variants of meta_item
294-
alt (mi.node) {
295-
case (ast::meta_name_value(?name, ?value)) {
296-
if (name == k) { v += [mi]; }
278+
type link_metas = rec(option::t[str] name,
279+
option::t[str] vers,
280+
vec[@ast::meta_item] cmh_items);
281+
282+
fn crate_link_metas(&ast::crate c) -> link_metas {
283+
let option::t[str] name = none;
284+
let option::t[str] vers = none;
285+
let vec[@ast::meta_item] cmh_items = [];
286+
for (@ast::meta_item meta in
287+
attr::find_linkage_metas(c.node.attrs)) {
288+
alt (meta.node) {
289+
case (ast::meta_name_value("name", ?v)) {
290+
// FIXME: Should probably warn about duplicate name items
291+
name = some(v);
297292
}
298-
case (_) {}
299-
}
300-
}
301-
alt (vec::len(v)) {
302-
case (0u) {
303-
if (warn_default) {
304-
sess.warn(#fmt("missing meta '%s', using '%s' as default", k,
305-
default));
293+
case (ast::meta_name_value("value", ?v)) {
294+
// FIXME: Should probably warn about duplicate value items
295+
vers = some(v);
306296
}
307-
ret default;
308-
}
309-
case (1u) {
310-
alt (v.(0).node) {
311-
case (ast::meta_name_value(_, ?value)) {
312-
ret value;
313-
}
314-
case (_) {
315-
ret default;
316-
}
297+
case (_) {
298+
cmh_items += [meta];
317299
}
318300
}
319-
case (_) {
320-
sess.span_fatal(v.(1).span, #fmt("duplicate meta '%s'", k));
321-
}
322301
}
302+
ret rec(name = name,
303+
vers = vers,
304+
cmh_items = cmh_items);
323305
}
324306

325-
326307
// This calculates CMH as defined above
327308
fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
309+
// FIXME (#487) Move this sorting stuff into middle::attr
328310
fn lteq(&@ast::meta_item ma, &@ast::meta_item mb) -> bool {
329311
fn key(&@ast::meta_item m) -> ast::ident {
330312
alt (m.node) {
@@ -342,18 +324,10 @@ fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
342324
ret key(ma) <= key(mb);
343325
}
344326
fn len_and_str(&str s) -> str { ret #fmt("%u_%s", str::byte_len(s), s); }
327+
345328
let vec[mutable @ast::meta_item] v = [mutable ];
346-
for each (@ast::meta_item mi in crate_export_metas(crate)) {
347-
alt (mi.node) {
348-
case (ast::meta_name_value(?name, _)) {
349-
if (name != "name" && name != "vers") {
350-
v += [mutable mi];
351-
}
352-
}
353-
case (_) {
354-
v += [mutable mi];
355-
}
356-
}
329+
for (@ast::meta_item mi in crate_link_metas(crate).cmh_items) {
330+
v += [mutable mi];
357331
}
358332
sort::quick_sort(lteq, v);
359333
sha.reset();
@@ -367,24 +341,32 @@ fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
367341
case (ast::meta_word(?name)) {
368342
sha.input_str(len_and_str(name));
369343
}
370-
case (_) {}
344+
case (ast::meta_list(_, _)) {
345+
fail "unimplemented meta_item variant";
346+
}
371347
}
372348
}
373349
ret truncated_sha1_result(sha);
374350
}
375351

376-
fn crate_meta_name(&session::session sess, &ast::crate crate, &str output) ->
377-
str {
378-
auto os = str::split(fs::basename(output), '.' as u8);
379-
assert (vec::len(os) >= 2u);
380-
vec::pop(os);
381-
ret get_crate_meta_export(sess, crate, "name", str::connect(os, "."),
382-
sess.get_opts().shared);
352+
fn crate_meta_name(&session::session sess, &ast::crate crate,
353+
&str output) -> str {
354+
ret alt (crate_link_metas(crate).name) {
355+
case (some(?v)) { v }
356+
case (none) {
357+
auto os = str::split(fs::basename(output), '.' as u8);
358+
assert (vec::len(os) >= 2u);
359+
vec::pop(os);
360+
str::connect(os, ".")
361+
}
362+
};
383363
}
384364

385365
fn crate_meta_vers(&session::session sess, &ast::crate crate) -> str {
386-
ret get_crate_meta_export(sess, crate, "vers", "0.0",
387-
sess.get_opts().shared);
366+
ret alt (crate_link_metas(crate).vers) {
367+
case (some(?v)) { v }
368+
case (none) { "0.0" }
369+
};
388370
}
389371

390372
fn truncated_sha1_result(sha1 sha) -> str {

src/comp/metadata/creader.rs

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import lib::llvm::False;
66
import lib::llvm::llvm;
77
import lib::llvm::mk_object_file;
88
import lib::llvm::mk_section_iter;
9+
import middle::attr;
910
import middle::resolve;
1011
import middle::walk;
1112
import back::x86;
@@ -19,42 +20,24 @@ import std::option;
1920
import std::option::none;
2021
import std::option::some;
2122
import std::map::hashmap;
23+
import pretty::pprust;
2224
import tags::*;
2325

2426
export read_crates;
2527
export list_file_metadata;
2628

27-
fn metadata_matches(hashmap[str, str] mm, &vec[@ast::meta_item] metas) ->
28-
bool {
29-
log #fmt("matching %u metadata requirements against %u metadata items",
30-
vec::len(metas), mm.size());
31-
for (@ast::meta_item mi in metas) {
32-
alt (mi.node) {
33-
case (ast::meta_name_value(?name, ?value)) {
34-
alt (mm.find(name)) {
35-
case (some(?v)) {
36-
if (v == value) {
37-
log #fmt("matched '%s': '%s'", name,
38-
value);
39-
} else {
40-
log #fmt("missing '%s': '%s' (got '%s')",
41-
name,
42-
value, v);
43-
ret false;
44-
}
45-
}
46-
case (none) {
47-
log #fmt("missing '%s': '%s'",
48-
name, value);
49-
ret false;
50-
}
51-
}
52-
}
53-
case (_) {
54-
// FIXME (#487): Support all forms of meta_item
55-
log_err "unimplemented meta_item variant in metadata_matches";
56-
ret false;
57-
}
29+
fn metadata_matches(&vec[u8] crate_data,
30+
&vec[@ast::meta_item] metas) -> bool {
31+
auto attrs = decoder::get_crate_attributes(crate_data);
32+
auto linkage_metas = attr::find_linkage_metas(attrs);
33+
34+
log #fmt("matching %u metadata requirements against %u items",
35+
vec::len(metas), vec::len(linkage_metas));
36+
37+
for (@ast::meta_item needed in metas) {
38+
if (!attr::contains(linkage_metas, needed)) {
39+
log #fmt("missing %s", pprust::meta_item_to_str(*needed));
40+
ret false;
5841
}
5942
}
6043
ret true;
@@ -106,9 +89,7 @@ fn find_library_crate(&session::session sess, &ast::ident ident,
10689
}
10790
alt (get_metadata_section(path)) {
10891
case (option::some(?cvec)) {
109-
auto mm = decoder::get_exported_metadata(sess,
110-
path, cvec);
111-
if (!metadata_matches(mm, metas)) {
92+
if (!metadata_matches(cvec, metas)) {
11293
log #fmt("skipping %s, metadata doesn't match", path);
11394
cont;
11495
}

src/comp/metadata/decoder.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export get_tag_variants;
2020
export get_type;
2121
export lookup_defs;
2222
export get_type;
23+
export get_crate_attributes;
2324
export list_crate_metadata;
2425
export get_exported_metadata;
2526

@@ -294,7 +295,6 @@ fn get_attributes(&ebml::doc md) -> vec[ast::attribute] {
294295
auto meta_items = get_meta_items(attr_doc);
295296
// Currently it's only possible to have a single meta item on
296297
// an attribute
297-
log_err vec::len(meta_items);
298298
assert (vec::len(meta_items) == 1u);
299299
auto meta_item = meta_items.(0);
300300
attrs += [rec(node=rec(style=ast::attr_outer,
@@ -316,7 +316,7 @@ fn list_meta_items(&ebml::doc meta_items, io::writer out) {
316316
fn list_crate_attributes(&ebml::doc md, io::writer out) {
317317
out.write_str("=Crate=");
318318

319-
// FIXME: This is transitional until attributes are snapshotted
319+
// FIXME (#487): This is transitional until attributes are snapshotted
320320
out.write_str("old-style:\n");
321321
auto meta_items = ebml::get_doc(md, tag_meta_export);
322322
list_meta_items(meta_items, out);
@@ -359,25 +359,6 @@ fn list_crate_metadata(vec[u8] bytes, io::writer out) {
359359
list_crate_items(bytes, md, out);
360360
}
361361

362-
fn get_exported_metadata(&session::session sess, &str path, &vec[u8] data) ->
363-
hashmap[str, str] {
364-
auto meta_items =
365-
ebml::get_doc(ebml::new_doc(data), tag_meta_export);
366-
auto mm = common::new_str_hash[str]();
367-
for each (ebml::doc m in
368-
ebml::tagged_docs(meta_items, tag_meta_item_name_value)) {
369-
auto nd = ebml::get_doc(m, tag_meta_item_name);
370-
auto vd = ebml::get_doc(m, tag_meta_item_value);
371-
auto n = str::unsafe_from_bytes(ebml::doc_data(nd));
372-
auto v = str::unsafe_from_bytes(ebml::doc_data(vd));
373-
log #fmt("metadata in %s: %s = %s", path, n, v);
374-
if (!mm.insert(n, v)) {
375-
sess.warn(#fmt("Duplicate metadata item in %s: %s", path, n));
376-
}
377-
}
378-
ret mm;
379-
}
380-
381362
// Local Variables:
382363
// mode: rust
383364
// fill-column: 78;

src/comp/metadata/encoder.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import tags::*;
1313
import middle::trans::crate_ctxt;
1414
import middle::trans::node_id_type;
1515
import middle::ty;
16-
import back::link::crate_export_metas;
17-
import back::link::crate_local_metas;
1816

1917
export def_to_str;
2018
export hash_path;
@@ -459,16 +457,20 @@ fn encode_attributes(&ebml::writer ebml_w, &vec[attribute] attrs) {
459457
ebml::end_tag(ebml_w);
460458
}
461459

460+
// FIXME (#487): Transitional
462461
fn encode_meta_items(&ebml::writer ebml_w, &crate crate) {
462+
auto name = middle::attr::find_attrs_by_name(crate.node.attrs,
463+
"name");
464+
auto value = middle::attr::find_attrs_by_name(crate.node.attrs,
465+
"value");
466+
auto name_and_val = middle::attr::attr_metas(name + value);
467+
463468
ebml::start_tag(ebml_w, tag_meta_export);
464-
for each (@meta_item mi in crate_export_metas(crate)) {
469+
for (@meta_item mi in name_and_val) {
465470
encode_meta_item(ebml_w, *mi);
466471
}
467472
ebml::end_tag(ebml_w);
468473
ebml::start_tag(ebml_w, tag_meta_local);
469-
for each (@meta_item mi in crate_local_metas(crate)) {
470-
encode_meta_item(ebml_w, *mi);
471-
}
472474
ebml::end_tag(ebml_w);
473475
}
474476

src/comp/middle/attr.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import std::vec;
22
import std::option;
33
import front::ast;
44

5-
export get_linkage_metas;
5+
export attr_metas;
6+
export find_linkage_metas;
67
export find_attrs_by_name;
8+
export contains;
79

810
// From a list of crate attributes get only the meta_items that impact crate
911
// linkage
@@ -62,6 +64,42 @@ fn get_meta_item_name(&@ast::meta_item meta) -> ast::ident {
6264
}
6365
}
6466

67+
fn attr_meta(&ast::attribute attr) -> @ast::meta_item { @attr.node.value }
68+
69+
fn attr_metas(&vec[ast::attribute] attrs) -> vec[@ast::meta_item] {
70+
ret vec::map(attr_meta, attrs);
71+
}
72+
73+
fn eq(@ast::meta_item a, @ast::meta_item b) -> bool {
74+
ret alt (a.node) {
75+
case (ast::meta_word(?na)) {
76+
alt (b.node) {
77+
case(ast::meta_word(?nb)) { na == nb }
78+
case(_) { false }
79+
}
80+
}
81+
case (ast::meta_name_value(?na, ?va)) {
82+
alt (b.node) {
83+
case (ast::meta_name_value(?nb, ?vb)) { na == nb && va == vb }
84+
case (_) { false }
85+
}
86+
}
87+
case (ast::meta_list(?na, ?la)) {
88+
// FIXME (#487): This involves probably sorting the list by name
89+
fail "unimplemented meta_item variant"
90+
}
91+
}
92+
}
93+
94+
fn contains(&vec[@ast::meta_item] haystack, @ast::meta_item needle) -> bool {
95+
for (@ast::meta_item item in haystack) {
96+
if (eq(item, needle)) {
97+
ret true;
98+
}
99+
}
100+
ret false;
101+
}
102+
65103
//
66104
// Local Variables:
67105
// mode: rust

src/lib/std.rc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
#[name = "std"];
2-
#[vers = "0.1"];
3-
#[uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297"];
4-
#[url = "http://rust-lang.org/src/std"];
1+
2+
#[link(name = "std",
3+
vers = "0.1",
4+
uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",
5+
url = "http://rust-lang.org/src/std")];
6+
57
#[comment = "Rust standard library"];
68
#[license = "BSD"];
79

0 commit comments

Comments
 (0)