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
This commit is contained in:
parent
0608e277b6
commit
a83b64d15d
@ -1,6 +1,7 @@
|
||||
|
||||
import driver::session;
|
||||
import lib::llvm::llvm;
|
||||
import middle::attr;
|
||||
import middle::trans;
|
||||
import middle::ty;
|
||||
import std::str;
|
||||
@ -274,57 +275,38 @@ fn run_passes(session::session sess, ModuleRef llmod, str output) {
|
||||
* system linkers understand.
|
||||
*
|
||||
*/
|
||||
iter crate_export_metas(&ast::crate c) -> @ast::meta_item {
|
||||
// FIXME: Need to identify exported attributes as described above,
|
||||
// reevaluate how the above strategy fits in with attributes
|
||||
for (ast::attribute attr in c.node.attrs) {
|
||||
put @attr.node.value;
|
||||
}
|
||||
}
|
||||
type link_metas = rec(option::t[str] name,
|
||||
option::t[str] vers,
|
||||
vec[@ast::meta_item] cmh_items);
|
||||
|
||||
iter crate_local_metas(&ast::crate c) -> @ast::meta_item {
|
||||
// FIXME: As above
|
||||
}
|
||||
|
||||
fn get_crate_meta_export(&session::session sess, &ast::crate c, str k,
|
||||
str default, bool warn_default) -> str {
|
||||
let vec[@ast::meta_item] v = [];
|
||||
for each (@ast::meta_item mi in crate_export_metas(c)) {
|
||||
// FIXME (#487): Support all variants of meta_item
|
||||
alt (mi.node) {
|
||||
case (ast::meta_name_value(?name, ?value)) {
|
||||
if (name == k) { v += [mi]; }
|
||||
fn crate_link_metas(&ast::crate c) -> link_metas {
|
||||
let option::t[str] name = none;
|
||||
let option::t[str] vers = none;
|
||||
let vec[@ast::meta_item] cmh_items = [];
|
||||
for (@ast::meta_item meta in
|
||||
attr::find_linkage_metas(c.node.attrs)) {
|
||||
alt (meta.node) {
|
||||
case (ast::meta_name_value("name", ?v)) {
|
||||
// FIXME: Should probably warn about duplicate name items
|
||||
name = some(v);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
alt (vec::len(v)) {
|
||||
case (0u) {
|
||||
if (warn_default) {
|
||||
sess.warn(#fmt("missing meta '%s', using '%s' as default", k,
|
||||
default));
|
||||
case (ast::meta_name_value("value", ?v)) {
|
||||
// FIXME: Should probably warn about duplicate value items
|
||||
vers = some(v);
|
||||
}
|
||||
ret default;
|
||||
}
|
||||
case (1u) {
|
||||
alt (v.(0).node) {
|
||||
case (ast::meta_name_value(_, ?value)) {
|
||||
ret value;
|
||||
}
|
||||
case (_) {
|
||||
ret default;
|
||||
}
|
||||
case (_) {
|
||||
cmh_items += [meta];
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
sess.span_fatal(v.(1).span, #fmt("duplicate meta '%s'", k));
|
||||
}
|
||||
}
|
||||
ret rec(name = name,
|
||||
vers = vers,
|
||||
cmh_items = cmh_items);
|
||||
}
|
||||
|
||||
|
||||
// This calculates CMH as defined above
|
||||
fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
|
||||
// FIXME (#487) Move this sorting stuff into middle::attr
|
||||
fn lteq(&@ast::meta_item ma, &@ast::meta_item mb) -> bool {
|
||||
fn key(&@ast::meta_item m) -> ast::ident {
|
||||
alt (m.node) {
|
||||
@ -342,18 +324,10 @@ fn key(&@ast::meta_item m) -> ast::ident {
|
||||
ret key(ma) <= key(mb);
|
||||
}
|
||||
fn len_and_str(&str s) -> str { ret #fmt("%u_%s", str::byte_len(s), s); }
|
||||
|
||||
let vec[mutable @ast::meta_item] v = [mutable ];
|
||||
for each (@ast::meta_item mi in crate_export_metas(crate)) {
|
||||
alt (mi.node) {
|
||||
case (ast::meta_name_value(?name, _)) {
|
||||
if (name != "name" && name != "vers") {
|
||||
v += [mutable mi];
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
v += [mutable mi];
|
||||
}
|
||||
}
|
||||
for (@ast::meta_item mi in crate_link_metas(crate).cmh_items) {
|
||||
v += [mutable mi];
|
||||
}
|
||||
sort::quick_sort(lteq, v);
|
||||
sha.reset();
|
||||
@ -367,24 +341,32 @@ fn key(&@ast::meta_item m) -> ast::ident {
|
||||
case (ast::meta_word(?name)) {
|
||||
sha.input_str(len_and_str(name));
|
||||
}
|
||||
case (_) {}
|
||||
case (ast::meta_list(_, _)) {
|
||||
fail "unimplemented meta_item variant";
|
||||
}
|
||||
}
|
||||
}
|
||||
ret truncated_sha1_result(sha);
|
||||
}
|
||||
|
||||
fn crate_meta_name(&session::session sess, &ast::crate crate, &str output) ->
|
||||
str {
|
||||
auto os = str::split(fs::basename(output), '.' as u8);
|
||||
assert (vec::len(os) >= 2u);
|
||||
vec::pop(os);
|
||||
ret get_crate_meta_export(sess, crate, "name", str::connect(os, "."),
|
||||
sess.get_opts().shared);
|
||||
fn crate_meta_name(&session::session sess, &ast::crate crate,
|
||||
&str output) -> str {
|
||||
ret alt (crate_link_metas(crate).name) {
|
||||
case (some(?v)) { v }
|
||||
case (none) {
|
||||
auto os = str::split(fs::basename(output), '.' as u8);
|
||||
assert (vec::len(os) >= 2u);
|
||||
vec::pop(os);
|
||||
str::connect(os, ".")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn crate_meta_vers(&session::session sess, &ast::crate crate) -> str {
|
||||
ret get_crate_meta_export(sess, crate, "vers", "0.0",
|
||||
sess.get_opts().shared);
|
||||
ret alt (crate_link_metas(crate).vers) {
|
||||
case (some(?v)) { v }
|
||||
case (none) { "0.0" }
|
||||
};
|
||||
}
|
||||
|
||||
fn truncated_sha1_result(sha1 sha) -> str {
|
||||
|
@ -6,6 +6,7 @@
|
||||
import lib::llvm::llvm;
|
||||
import lib::llvm::mk_object_file;
|
||||
import lib::llvm::mk_section_iter;
|
||||
import middle::attr;
|
||||
import middle::resolve;
|
||||
import middle::walk;
|
||||
import back::x86;
|
||||
@ -19,42 +20,24 @@
|
||||
import std::option::none;
|
||||
import std::option::some;
|
||||
import std::map::hashmap;
|
||||
import pretty::pprust;
|
||||
import tags::*;
|
||||
|
||||
export read_crates;
|
||||
export list_file_metadata;
|
||||
|
||||
fn metadata_matches(hashmap[str, str] mm, &vec[@ast::meta_item] metas) ->
|
||||
bool {
|
||||
log #fmt("matching %u metadata requirements against %u metadata items",
|
||||
vec::len(metas), mm.size());
|
||||
for (@ast::meta_item mi in metas) {
|
||||
alt (mi.node) {
|
||||
case (ast::meta_name_value(?name, ?value)) {
|
||||
alt (mm.find(name)) {
|
||||
case (some(?v)) {
|
||||
if (v == value) {
|
||||
log #fmt("matched '%s': '%s'", name,
|
||||
value);
|
||||
} else {
|
||||
log #fmt("missing '%s': '%s' (got '%s')",
|
||||
name,
|
||||
value, v);
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
case (none) {
|
||||
log #fmt("missing '%s': '%s'",
|
||||
name, value);
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
// FIXME (#487): Support all forms of meta_item
|
||||
log_err "unimplemented meta_item variant in metadata_matches";
|
||||
ret false;
|
||||
}
|
||||
fn metadata_matches(&vec[u8] crate_data,
|
||||
&vec[@ast::meta_item] metas) -> bool {
|
||||
auto attrs = decoder::get_crate_attributes(crate_data);
|
||||
auto linkage_metas = attr::find_linkage_metas(attrs);
|
||||
|
||||
log #fmt("matching %u metadata requirements against %u items",
|
||||
vec::len(metas), vec::len(linkage_metas));
|
||||
|
||||
for (@ast::meta_item needed in metas) {
|
||||
if (!attr::contains(linkage_metas, needed)) {
|
||||
log #fmt("missing %s", pprust::meta_item_to_str(*needed));
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
ret true;
|
||||
@ -106,9 +89,7 @@ fn find_library_crate(&session::session sess, &ast::ident ident,
|
||||
}
|
||||
alt (get_metadata_section(path)) {
|
||||
case (option::some(?cvec)) {
|
||||
auto mm = decoder::get_exported_metadata(sess,
|
||||
path, cvec);
|
||||
if (!metadata_matches(mm, metas)) {
|
||||
if (!metadata_matches(cvec, metas)) {
|
||||
log #fmt("skipping %s, metadata doesn't match", path);
|
||||
cont;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
export get_type;
|
||||
export lookup_defs;
|
||||
export get_type;
|
||||
export get_crate_attributes;
|
||||
export list_crate_metadata;
|
||||
export get_exported_metadata;
|
||||
|
||||
@ -294,7 +295,6 @@ fn get_attributes(&ebml::doc md) -> vec[ast::attribute] {
|
||||
auto meta_items = get_meta_items(attr_doc);
|
||||
// Currently it's only possible to have a single meta item on
|
||||
// an attribute
|
||||
log_err vec::len(meta_items);
|
||||
assert (vec::len(meta_items) == 1u);
|
||||
auto meta_item = meta_items.(0);
|
||||
attrs += [rec(node=rec(style=ast::attr_outer,
|
||||
@ -316,7 +316,7 @@ fn list_meta_items(&ebml::doc meta_items, io::writer out) {
|
||||
fn list_crate_attributes(&ebml::doc md, io::writer out) {
|
||||
out.write_str("=Crate=");
|
||||
|
||||
// FIXME: This is transitional until attributes are snapshotted
|
||||
// FIXME (#487): This is transitional until attributes are snapshotted
|
||||
out.write_str("old-style:\n");
|
||||
auto meta_items = ebml::get_doc(md, tag_meta_export);
|
||||
list_meta_items(meta_items, out);
|
||||
@ -359,25 +359,6 @@ fn list_crate_metadata(vec[u8] bytes, io::writer out) {
|
||||
list_crate_items(bytes, md, out);
|
||||
}
|
||||
|
||||
fn get_exported_metadata(&session::session sess, &str path, &vec[u8] data) ->
|
||||
hashmap[str, str] {
|
||||
auto meta_items =
|
||||
ebml::get_doc(ebml::new_doc(data), tag_meta_export);
|
||||
auto mm = common::new_str_hash[str]();
|
||||
for each (ebml::doc m in
|
||||
ebml::tagged_docs(meta_items, tag_meta_item_name_value)) {
|
||||
auto nd = ebml::get_doc(m, tag_meta_item_name);
|
||||
auto vd = ebml::get_doc(m, tag_meta_item_value);
|
||||
auto n = str::unsafe_from_bytes(ebml::doc_data(nd));
|
||||
auto v = str::unsafe_from_bytes(ebml::doc_data(vd));
|
||||
log #fmt("metadata in %s: %s = %s", path, n, v);
|
||||
if (!mm.insert(n, v)) {
|
||||
sess.warn(#fmt("Duplicate metadata item in %s: %s", path, n));
|
||||
}
|
||||
}
|
||||
ret mm;
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
@ -13,8 +13,6 @@
|
||||
import middle::trans::crate_ctxt;
|
||||
import middle::trans::node_id_type;
|
||||
import middle::ty;
|
||||
import back::link::crate_export_metas;
|
||||
import back::link::crate_local_metas;
|
||||
|
||||
export def_to_str;
|
||||
export hash_path;
|
||||
@ -459,16 +457,20 @@ fn encode_attributes(&ebml::writer ebml_w, &vec[attribute] attrs) {
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
// FIXME (#487): Transitional
|
||||
fn encode_meta_items(&ebml::writer ebml_w, &crate crate) {
|
||||
auto name = middle::attr::find_attrs_by_name(crate.node.attrs,
|
||||
"name");
|
||||
auto value = middle::attr::find_attrs_by_name(crate.node.attrs,
|
||||
"value");
|
||||
auto name_and_val = middle::attr::attr_metas(name + value);
|
||||
|
||||
ebml::start_tag(ebml_w, tag_meta_export);
|
||||
for each (@meta_item mi in crate_export_metas(crate)) {
|
||||
for (@meta_item mi in name_and_val) {
|
||||
encode_meta_item(ebml_w, *mi);
|
||||
}
|
||||
ebml::end_tag(ebml_w);
|
||||
ebml::start_tag(ebml_w, tag_meta_local);
|
||||
for each (@meta_item mi in crate_local_metas(crate)) {
|
||||
encode_meta_item(ebml_w, *mi);
|
||||
}
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,10 @@
|
||||
import std::option;
|
||||
import front::ast;
|
||||
|
||||
export get_linkage_metas;
|
||||
export attr_metas;
|
||||
export find_linkage_metas;
|
||||
export find_attrs_by_name;
|
||||
export contains;
|
||||
|
||||
// From a list of crate attributes get only the meta_items that impact crate
|
||||
// linkage
|
||||
@ -62,6 +64,42 @@ fn get_meta_item_name(&@ast::meta_item meta) -> ast::ident {
|
||||
}
|
||||
}
|
||||
|
||||
fn attr_meta(&ast::attribute attr) -> @ast::meta_item { @attr.node.value }
|
||||
|
||||
fn attr_metas(&vec[ast::attribute] attrs) -> vec[@ast::meta_item] {
|
||||
ret vec::map(attr_meta, attrs);
|
||||
}
|
||||
|
||||
fn eq(@ast::meta_item a, @ast::meta_item b) -> bool {
|
||||
ret alt (a.node) {
|
||||
case (ast::meta_word(?na)) {
|
||||
alt (b.node) {
|
||||
case(ast::meta_word(?nb)) { na == nb }
|
||||
case(_) { false }
|
||||
}
|
||||
}
|
||||
case (ast::meta_name_value(?na, ?va)) {
|
||||
alt (b.node) {
|
||||
case (ast::meta_name_value(?nb, ?vb)) { na == nb && va == vb }
|
||||
case (_) { false }
|
||||
}
|
||||
}
|
||||
case (ast::meta_list(?na, ?la)) {
|
||||
// FIXME (#487): This involves probably sorting the list by name
|
||||
fail "unimplemented meta_item variant"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn contains(&vec[@ast::meta_item] haystack, @ast::meta_item needle) -> bool {
|
||||
for (@ast::meta_item item in haystack) {
|
||||
if (eq(item, needle)) {
|
||||
ret true;
|
||||
}
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
@ -1,7 +1,9 @@
|
||||
#[name = "std"];
|
||||
#[vers = "0.1"];
|
||||
#[uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297"];
|
||||
#[url = "http://rust-lang.org/src/std"];
|
||||
|
||||
#[link(name = "std",
|
||||
vers = "0.1",
|
||||
uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",
|
||||
url = "http://rust-lang.org/src/std")];
|
||||
|
||||
#[comment = "Rust standard library"];
|
||||
#[license = "BSD"];
|
||||
|
||||
|
207
src/test/run-pass/item-attributes.rs
Normal file
207
src/test/run-pass/item-attributes.rs
Normal file
@ -0,0 +1,207 @@
|
||||
// xfail-stage0
|
||||
|
||||
// These are attributes of the implicit crate. Really this just needs to parse
|
||||
// for completeness since .rs files linked from .rc files support this
|
||||
// notation to specify their module's attributes
|
||||
#[attr1 = "val"];
|
||||
#[attr2 = "val"];
|
||||
#[attr3];
|
||||
#[attr4(attr5)];
|
||||
|
||||
// Special linkage attributes for the crate
|
||||
#[link(name = "std",
|
||||
vers = "0.1",
|
||||
uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",
|
||||
url = "http://rust-lang.org/src/std")];
|
||||
|
||||
// These are are attributes of the following mod
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
mod test_first_item_in_file_mod {
|
||||
}
|
||||
|
||||
mod test_single_attr_outer {
|
||||
|
||||
#[attr = "val"]
|
||||
const int x = 10;
|
||||
|
||||
#[attr = "val"]
|
||||
fn f() {}
|
||||
|
||||
#[attr = "val"]
|
||||
mod mod1 {
|
||||
}
|
||||
|
||||
#[attr = "val"]
|
||||
native "rust" mod rustrt { }
|
||||
|
||||
#[attr = "val"]
|
||||
type t = obj { };
|
||||
|
||||
|
||||
#[attr = "val"]
|
||||
obj o() { }
|
||||
}
|
||||
|
||||
mod test_multi_attr_outer {
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
const int x = 10;
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
fn f() {}
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
mod mod1 {
|
||||
}
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
native "rust" mod rustrt { }
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
type t = obj { };
|
||||
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
obj o() { }
|
||||
}
|
||||
|
||||
mod test_stmt_single_attr_outer {
|
||||
|
||||
fn f() {
|
||||
|
||||
#[attr = "val"]
|
||||
const int x = 10;
|
||||
|
||||
#[attr = "val"]
|
||||
fn f() {}
|
||||
|
||||
/* FIXME: Issue #493
|
||||
#[attr = "val"]
|
||||
mod mod1 {
|
||||
}
|
||||
|
||||
#[attr = "val"]
|
||||
native "rust" mod rustrt {
|
||||
}
|
||||
*/
|
||||
|
||||
#[attr = "val"]
|
||||
type t = obj { };
|
||||
|
||||
#[attr = "val"]
|
||||
obj o() { }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
mod test_stmt_multi_attr_outer {
|
||||
|
||||
fn f() {
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
const int x = 10;
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
fn f() {}
|
||||
|
||||
/* FIXME: Issue #493
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
mod mod1 {
|
||||
}
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
native "rust" mod rustrt {
|
||||
}
|
||||
*/
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
type t = obj { };
|
||||
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
obj o() { }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
mod test_attr_inner {
|
||||
|
||||
mod m {
|
||||
// This is an attribute of mod m
|
||||
#[attr = "val"];
|
||||
}
|
||||
}
|
||||
|
||||
mod test_attr_inner_then_outer {
|
||||
|
||||
mod m {
|
||||
// This is an attribute of mod m
|
||||
#[attr = "val"];
|
||||
// This is an attribute of fn f
|
||||
#[attr = "val"]
|
||||
fn f() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod test_attr_inner_then_outer_multi {
|
||||
mod m {
|
||||
// This is an attribute of mod m
|
||||
#[attr1 = "val"];
|
||||
#[attr2 = "val"];
|
||||
// This is an attribute of fn f
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
fn f() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod test_distinguish_syntax_ext {
|
||||
|
||||
use std;
|
||||
|
||||
fn f() {
|
||||
#fmt("test%s", "s");
|
||||
#[attr = "val"]
|
||||
fn g() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod test_other_forms {
|
||||
#[attr]
|
||||
#[attr(word)]
|
||||
#[attr(attr(word))]
|
||||
#[attr(key1 = "val",
|
||||
key2 = "val",
|
||||
attr)]
|
||||
fn f() {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
//
|
Loading…
Reference in New Issue
Block a user