about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-06-28 12:53:59 -0700
committerBrian Anderson <banderson@mozilla.com>2011-06-28 15:25:47 -0700
commita83b64d15dd8e4ad175fec976772a624437eb9b1 (patch)
tree9ebccccddbfa0443c7032966d07d2c518c09acae /src/comp
parent0608e277b62bb96de225bfae404b3fcfef6253c4 (diff)
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
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/back/link.rs108
-rw-r--r--src/comp/metadata/creader.rs49
-rw-r--r--src/comp/metadata/decoder.rs23
-rw-r--r--src/comp/metadata/encoder.rs14
-rw-r--r--src/comp/middle/attr.rs40
5 files changed, 109 insertions, 125 deletions
diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs
index 25c8b8b17d8..1c1bdee8747 100644
--- a/src/comp/back/link.rs
+++ b/src/comp/back/link.rs
@@ -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 @@ mod write {
  *    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;
-    }
-}
-
-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]; }
+type link_metas = rec(option::t[str] name,
+                      option::t[str] vers,
+                      vec[@ast::meta_item] cmh_items);
+
+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 crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
         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 crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
             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 {
diff --git a/src/comp/metadata/creader.rs b/src/comp/metadata/creader.rs
index c2899e17953..6c23a7d0568 100644
--- a/src/comp/metadata/creader.rs
+++ b/src/comp/metadata/creader.rs
@@ -6,6 +6,7 @@ import lib::llvm::False;
 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;
 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;
                     }
diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs
index b7751fc2303..9d0efd21337 100644
--- a/src/comp/metadata/decoder.rs
+++ b/src/comp/metadata/decoder.rs
@@ -20,6 +20,7 @@ export get_tag_variants;
 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;
diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs
index 27a36e82675..63d56a04a72 100644
--- a/src/comp/metadata/encoder.rs
+++ b/src/comp/metadata/encoder.rs
@@ -13,8 +13,6 @@ import tags::*;
 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);
 }
 
diff --git a/src/comp/middle/attr.rs b/src/comp/middle/attr.rs
index 45b0ccb7026..d255291c1d4 100644
--- a/src/comp/middle/attr.rs
+++ b/src/comp/middle/attr.rs
@@ -2,8 +2,10 @@ import std::vec;
 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